home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip21.zip / amiga / filedate.c < prev    next >
C/C++ Source or Header  |  1996-04-25  |  16KB  |  469 lines

  1. /* Low-level Amiga routines shared between Zip and UnZip.
  2.  *
  3.  * Contains:  FileDate()
  4.  *            tzset()           [replaces bad C library versions]
  5.  *            gmtime()          [ditto]
  6.  *            localtime()       [ditto]
  7.  *            time()            [ditto]
  8.  *            sendpkt()
  9.  *            Agetch()
  10.  *
  11.  * The first two are used by all Info-Zip programs except fUnZip.  The last two
  12.  * are used by all except the non-CRYPT version of fUnZip.  Probably some of
  13.  * the stuff in here is unused by ZipNote and ZipSplit too...  sendpkt() is
  14.  * used by Agetch() and FileDate(), and by windowheight() in amiga/amiga.c
  15.  * (UnZip).
  16.  */
  17.  
  18.  
  19. /* HISTORY/CHANGES
  20.  *  2 Sep 92, Greg Roelofs, Original coding.
  21.  *  6 Sep 92, John Bush, Incorporated into UnZip 5.1
  22.  *  6 Sep 92, John Bush, Interlude "FileDate()" defined, which calls or
  23.  *            redefines SetFileDate() depending upon AMIGADOS2 definition.
  24.  * 11 Oct 92, John Bush, Eliminated AMIGADOS2 switch by determining
  25.  *            revision via OpenLibrary() call.  Now only one version of
  26.  *            the program runs on both platforms (1.3.x vs. 2.x)
  27.  * 11 Oct 92, John Bush, Merged with Zip version and changed arg passing
  28.  *            to take time_t input instead of struct DateStamp.
  29.  *            Arg passing made to conform with utime().
  30.  * 22 Nov 92, Paul Kienitz, fixed includes for Aztec and cleaned up some
  31.  *            lint-ish errors; simplified test for AmigaDOS version.
  32.  * 11 Nov 95, Paul Kienitz, added Agetch() for crypt password input and
  33.  *            UnZip's "More" prompt -- simplifies crypt.h and avoids
  34.  *            use of library code redundant with sendpkt().  Made it
  35.  *            available to FUnZip, which does not use FileDate().
  36.  * 22 Nov 95, Paul Kienitz, created a new tzset() that gets the current
  37.  *            timezone from the Locale preferences.  These exist only under
  38.  *            AmigaDOS 2.1 and up, but it is probably correctly set on more
  39.  *            Amigas than the TZ environment variable is.  We check that
  40.  *            only if TZ is not validly set.  We do not parse daylight
  41.  *            savings syntax except to check for presence vs. absence of a
  42.  *            DST part; United States rules are assumed.  This is better
  43.  *            than the tzset()s in the Amiga compilers' libraries do.
  44.  * 15 Jan 96, Chr. Spieler, corrected the logic when to select low level
  45.  *            sendpkt() (when FileDate(), Agetch() or windowheight() is used),
  46.  *            and AMIGA's Agetch() (CRYPT, and UnZip(SFX)'s UzpMorePause()).
  47.  * 10 Feb 96, Paul Kienitz, re-fiddled that selection logic again, moved
  48.  *            stuff around for clarity.
  49.  * 16 Mar 96, Paul Kienitz, created a replacement localtime() to go with the
  50.  *            new tzset(), because Aztec's is hopelessly broken.  Also
  51.  *            gmtime(), which localtime() calls.
  52.  * 12 Apr 96, Paul Kienitz, daylight savings was being handled incorrectly.
  53.  * 21 Apr 96, Paul Kienitz, had to replace time() as well, Aztec's returns
  54.  *            local time instead of GMT.  That's why their localtime() was bad,
  55.  *            because it assumed time_t was already local, and gmtime() was
  56.  *            the one that checked TZ.
  57.  * 23 Apr 96, Chr. Spieler, deactivated time() replacement for UnZip stuff.
  58.  *            Currently, the UnZip sources do not make use of time() (and do
  59.  *            not supply the working mktime() replacement, either!).
  60.  */
  61.  
  62. #include <ctype.h>
  63. #include <string.h>
  64. #include <time.h>
  65. #include <errno.h>
  66. #include <stdio.h>
  67.  
  68. #include <exec/types.h>
  69. #include <exec/memory.h>
  70. #include <exec/libraries.h>
  71. #include <libraries/dos.h>
  72. #include <libraries/dosextens.h>
  73. #include <clib/exec_protos.h>
  74. #include <clib/dos_protos.h>
  75. #include <clib/locale_protos.h>
  76.  
  77. #ifdef AZTEC_C
  78. #  include <pragmas/exec_lib.h>
  79. #  include <pragmas/dos_lib.h>
  80. #  include <pragmas/locale_lib.h>
  81. #  define ESRCH  ENOENT
  82. #  define EOSERR EIO
  83. #endif
  84.  
  85. #if defined(LATTICE) || defined(__SASC)
  86. #  include <proto/exec.h>
  87. #  include <proto/dos.h>
  88. #endif
  89.  
  90. #define OF(x) x               /* so crypt.h prototypes compile okay */
  91. #if defined(ZIP) || defined(FUNZIP)
  92. #  define near                /* likewise */
  93.    typedef unsigned long ulg; /* likewise */
  94.    typedef size_t extent;     /* likewise */
  95.    typedef void zvoid;        /* likewise */
  96. #endif
  97. #include "crypt.h"            /* just so we can tell if CRYPT is defined */
  98.  
  99.  
  100. #ifndef FUNZIP
  101.  
  102. /***********************/
  103. /* Function filedate() */
  104. /***********************/
  105.  
  106. /*  FileDate() (originally utime.c), by Paul Wells.  Modified by John Bush
  107.  *  and others (see also sendpkt() comments, below); NewtWare SetFileDate()
  108.  *  clone cheaply ripped off from utime().
  109.  */
  110.  
  111. /* DESCRIPTION
  112.  * This routine chooses between 2 methods to set the file date on AMIGA.
  113.  * Since AmigaDOS 2.x came out, SetFileDate() was available in ROM (v.36
  114.  * and higher).  Under AmigaDOS 1.3.x (less than v.36 ROM), SetFileDate()
  115.  * must be accomplished by constructing a message packet and sending it
  116.  * to the file system handler of the file to be stamped.
  117.  *
  118.  * The system's ROM version is extracted from the external system Library
  119.  * base.
  120.  *
  121.  * NOTE:  although argument passing conforms with utime(), note the
  122.  *        following differences:
  123.  *          - Return value is boolean success/failure.
  124.  *          - If a structure or array is passed, only the first value
  125.  *            is used, which *may* correspond to date accessed and not
  126.  *            date modified.
  127.  */
  128.  
  129. #  ifndef SUCCESS
  130. #    define SUCCESS (-1L)
  131. #    define FAILURE 0L
  132. #  endif
  133.  
  134. #  define ReqVers 36L  /* required library version for SetFileDate() */
  135. #  define TZSIZE  40   /* max space allowed for a timezone string    */
  136.  
  137. extern struct Library *SysBase;
  138.  
  139. long timezone = 0;     /* should be pretty safe for reentrancy */
  140. int daylight = 0;
  141.  
  142. LONG FileDate (char *filename, time_t u[]);
  143. void tzset(void);
  144.  
  145. /* =============================================================== */
  146.  
  147. LONG FileDate(filename, u)
  148.     char *filename;
  149.     time_t u[];
  150. {
  151.     LONG SetFileDate(UBYTE *filename, struct DateStamp *pDate);
  152.     LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
  153.     struct MsgPort *taskport;
  154.     BPTR dirlock, lock;
  155.     struct FileInfoBlock *fib;
  156.     LONG pktargs[4];
  157.     UBYTE *ptr;
  158.     long ret;
  159.  
  160.     struct DateStamp pDate;
  161.     time_t mtime;
  162.  
  163.     tzset();
  164.     mtime = u[0] - timezone;
  165.  
  166. /* magic number = 2922 = 8 years + 2 leaps between 1970 - 1978 */
  167.     pDate.ds_Days = (mtime / 86400L) - 2922L;
  168.     mtime = mtime % 86400L;
  169.     pDate.ds_Minute = mtime / 60L;
  170.     mtime = mtime % 60L;
  171.     pDate.ds_Tick = mtime * TICKS_PER_SECOND;
  172.  
  173.     if (SysBase->lib_Version >= ReqVers) {
  174.         return (SetFileDate(filename,&pDate));  /* native routine at 2.0+ */
  175.     }
  176.     else  /* !(SysBase->lib_Version >=ReqVers) */
  177.     {
  178.         if( !(taskport = (struct MsgPort *)DeviceProc(filename)) )
  179.         {
  180.             errno = ESRCH;          /* no such process */
  181.             return FAILURE;
  182.         }
  183.  
  184.         if( !(lock = Lock(filename,SHARED_LOCK)) )
  185.         {
  186.             errno = ENOENT;         /* no such file */
  187.             return FAILURE;
  188.         }
  189.  
  190.         if( !(fib = (struct FileInfoBlock *)AllocMem(
  191.             (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
  192.         {
  193.             errno = ENOMEM;         /* insufficient memory */
  194.             UnLock(lock);
  195.             return FAILURE;
  196.         }
  197.  
  198.         if( Examine(lock,fib)==FAILURE )
  199.         {
  200.             errno = EOSERR;         /* operating system error */
  201.             UnLock(lock);
  202.             FreeMem(fib,(long)sizeof(*fib));
  203.             return FAILURE;
  204.         }
  205.  
  206.         dirlock = ParentDir(lock);
  207.         ptr = (UBYTE *)AllocMem(64L,MEMF_PUBLIC);
  208.         strcpy((ptr+1),fib->fib_FileName);
  209.         *ptr = strlen(fib->fib_FileName);
  210.         FreeMem(fib,(long)sizeof(*fib));
  211.         UnLock(lock);
  212.  
  213.         /* now fill in argument array */
  214.  
  215.         pktargs[0] = 0;
  216.         pktargs[1] = (LONG)dirlock;
  217.         pktargs[2] = (LONG)&ptr[0] >> 2;
  218.         pktargs[3] = (LONG)&pDate;
  219.  
  220.         errno = ret = sendpkt(taskport,ACTION_SET_DATE,pktargs,4L);
  221.  
  222.         FreeMem(ptr,64L);
  223.         UnLock(dirlock);
  224.  
  225.         return SUCCESS;
  226.     }  /* ?(SysBase->lib_Version >= ReqVers) */
  227. } /* FileDate() */
  228.  
  229.  
  230. void tzset(void)         /* check Locale and TZ -- the environment overrides */
  231. {
  232.     struct Library *LocaleBase;
  233.     struct Locale *ll;
  234.     char TZstring[TZSIZE], *p;
  235.     struct Process *me = (void *) FindTask(NULL);
  236.     void *old_window = me->pr_WindowPtr;
  237.     BPTR eh;
  238.     int z, valid = FALSE;
  239.     static zone_is_set = FALSE;         /* should be okayish with reentrancy */
  240.  
  241.     if (zone_is_set)
  242.         return;
  243.     timezone = 5 * 60;                                            /* default */
  244.     me->pr_WindowPtr = (void *) -1;   /* suppress any "Please insert" popups */
  245.     if (SysBase->lib_Version >= ReqVers) {
  246.         if (GetVar("TZ", TZstring, TZSIZE - 1, /* GVF_GLOBAL_ONLY */ 0) <= 0)
  247.             TZstring[0] = 0;
  248.     } else {                    /* early AmigaDOS, get env var the crude way */
  249.         z = 0;
  250.         if (eh = Open("ENV:TZ", MODE_OLDFILE)) {
  251.             z = Read(eh, TZstring, TZSIZE - 1);
  252.             Close(eh);
  253.             if (z < 0)
  254.                 z = 0;
  255.         }
  256.         TZstring[z] = '\0';
  257.     }
  258.     if (TZstring[0]) {
  259.         z = 3600;
  260.         for (p = TZstring; *p && !isdigit(*p) && *p != '-'; p++) ;
  261.         if (*p == '-')
  262.             z = -3600, p++;
  263.         if (*p) {
  264.             timezone = 0;
  265.             do {
  266.                 while (isdigit(*p))
  267.                     timezone = timezone * 10 + z * (*p++ - '0'), valid = TRUE;
  268.                 if (*p == ':') p++;
  269.             } while (isdigit(*p) && (z /= 60) > 0);
  270.         }
  271.         while (isspace(*p)) p++;                      /* probably not needed */
  272.         if (valid)
  273.             zone_is_set = TRUE, daylight = !!*p;   /* a DST name part exists */
  274.     }
  275.     if (!valid && (LocaleBase = OpenLibrary("locale.library", 0))) {
  276.         if (ll = OpenLocale(NULL)) {
  277.             z = ll->loc_GMTOffset;
  278.             if (z == -5) {
  279.                 if (eh = Lock("ENV:sys/locale.prefs", ACCESS_READ))
  280.                     UnLock(eh);
  281.                 else
  282.                     z = 5; /* bug: locale not initialized, default is bogus! */
  283.             } else
  284.                 zone_is_set = TRUE;
  285.             timezone = z * 60;
  286.             daylight = (z >= 4*60 && z <= 9*60);    /* apply in the Americas */
  287.             CloseLocale(ll);
  288.         }
  289.         CloseLibrary(LocaleBase);
  290.     }
  291.     me->pr_WindowPtr = old_window;
  292. }
  293.  
  294.  
  295. struct tm *gmtime(const time_t *when)
  296. {
  297.     static struct tm tbuf;   /* this function is intrinsically non-reentrant */
  298.     static short smods[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  299.     long days = *when / 86400;
  300.     long secs = *when % 86400;
  301.     short yell, yday;
  302.  
  303.     tbuf.tm_wday = (days + 4) % 7;                   /* 1/1/70 is a Thursday */
  304.     tbuf.tm_year = 70 + 4 * (days / 1461);
  305.     yday = days % 1461;
  306.     while (yday >= (yell = (tbuf.tm_year & 3 ? 365 : 366)))
  307.         yday -= yell, tbuf.tm_year++;
  308.     smods[1] = (tbuf.tm_year & 3 ? 28 : 29);
  309.     tbuf.tm_mon = 0;
  310.     tbuf.tm_yday = yday;
  311.     while (yday >= smods[tbuf.tm_mon])
  312.         yday -= smods[tbuf.tm_mon++];
  313.     tbuf.tm_mday = yday + 1;
  314.     tbuf.tm_isdst = 0;
  315.     tbuf.tm_sec = secs % 60;
  316.     tbuf.tm_min = (secs / 60) % 60;
  317.     tbuf.tm_hour = secs / 3600;
  318. #ifdef AZTEC_C
  319.     tbuf.tm_hsec = 0;
  320. #endif
  321.     return &tbuf;
  322. }
  323.  
  324.  
  325. struct tm *localtime(const time_t *when)
  326. {
  327.     struct tm *t;
  328.     time_t localwhen;
  329.     int dst = FALSE, sundays, lastweekday;
  330.  
  331.     tzset();
  332.     localwhen = *when - timezone;
  333.     t = gmtime(&localwhen);
  334.     /* So far we support daylight savings correction by the USA rule only: */
  335.     if (daylight && t->tm_mon >= 3 && t->tm_mon <= 9) {
  336.         if (t->tm_mon > 3 && t->tm_mon < 9)      /* May Jun Jul Aug Sep: yes */
  337.             dst = TRUE;
  338.         else {
  339.             sundays = (t->tm_mday + 6 - t->tm_wday) / 7;
  340.             if (t->tm_wday == 0 && t->tm_hour < 2 && sundays)
  341.                 sundays--;           /* a Sunday does not count until 2:00am */
  342.             if (t->tm_mon == 3 && sundays > 0)      /* first sunday in April */
  343.                 dst = TRUE;
  344.             else if (t->tm_mon == 9) {
  345.                 lastweekday = (t->tm_wday + 31 - t->tm_mday) % 7;
  346.                 if (sundays < (37 - lastweekday) / 7)
  347.                     dst = TRUE;                    /* last sunday in October */
  348.             }
  349.         }
  350.         if (dst) {
  351.             localwhen += 3600;
  352.             t = gmtime(&localwhen);                   /* crude but effective */
  353.             t->tm_isdst = 1;
  354.         }
  355.     }
  356.     return t;
  357. }
  358.  
  359.  
  360. #ifdef ZIP
  361. time_t time(time_t *tp)
  362. {
  363.     time_t t;
  364.     struct DateStamp ds;
  365.     DateStamp(&ds);
  366.     t = ds.ds_Tick / TICKS_PER_SECOND + ds.ds_Minute * 60
  367.                                       + (ds.ds_Days + 2922) * 86400;
  368.     t = mktime(gmtime(&t));
  369.     /* gmtime leaves ds in the local timezone, mktime converts it to GMT */
  370.     if (tp) *tp = t;
  371.     return t;
  372. }
  373. #endif /* ZIP */
  374.  
  375. #endif /* !FUNZIP */
  376.  
  377.  
  378. #if defined(CRYPT) || !defined(FUNZIP)
  379.  
  380. /*  sendpkt.c
  381.  *  by A. Finkel, P. Lindsay, C. Sheppner
  382.  *  returns Res1 of the reply packet
  383.  */
  384. /*
  385. #include <exec/types.h>
  386. #include <exec/memory.h>
  387. #include <libraries/dos.h>
  388. #include <libraries/dosextens.h>
  389. #include <proto/exec.h>
  390. #include <proto/dos.h>
  391. */
  392.  
  393. LONG sendpkt(pid,action,args,nargs)
  394. struct MsgPort *pid;           /* process identifier (handler message port) */
  395. LONG action,                   /* packet type (desired action)              */
  396.      *args,                    /* a pointer to argument list                */
  397.      nargs;                    /* number of arguments in list               */
  398. {
  399.  
  400.     struct MsgPort *replyport, *CreatePort(UBYTE *, long);
  401.     void DeletePort(struct MsgPort *);
  402.     struct StandardPacket *packet;
  403.     LONG count, *pargs, res1;
  404.  
  405.     replyport = CreatePort(NULL,0L);
  406.     if( !replyport ) return(0);
  407.  
  408.     packet = (struct StandardPacket *)AllocMem(
  409.             (long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
  410.     if( !packet )
  411.     {
  412.         DeletePort(replyport);
  413.         return(0);
  414.     }
  415.  
  416.     packet->sp_Msg.mn_Node.ln_Name  = (char *)&(packet->sp_Pkt);
  417.     packet->sp_Pkt.dp_Link          = &(packet->sp_Msg);
  418.     packet->sp_Pkt.dp_Port          = replyport;
  419.     packet->sp_Pkt.dp_Type          = action;
  420.  
  421.     /* copy the args into the packet */
  422.     pargs = &(packet->sp_Pkt.dp_Arg1);      /* address of 1st argument */
  423.     for( count=0; count<nargs; count++ )
  424.         pargs[count] = args[count];
  425.  
  426.     PutMsg(pid,(struct Message *)packet);   /* send packet */
  427.  
  428.     WaitPort(replyport);
  429.     GetMsg(replyport);
  430.  
  431.     res1 = packet->sp_Pkt.dp_Res1;
  432.  
  433.     FreeMem((char *)packet,(long)sizeof(*packet));
  434.     DeletePort(replyport);
  435.  
  436.     return(res1);
  437.  
  438. } /* sendpkt() */
  439.  
  440. #endif /* CRYPT || !FUNZIP */
  441.  
  442.  
  443. #if defined(CRYPT) || (defined(UNZIP) && !defined(FUNZIP))
  444.  
  445. /* Agetch() reads one raw keystroke -- uses sendpkt() */
  446.  
  447. int Agetch(void)
  448. {
  449.     LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
  450.     struct Task *me = FindTask(NULL);
  451.     struct CommandLineInterface *cli = BADDR(((struct Process *) me)->pr_CLI);
  452.     BPTR fh = cli->cli_StandardInput;   /* this is immune to < redirection */
  453.     void *conp = ((struct FileHandle *) BADDR(fh))->fh_Type;
  454.     char longspace[8];
  455.     long *flag = (long *) ((ULONG) &longspace[4] & ~3); /* LONGWORD ALIGNED! */
  456.     UBYTE c;
  457.  
  458.     *flag = 1;
  459.     sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);         /* assume success */
  460.     Read(fh, &c, 1);
  461.     *flag = 0;
  462.     sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);
  463.     if (c == 3)                                         /* ^C in input */
  464.         Signal(me, SIGBREAKF_CTRL_C);
  465.     return c;
  466. }
  467.  
  468. #endif /* CRYPT || (UNZIP && !FUNZIP) */
  469.