home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip532.zip / amiga / filedate.c < prev    next >
C/C++ Source or Header  |  1997-07-26  |  24KB  |  676 lines

  1. /* Low-level Amiga routines shared between Zip and UnZip.
  2.  *
  3.  * Contains:  FileDate()
  4.  *            locale_TZ()
  5.  *            getenv()          [Aztec C only; replaces bad C library versions]
  6.  *            setenv()          [ditto]
  7.  *            tzset()           [ditto]
  8.  *            gmtime()          [ditto]
  9.  *            localtime()       [ditto]
  10.  *            time()            [ditto]
  11.  *            mkgmtime()
  12.  *            sendpkt()
  13.  *            Agetch()
  14.  *
  15.  * The first five are used by all Info-ZIP programs except fUnZip.
  16.  * The last two are used by all except the non-CRYPT version of fUnZip.
  17.  * Probably some of the stuff in here is unused by ZipNote and ZipSplit too...
  18.  * sendpkt() is used by Agetch() and FileDate(), and by windowheight() in
  19.  * amiga/amiga.c (UnZip).  time() is used only by Zip.
  20.  */
  21.  
  22.  
  23. /* HISTORY/CHANGES
  24.  *  2 Sep 92, Greg Roelofs, Original coding.
  25.  *  6 Sep 92, John Bush, Incorporated into UnZip 5.1
  26.  *  6 Sep 92, John Bush, Interlude "FileDate()" defined, which calls or
  27.  *            redefines SetFileDate() depending upon AMIGADOS2 definition.
  28.  * 11 Oct 92, John Bush, Eliminated AMIGADOS2 switch by determining
  29.  *            revision via OpenLibrary() call.  Now only one version of
  30.  *            the program runs on both platforms (1.3.x vs. 2.x)
  31.  * 11 Oct 92, John Bush, Merged with Zip version and changed arg passing
  32.  *            to take time_t input instead of struct DateStamp.
  33.  *            Arg passing made to conform with utime().
  34.  * 22 Nov 92, Paul Kienitz, fixed includes for Aztec and cleaned up some
  35.  *            lint-ish errors; simplified test for AmigaDOS version.
  36.  * 11 Nov 95, Paul Kienitz, added Agetch() for crypt password input and
  37.  *            UnZip's "More" prompt -- simplifies crypt.h and avoids
  38.  *            use of library code redundant with sendpkt().  Made it
  39.  *            available to fUnZip, which does not use FileDate().
  40.  * 22 Nov 95, Paul Kienitz, created a new tzset() that gets the current
  41.  *            timezone from the Locale preferences.  These exist only under
  42.  *            AmigaDOS 2.1 and up, but it is probably correctly set on more
  43.  *            Amigas than the TZ environment variable is.  We check that
  44.  *            only if TZ is not validly set.  We do not parse daylight
  45.  *            savings syntax except to check for presence vs. absence of a
  46.  *            DST part; United States rules are assumed.  This is better
  47.  *            than the tzset()s in the Amiga compilers' libraries do.
  48.  * 15 Jan 96, Chr. Spieler, corrected the logic when to select low level
  49.  *            sendpkt() (when FileDate(), Agetch() or windowheight() is used),
  50.  *            and AMIGA's Agetch() (CRYPT, and UnZip(SFX)'s UzpMorePause()).
  51.  * 10 Feb 96, Paul Kienitz, re-fiddled that selection logic again, moved
  52.  *            stuff around for clarity.
  53.  * 16 Mar 96, Paul Kienitz, created a replacement localtime() to go with the
  54.  *            new tzset(), because Aztec's is hopelessly broken.  Also
  55.  *            gmtime(), which localtime() calls.
  56.  * 12 Apr 96, Paul Kienitz, daylight savings was being handled incorrectly.
  57.  * 21 Apr 96, Paul Kienitz, had to replace time() as well, Aztec's returns
  58.  *            local time instead of GMT.  That's why their localtime() was bad,
  59.  *            because it assumed time_t was already local, and gmtime() was
  60.  *            the one that checked TZ.
  61.  * 23 Apr 96, Chr. Spieler, deactivated time() replacement for UnZip stuff.
  62.  *            Currently, the UnZip sources do not make use of time() (and do
  63.  *            not supply the working mktime() replacement, either!).
  64.  * 29 Apr 96, Paul Kienitz, created a replacement getenv() out of code that
  65.  *            was previously embedded in tzset(), for reliable global test
  66.  *            of whether TZ is set or not.
  67.  * 19 Jun 96, Haidinger Walter, re-adapted for current SAS/C compiler.
  68.  *  7 Jul 96, Paul Kienitz, smoothed together compiler-related changes.
  69.  *  4 Feb 97, Haidinger Walter, added set_TZ() for SAS/C.
  70.  * 23 Apr 97, Paul Kienitz, corrected Unix->Amiga DST error by adding
  71.  *            mkgmtime() so localtime() could be used.
  72.  * 28 Apr 97, Christian Spieler, deactivated mkgmtime() definition for ZIP;
  73.  *            the Zip sources supply this function as part of util.c.
  74.  * 24 May 97, Haidinger Walter, added time_lib support for SAS/C and moved
  75.  *            set_TZ() to time_lib.c
  76.  * 12 Jul 97, Paul Kienitz, adapted time_lib stuff for Aztec.
  77.  * 26 Jul 97, Chr. Spieler, old mkgmtime() fixed (ydays[] def, sign vs unsign).
  78.  */
  79.  
  80. #include <ctype.h>
  81. #include <string.h>
  82. #include <time.h>
  83. #include <errno.h>
  84. #include <stdio.h>
  85.  
  86. #include <exec/types.h>
  87. #include <exec/execbase.h>
  88. #include <exec/memory.h>
  89.  
  90. #ifdef AZTEC_C
  91. #  include <libraries/dos.h>
  92. #  include <libraries/dosextens.h>
  93. #  include <clib/exec_protos.h>
  94. #  include <clib/dos_protos.h>
  95. #  include <clib/locale_protos.h>
  96. #  include <pragmas/exec_lib.h>
  97. #  include <pragmas/dos_lib.h>
  98. #  include <pragmas/locale_lib.h>
  99. #  define ESRCH  ENOENT
  100. #  define EOSERR EIO
  101. #endif
  102.  
  103. #ifdef __SASC
  104. #  include <stdlib.h>
  105. #  if (defined(_M68020) && (!defined(__USE_SYSBASE)))
  106.                             /* on 68020 or higher processors it is faster   */
  107. #    define __USE_SYSBASE   /* to use the pragma libcall instead of syscall */
  108. #  endif                    /* to access functions of the exec.library      */
  109. #  include <proto/exec.h>   /* see SAS/C manual:part 2,chapter 2,pages 6-7  */
  110. #  include <proto/dos.h>
  111. #  include <proto/locale.h>
  112. #  ifdef DEBUG
  113. #     include <sprof.h>
  114. #  endif
  115. #  ifdef MWDEBUG
  116. #    include <stdio.h>      /* include both before memwatch.h again just */
  117. #    include <stdlib.h>     /* to be safe */
  118. #    include "memwatch.h"
  119. #if 0                       /* remember_alloc currently unavailable */
  120. #    ifdef getenv
  121. #      undef getenv         /* remove previously preprocessor symbol */
  122. #    endif
  123. #    define getenv(name)    ((char *)remember_alloc((zvoid *)MWGetEnv(name, __FILE__, __LINE__)))
  124. #endif
  125. #  endif /* MWDEBUG */
  126.    /* define USE_TIME_LIB if replacement functions of time_lib are available */
  127.    /* replaced are: tzset(), time(), localtime() and gmtime()                */
  128. #endif /* __SASC */
  129.  
  130. #ifndef OF
  131. #  define OF(x) x             /* so crypt.h prototypes compile okay */
  132. #endif
  133. #if defined(ZIP) || defined(FUNZIP)
  134.    void zipwarn  OF((char *, char *));   /* add zipwarn prototype from zip.h */
  135. #  define near                /* likewise */
  136.    typedef unsigned long ulg; /* likewise */
  137.    typedef size_t extent;     /* likewise */
  138.    typedef void zvoid;        /* likewise */
  139. #endif
  140. #include "crypt.h"            /* just so we can tell if CRYPT is supported */
  141.  
  142. int zone_is_set = FALSE;      /* set by tzset() */
  143.  
  144.  
  145. #ifndef FUNZIP
  146.  
  147. #  ifndef SUCCESS
  148. #    define SUCCESS (-1L)
  149. #    define FAILURE 0L
  150. #  endif
  151.  
  152. #  define ReqVers 36L  /* required library version for SetFileDate() */
  153. #  define ENVSIZE 100  /* max space allowed for an environment var   */
  154.  
  155. extern struct ExecBase *SysBase;
  156.  
  157. #ifdef AZTEC_C                      /* should be pretty safe for reentrancy */
  158.    long timezone = 0;               /* already declared SAS/C external */
  159.    int daylight = 0;                /* likewise */
  160. #endif
  161.  
  162. /* prototypes */
  163. #ifdef AZTEC_C
  164.   char *getenv(const char *var);
  165.   int setenv(const char *var, const char *value, int overwrite);
  166. #endif
  167. LONG FileDate (char *filename, time_t u[]);
  168. LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
  169. int Agetch(void);
  170.  
  171. #if (!defined(ZIP) || !defined(NO_MKTIME)) && !defined(USE_TIME_LIB)
  172.   time_t mkgmtime(struct tm *tm);          /* use mkgmtime() from here */
  173. #else
  174.   extern time_t mkgmtime(struct tm *tm);   /* from mktime.c or time_lib.c */
  175. #endif
  176.  
  177. /* prototypes for time replacement functions */
  178. #ifndef USE_TIME_LIB
  179.   void tzset(void);
  180.   int locale_TZ(void);
  181.   struct tm *gmtime(const time_t *when);
  182.   struct tm *localtime(const time_t *when);
  183.   extern void set_TZ(long time_zone, int day_light);  /* in time_lib.c */
  184. #  ifdef ZIP
  185.      time_t time(time_t *tp);
  186. #  endif
  187. #endif /* !USE_TIME_LIB */
  188. #if 0    /* not used YET */
  189.   extern zvoid *remember_alloc   OF((zvoid *memptr));
  190. #endif
  191.  
  192. /* =============================================================== */
  193.  
  194. /***********************/
  195. /* Function filedate() */
  196. /***********************/
  197.  
  198. /*  FileDate() (originally utime.c), by Paul Wells.  Modified by John Bush
  199.  *  and others (see also sendpkt() comments, below); NewtWare SetFileDate()
  200.  *  clone cheaply ripped off from utime().
  201.  */
  202.  
  203. /* DESCRIPTION
  204.  * This routine chooses between 2 methods to set the file date on AMIGA.
  205.  * Since AmigaDOS 2.x came out, SetFileDate() was available in ROM (v.36
  206.  * and higher).  Under AmigaDOS 1.3.x (less than v.36 ROM), SetFileDate()
  207.  * must be accomplished by constructing a message packet and sending it
  208.  * to the file system handler of the file to be stamped.
  209.  *
  210.  * The system's ROM version is extracted from the external system Library
  211.  * base.
  212.  *
  213.  * NOTE:  although argument passing conforms with utime(), note the
  214.  *        following differences:
  215.  *          - Return value is boolean success/failure.
  216.  *          - If a structure or array is passed, only the first value
  217.  *            is used, which *may* correspond to date accessed and not
  218.  *            date modified.
  219.  */
  220.  
  221.  
  222. LONG FileDate(filename, u)
  223.     char *filename;
  224.     time_t u[];
  225. {
  226.     LONG SetFileDate(UBYTE *filename, struct DateStamp *pDate);
  227.     LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
  228.     struct MsgPort *taskport;
  229.     BPTR dirlock, lock;
  230.     struct FileInfoBlock *fib;
  231.     LONG pktargs[4];
  232.     UBYTE *ptr;
  233.     long ret;
  234.  
  235.     struct DateStamp pDate;
  236.     time_t mtime;
  237.  
  238.     /* tzset(); */
  239.     /* mtime = u[0] - timezone; */
  240.     mtime = mkgmtime(localtime(&u[0]));
  241.  
  242. /* magic number = 2922 = 8 years + 2 leaps between 1970 - 1978 */
  243.     pDate.ds_Days = (mtime / 86400L) - 2922L;
  244.     mtime = mtime % 86400L;
  245.     pDate.ds_Minute = mtime / 60L;
  246.     mtime = mtime % 60L;
  247.     pDate.ds_Tick = mtime * TICKS_PER_SECOND;
  248.  
  249.     if (SysBase->LibNode.lib_Version >= ReqVers)
  250.     {
  251.         return (SetFileDate(filename,&pDate));  /* native routine at 2.0+ */
  252.     }
  253.     else  /* !(SysBase->lib_Version >=ReqVers) */
  254.     {
  255.         if( !(taskport = (struct MsgPort *)DeviceProc(filename)) )
  256.         {
  257.             errno = ESRCH;          /* no such process */
  258.             return FAILURE;
  259.         }
  260.  
  261.         if( !(lock = Lock(filename,SHARED_LOCK)) )
  262.         {
  263.             errno = ENOENT;         /* no such file */
  264.             return FAILURE;
  265.         }
  266.  
  267.         if( !(fib = (struct FileInfoBlock *)AllocMem(
  268.             (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
  269.         {
  270.             errno = ENOMEM;         /* insufficient memory */
  271.             UnLock(lock);
  272.             return FAILURE;
  273.         }
  274.  
  275.         if( Examine(lock,fib)==FAILURE )
  276.         {
  277.             errno = EOSERR;         /* operating system error */
  278.             UnLock(lock);
  279.             FreeMem(fib,(long)sizeof(*fib));
  280.             return FAILURE;
  281.         }
  282.  
  283.         dirlock = ParentDir(lock);
  284.         ptr = (UBYTE *)AllocMem(64L,MEMF_PUBLIC);
  285.         strcpy((ptr+1),fib->fib_FileName);
  286.         *ptr = strlen(fib->fib_FileName);
  287.         FreeMem(fib,(long)sizeof(*fib));
  288.         UnLock(lock);
  289.  
  290.         /* now fill in argument array */
  291.  
  292.         pktargs[0] = 0;
  293.         pktargs[1] = (LONG)dirlock;
  294.         pktargs[2] = (LONG)&ptr[0] >> 2;
  295.         pktargs[3] = (LONG)&pDate;
  296.  
  297.         errno = ret = sendpkt(taskport,ACTION_SET_DATE,pktargs,4L);
  298.  
  299.         FreeMem(ptr,64L);
  300.         UnLock(dirlock);
  301.  
  302.         return SUCCESS;
  303.     }  /* ?(SysBase->lib_Version >= ReqVers) */
  304. } /* FileDate() */
  305.  
  306.  
  307. #ifdef AZTEC_C    /* SAS/C uses library getenv() & putenv() */
  308. char *getenv(const char *var)         /* not reentrant! */
  309. {
  310.     static char space[ENVSIZE];
  311.     struct Process *me = (void *) FindTask(NULL);
  312.     void *old_window = me->pr_WindowPtr;
  313.     char *ret = NULL;
  314.  
  315.     me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
  316.     if (SysBase->LibNode.lib_Version >= ReqVers) {
  317.         if (GetVar((char *) var, space, ENVSIZE - 1, /* GVF_GLOBAL_ONLY */ 0) > 0)
  318.             ret = space;
  319.     } else {                    /* early AmigaDOS, get env var the crude way */
  320.         BPTR hand, foot, spine;
  321.         int z = 0;
  322.         if (foot = Lock("ENV:", ACCESS_READ)) {
  323.             spine = CurrentDir(foot);
  324.             if (hand = Open((char *) var, MODE_OLDFILE)) {
  325.                 z = Read(hand, space, ENVSIZE - 1);
  326.                 Close(hand);
  327.             }
  328.             UnLock(CurrentDir(spine));
  329.         }
  330.         if (z > 0) {
  331.             space[z] = '\0';
  332.             ret = space;
  333.         }
  334.     }
  335.     me->pr_WindowPtr = old_window;
  336.     return ret;
  337. }
  338.  
  339. int setenv(const char *var, const char *value, int overwrite)
  340. {
  341.     struct Process *me = (void *) FindTask(NULL);
  342.     void *old_window = me->pr_WindowPtr;
  343.     int ret = -1;
  344.  
  345.     me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
  346.     if (SysBase->LibNode.lib_Version >= ReqVers)
  347.         ret = !SetVar((char *) var, (char *) value, -1, GVF_GLOBAL_ONLY | LV_VAR);
  348.     else {
  349.         BPTR hand, foot, spine;
  350.         int len = value ? strlen(value) : 0;
  351.         if (foot = Lock("ENV:", ACCESS_READ)) {
  352.             spine = CurrentDir(foot);
  353.             if (len) {
  354.                 if (hand = Open((char *) var, MODE_NEWFILE)) {
  355.                     ret = Write(hand, (char *) value, len + 1) >= len;
  356.                     Close(hand);
  357.                 }
  358.             } else
  359.                 ret = DeleteFile((char *) var);
  360.             UnLock(CurrentDir(spine));
  361.         }
  362.     }
  363.     me->pr_WindowPtr = old_window;
  364.     return ret;
  365. }
  366. #endif /* AZTEC_C */
  367.  
  368.  
  369. #if (!defined(ZIP) || !defined(NO_MKTIME)) && !defined(USE_TIME_LIB)
  370. /* this mkgmtime() code is a simplified version taken from Zip's mktime.c */
  371.  
  372. /* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
  373.    of the Greenwich Mean time and date in the exploded time structure `tm',
  374.    and set `tm->tm_yday' and `tm->tm_wday', but not `tm->tm_isdst'.
  375.    Return -1 if any of the other fields in `tm' has an invalid value. */
  376.  
  377. /* Nonzero if `y' is a leap year, else zero. */
  378. #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
  379.  
  380. /* Number of leap years from 1970 to `y' (not including `y' itself). */
  381. #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
  382.  
  383. /* Accumulated number of days from 01-Jan up to start of current month. */
  384. #ifdef ZIP
  385. static const unsigned short ydays[] =
  386. {  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
  387. #else
  388. extern const unsigned short ydays[];  /* in unzip's fileio.c */
  389. #endif
  390.  
  391.  
  392. time_t mkgmtime(struct tm *tm)
  393. {
  394.   int years, months, days, hours, minutes, seconds;
  395.  
  396.   years = tm->tm_year + 1900;   /* year - 1900 -> year */
  397.   months = tm->tm_mon;          /* 0..11 */
  398.   days = tm->tm_mday - 1;       /* 1..31 -> 0..30 */
  399.   hours = tm->tm_hour;          /* 0..23 */
  400.   minutes = tm->tm_min;         /* 0..59 */
  401.   seconds = tm->tm_sec;         /* 0..61 in ANSI C. */
  402.  
  403.   if (years < 1970
  404.       || months < 0 || months > 11
  405.       || days < 0
  406.       || days >= (months == 11? 365 : ydays[months + 1]) - ydays[months]
  407.            + (months == 1 && leap(years))
  408.       || hours < 0 || hours > 23
  409.       || minutes < 0 || minutes > 59
  410.       || seconds < 0 || seconds > 61)
  411.   return -1;
  412.  
  413.   /* Set `days' to the number of days into the year. */
  414.   days += ydays[months] + (months > 1 && leap(years));
  415.   tm->tm_yday = days;
  416.  
  417.   /* Now set `days' to the number of days since Jan 1, 1970. */
  418.   days = (unsigned)days + 365 * (unsigned)(years - 1970) +
  419.          (unsigned)(nleap(years));
  420.   tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
  421. /*  tm->tm_isdst = 0; */
  422.  
  423.   return (time_t)(86400L * (unsigned long)(unsigned)days +
  424.                   3600L * (unsigned long)hours +
  425.                   (unsigned long)(60 * minutes + seconds));
  426. }
  427.  
  428. #endif /* (!ZIP || !NO_MKTIME) && !USE_TIME_LIB */
  429.  
  430. #ifndef USE_TIME_LIB
  431.  
  432. /* set timezone and daylight to settings found in locale.library */
  433. int locale_TZ(void)
  434. {
  435.     struct Library *LocaleBase;
  436.     struct Locale *ll;
  437.     struct Process *me = (void *) FindTask(NULL);
  438.     void *old_window = me->pr_WindowPtr;
  439.     BPTR eh;
  440.     int z, valid = FALSE;
  441.     /* read timezone from locale.library if TZ envvar missing */
  442.     me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
  443.     if (LocaleBase = OpenLibrary("locale.library", 0)) {
  444.         if (ll = OpenLocale(NULL)) {
  445.             z = ll->loc_GMTOffset;
  446.             if (z == -300) {
  447.                 if (eh = Lock("ENV:sys/locale.prefs", ACCESS_READ))
  448.                     UnLock(eh);
  449.                 else
  450.                     z = 300; /* bug: locale not initialized, default is bogus! */
  451.             } else
  452.                 zone_is_set = TRUE;
  453.             timezone = z * 60;
  454.             daylight = (z >= 4*60 && z <= 9*60);    /* apply in the Americas */
  455.             valid = TRUE;
  456.             CloseLocale(ll);
  457.         }
  458.         CloseLibrary(LocaleBase);
  459.     }
  460.     me->pr_WindowPtr = old_window;
  461.     return valid;
  462. }
  463.  
  464. void tzset(void) {
  465.     char *p,*TZstring;
  466.     int z,valid = FALSE;
  467.     if (zone_is_set)
  468.         return;
  469.     timezone = 0;       /* default is GMT0 which means no offsets */
  470.     daylight = 0;       /* from local system time                 */
  471.     TZstring = getenv("TZ");              /* read TZ envvar */
  472.     if (TZstring && TZstring[0]) {        /* TZ exists and has contents? */
  473.         z = 3600;
  474.         for (p = TZstring; *p && !isdigit(*p) && *p != '-'; p++) ;
  475.         if (*p == '-')
  476.             z = -3600, p++;
  477.         if (*p) {
  478.             timezone = 0;
  479.             do {
  480.                 while (isdigit(*p))
  481.                     timezone = timezone * 10 + z * (*p++ - '0'), valid = TRUE;
  482.                 if (*p == ':') p++;
  483.             } while (isdigit(*p) && (z /= 60) > 0);
  484.         }
  485.         while (isspace(*p)) p++;                      /* probably not needed */
  486.         if (valid)
  487.             zone_is_set = TRUE, daylight = !!*p;   /* a DST name part exists */
  488.     }
  489.     if (!valid)
  490.         locale_TZ();               /* read locale.library */
  491. #ifdef __SASC
  492.     /* Some SAS/C library functions, e.g. stat(), call library  */
  493.     /* __tzset() themselves. So envvar TZ *must* exist in order */
  494.     /* to get the right offset from GMT.                        */
  495.     set_TZ(timezone, daylight);
  496. #endif /* __SASC */
  497. }
  498.  
  499.  
  500. #  ifdef AZTEC_C    /* SAS/C uses library gmtime(), localtime(), time() */
  501. struct tm *gmtime(const time_t *when)
  502. {
  503.     static struct tm tbuf;   /* this function is intrinsically non-reentrant */
  504.     static short smods[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  505.     long days = *when / 86400;
  506.     long secs = *when % 86400;
  507.     short yell, yday;
  508.  
  509.     tbuf.tm_wday = (days + 4) % 7;                   /* 1/1/70 is a Thursday */
  510.     tbuf.tm_year = 70 + 4 * (days / 1461);
  511.     yday = days % 1461;
  512.     while (yday >= (yell = (tbuf.tm_year & 3 ? 365 : 366)))
  513.         yday -= yell, tbuf.tm_year++;
  514.     smods[1] = (tbuf.tm_year & 3 ? 28 : 29);
  515.     tbuf.tm_mon = 0;
  516.     tbuf.tm_yday = yday;
  517.     while (yday >= smods[tbuf.tm_mon])
  518.         yday -= smods[tbuf.tm_mon++];
  519.     tbuf.tm_mday = yday + 1;
  520.     tbuf.tm_isdst = 0;
  521.     tbuf.tm_sec = secs % 60;
  522.     tbuf.tm_min = (secs / 60) % 60;
  523.     tbuf.tm_hour = secs / 3600;
  524.     tbuf.tm_hsec = 0;                   /* this field exists for Aztec only */
  525.     return &tbuf;
  526. }
  527.  
  528. struct tm *localtime(const time_t *when)
  529. {
  530.     struct tm *t;
  531.     time_t localwhen;
  532.     int dst = FALSE, sundays, lastweekday;
  533.  
  534.     tzset();
  535.     localwhen = *when - timezone;
  536.     t = gmtime(&localwhen);
  537.     /* So far we support daylight savings correction by the USA rule only: */
  538.     if (daylight && t->tm_mon >= 3 && t->tm_mon <= 9) {
  539.         if (t->tm_mon > 3 && t->tm_mon < 9)      /* May Jun Jul Aug Sep: yes */
  540.             dst = TRUE;
  541.         else {
  542.             sundays = (t->tm_mday + 6 - t->tm_wday) / 7;
  543.             if (t->tm_wday == 0 && t->tm_hour < 2 && sundays)
  544.                 sundays--;           /* a Sunday does not count until 2:00am */
  545.             if (t->tm_mon == 3 && sundays > 0)      /* first sunday in April */
  546.                 dst = TRUE;
  547.             else if (t->tm_mon == 9) {
  548.                 lastweekday = (t->tm_wday + 31 - t->tm_mday) % 7;
  549.                 if (sundays < (37 - lastweekday) / 7)
  550.                     dst = TRUE;                    /* last sunday in October */
  551.             }
  552.         }
  553.         if (dst) {
  554.             localwhen += 3600;
  555.             t = gmtime(&localwhen);                   /* crude but effective */
  556.             t->tm_isdst = 1;
  557.         }
  558.     }
  559.     return t;
  560. }
  561.  
  562.  
  563. #    ifdef ZIP
  564. time_t time(time_t *tp)
  565. {
  566.     time_t t;
  567.     struct DateStamp ds;
  568.     DateStamp(&ds);
  569.     t = ds.ds_Tick / TICKS_PER_SECOND + ds.ds_Minute * 60
  570.                                       + (ds.ds_Days + 2922) * 86400;
  571.     t = mktime(gmtime(&t));
  572.     /* gmtime leaves ds in the local timezone, mktime converts it to GMT */
  573.     if (tp) *tp = t;
  574.     return t;
  575. }
  576. #    endif /* ZIP */
  577. #  endif /* AZTEC_C */
  578. #endif /* !USE_TIME_LIB */
  579.  
  580. #endif /* !FUNZIP */
  581.  
  582.  
  583. #if CRYPT || !defined(FUNZIP)
  584.  
  585. /*  sendpkt.c
  586.  *  by A. Finkel, P. Lindsay, C. Sheppner
  587.  *  returns Res1 of the reply packet
  588.  */
  589. /*
  590. #include <exec/types.h>
  591. #include <exec/memory.h>
  592. #include <libraries/dos.h>
  593. #include <libraries/dosextens.h>
  594. #include <proto/exec.h>
  595. #include <proto/dos.h>
  596. */
  597.  
  598. LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
  599.  
  600. LONG sendpkt(pid,action,args,nargs)
  601. struct MsgPort *pid;           /* process identifier (handler message port) */
  602. LONG action,                   /* packet type (desired action)              */
  603.      *args,                    /* a pointer to argument list                */
  604.      nargs;                    /* number of arguments in list               */
  605. {
  606.  
  607.     struct MsgPort *replyport, *CreatePort(UBYTE *, long);
  608.     void DeletePort(struct MsgPort *);
  609.     struct StandardPacket *packet;
  610.     LONG count, *pargs, res1;
  611.  
  612.     replyport = CreatePort(NULL,0L);
  613.     if( !replyport ) return(0);
  614.  
  615.     packet = (struct StandardPacket *)AllocMem(
  616.             (long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
  617.     if( !packet )
  618.     {
  619.         DeletePort(replyport);
  620.         return(0);
  621.     }
  622.  
  623.     packet->sp_Msg.mn_Node.ln_Name  = (char *)&(packet->sp_Pkt);
  624.     packet->sp_Pkt.dp_Link          = &(packet->sp_Msg);
  625.     packet->sp_Pkt.dp_Port          = replyport;
  626.     packet->sp_Pkt.dp_Type          = action;
  627.  
  628.     /* copy the args into the packet */
  629.     pargs = &(packet->sp_Pkt.dp_Arg1);      /* address of 1st argument */
  630.     for( count=0; count<nargs; count++ )
  631.         pargs[count] = args[count];
  632.  
  633.     PutMsg(pid,(struct Message *)packet);   /* send packet */
  634.  
  635.     WaitPort(replyport);
  636.     GetMsg(replyport);
  637.  
  638.     res1 = packet->sp_Pkt.dp_Res1;
  639.  
  640.     FreeMem((char *)packet,(long)sizeof(*packet));
  641.     DeletePort(replyport);
  642.  
  643.     return(res1);
  644.  
  645. } /* sendpkt() */
  646.  
  647. #endif /* CRYPT || !FUNZIP */
  648.  
  649.  
  650. #if CRYPT || (defined(UNZIP) && !defined(FUNZIP))
  651.  
  652. /* Agetch() reads one raw keystroke -- uses sendpkt() */
  653.  
  654. int Agetch(void)
  655. {
  656.     LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
  657.     struct Task *me = FindTask(NULL);
  658.     struct CommandLineInterface *cli = BADDR(((struct Process *) me)->pr_CLI);
  659.     BPTR fh = cli->cli_StandardInput;   /* this is immune to < redirection */
  660.     void *conp = ((struct FileHandle *) BADDR(fh))->fh_Type;
  661.     char longspace[8];
  662.     long *flag = (long *) ((ULONG) &longspace[4] & ~3); /* LONGWORD ALIGNED! */
  663.     UBYTE c;
  664.  
  665.     *flag = 1;
  666.     sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);         /* assume success */
  667.     Read(fh, &c, 1);
  668.     *flag = 0;
  669.     sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);
  670.     if (c == 3)                                         /* ^C in input */
  671.         Signal(me, SIGBREAKF_CTRL_C);
  672.     return c;
  673. }
  674.  
  675. #endif /* CRYPT || (UNZIP && !FUNZIP) */
  676.