home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip511.zip / amiga / amiga.c next >
C/C++ Source or Header  |  1994-07-07  |  26KB  |  771 lines

  1. /*------------------------------------------------------------------------
  2.  
  3.   amiga.c
  4.  
  5.   Amiga-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.   See History.5xx for revision history.
  7.  
  8.   Contents:   mapattr()
  9.               mapname()
  10.               do_wild()
  11.               checkdir()
  12.               cmptime()
  13.               invlocal()
  14.               close_outfile()
  15.               _abort()         (Aztec C only)
  16.               version()
  17.  
  18.   ------------------------------------------------------------------------*/
  19.  
  20.  
  21. #include "unzip.h"
  22.  
  23. /* Globular varibundus */
  24.  
  25. static int created_dir;      /* used in mapname(), checkdir() */
  26. static int renamed_fullpath; /* ditto */
  27. #define PERMS   0777
  28. #define MKDIR(path,mode) mkdir(path)
  29.  
  30.  
  31. #ifndef S_ISCRIPT          /* not having one implies you have none */
  32. #  define S_IARCHIVE 0020  /* not modified since this bit was last set */
  33. #  define S_IREAD    0010  /* can be opened for reading */
  34. #  define S_IWRITE   0004  /* can be opened for writing */
  35. #  define S_IDELETE  0001  /* can be deleted */
  36. #endif /* S_ISCRIPT */
  37.  
  38. #ifndef S_IRWD
  39. #  define S_IRWD     0015  /* useful combo of Amiga privileges */
  40. #endif /* !S_IRWD */
  41.  
  42. #ifndef S_IHIDDEN
  43. #  define S_IHIDDEN  0200  /* hidden supported in future AmigaDOS (someday) */
  44. #endif /* !S_HIDDEN */
  45.  
  46.  
  47.  
  48. /**********************/
  49. /* Function mapattr() */
  50. /**********************/
  51.  
  52. int mapattr(void)      /* Amiga version */
  53. {
  54.     ulg  tmp = crec.external_file_attributes;
  55.  
  56.  
  57.     /* Amiga attributes = hsparwed = hidden, script, pure, archive,
  58.      * read, write, execute, delete */
  59.  
  60.     switch (pInfo->hostnum) {
  61.         case AMIGA_:
  62.             if ((tmp & 1) == (tmp>>18 & 1))
  63.                 tmp ^= 0x000F0000;      /* PKAZip compatibility kluge */
  64.             /* turn off archive bit for restored Amiga files */
  65.             pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
  66.             break;
  67.  
  68.         case UNIX_:   /* preserve read, write, execute:  use logical-OR of */
  69.         case VMS_:    /* user, group, and other; if writable, set delete bit */
  70.             tmp >>= 16;
  71.             tmp = (( tmp>>6 | tmp>>3 | tmp) & 07) << 1;
  72.             pInfo->file_attr = (unsigned)(tmp&S_IWRITE? tmp|S_IDELETE : tmp);
  73.             break;
  74.  
  75.         /* all other platforms:  assume read-only bit in DOS half of attribute
  76.          * word is set correctly ==> will become READ or READ+WRITE+DELETE */
  77.         case FS_FAT_:
  78.         case FS_HPFS_:  /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
  79.         case FS_NTFS_:
  80.         case MAC_:
  81.         case ATARI_:
  82.         case TOPS20_:
  83.         default:
  84.             pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD); 
  85.             break;
  86.  
  87.     } /* end switch (host-OS-created-by) */
  88.  
  89.     pInfo->file_attr &= 0xff;   /* mask off all but lower eight bits */
  90.     return 0;
  91.  
  92. } /* end function mapattr() */
  93.  
  94.  
  95.  
  96.  
  97. /************************/
  98. /*  Function mapname()  */
  99. /************************/
  100.  
  101. int mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  102.     int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  103. {                     /* 3 if error (skip file), 10 if no memory (skip file) */
  104.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  105.     char *pp, *cp=NULL;         /* character pointers */
  106.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  107.     int quote = FALSE;          /* flags */
  108.     int error = 0;
  109.     register unsigned workch;   /* hold the character being tested */
  110.  
  111.  
  112. /*---------------------------------------------------------------------------
  113.     Initialize various pointers and counters and stuff.
  114.   ---------------------------------------------------------------------------*/
  115.  
  116.     /* can create path as long as not just freshening, or if user told us */
  117.     create_dirs = (!fflag || renamed);
  118.  
  119.     created_dir = FALSE;        /* not yet */
  120.  
  121.     /* user gave full pathname:  don't prepend rootpath */
  122.     renamed_fullpath = (renamed && strchr(filename, ':'));
  123.  
  124.     if (checkdir((char *)NULL, INIT) == 10)
  125.         return 10;              /* initialize path buffer, unless no memory */
  126.  
  127.     *pathcomp = '\0';           /* initialize translation buffer */
  128.     pp = pathcomp;              /* point to translation buffer */
  129.     if (jflag)                  /* junking directories */
  130.         cp = (char *)strrchr(filename, '/');
  131.     if (cp == NULL)             /* no '/' or not junking dirs */
  132.         cp = filename;          /* point to internal zipfile-member pathname */
  133.     else
  134.         ++cp;                   /* point to start of last component of path */
  135.  
  136. /*---------------------------------------------------------------------------
  137.     Begin main loop through characters in filename.
  138.   ---------------------------------------------------------------------------*/
  139.  
  140.     while ((workch = (uch)*cp++) != 0) {
  141.  
  142.         if (quote) {                 /* if character quoted, */
  143.             *pp++ = (char)workch;    /*  include it literally */
  144.             quote = FALSE;
  145.         } else
  146.             switch (workch) {
  147.             case '/':             /* can assume -j flag not given */
  148.                 *pp = '\0';
  149.                 if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  150.                     return error;
  151.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  152.                 lastsemi = NULL;  /* leave directory semi-colons alone */
  153.                 break;
  154.  
  155.             case ';':             /* VMS version (or DEC-20 attrib?) */
  156.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  157.                 *pp++ = (char)workch;  /*  later, if requested */
  158.                 break;
  159.  
  160.             case '\026':          /* control-V quote for special chars */
  161.                 quote = TRUE;     /* set flag for next character */
  162.                 break;
  163.  
  164.             default:
  165.                 /* allow European characters in filenames: */
  166.                 if (isprint(workch) || (128 <= workch && workch <= 255))
  167.                     *pp++ = (char)workch;
  168.             } /* end switch */
  169.  
  170.     } /* end while loop */
  171.  
  172.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  173.  
  174.     /* if not saving them, remove with VMS version numbers (appended ";###") */
  175.     if (!V_flag && lastsemi) {
  176.         pp = lastsemi + 1;
  177.         while (isdigit((uch)(*pp)))
  178.             ++pp;
  179.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  180.             *lastsemi = '\0';
  181.     }
  182.  
  183. /*---------------------------------------------------------------------------
  184.     Report if directory was created (and no file to create:  filename ended
  185.     in '/'), check name to be sure it exists, and combine path and name be-
  186.     fore exiting.
  187.   ---------------------------------------------------------------------------*/
  188.  
  189.     if (filename[strlen(filename) - 1] == '/') {
  190.         if (checkdir(filename, GETPATH) == 1) {
  191.             fprintf(stderr, "pathname too long:  truncat{ed/ing}\n");
  192.             return 1;  /* GRR:  NEEDS WORK! (do checking only when appending) */
  193.         }
  194.         if (created_dir && QCOND2) {
  195.             fprintf(stdout, "   creating: %s\n", filename);
  196.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  197.         }
  198.         return 2;   /* dir existed already; don't look for data to extract */
  199.     }
  200.  
  201.     if (*pathcomp == '\0') {
  202.         fprintf(stderr, "mapname:  conversion of %s failed\n", filename);
  203.         return 3;
  204.     }
  205.  
  206.     if ((error = checkdir(pathcomp, APPEND_NAME)) == 1) {
  207.         /* GRR:  OK if truncated here:  warn and continue */
  208.         /* (warn in checkdir?) */
  209.     }
  210.     checkdir(filename, GETPATH);
  211.  
  212.     return error;
  213.  
  214. } /* end function mapname() */
  215.  
  216.  
  217. static int ispattern(char *p)
  218. {
  219.     register char c;
  220.     while (c = *p++)
  221.     if (c == '\\') {
  222.         if (!*++p)
  223.         return FALSE;
  224.         } else if (c == '?' || c == '*')
  225.             return TRUE;
  226.         else if (c == '[') {
  227.             for (;;) {
  228.                 if (!(c = *p++))
  229.                     return FALSE;
  230.                 else if (c == '\\') {
  231.                     if (!*++p)
  232.             return FALSE;
  233.                 } else if (c == ']')
  234.                     return TRUE;
  235.             }
  236.         }
  237.     return FALSE;
  238. }
  239.  
  240. /**********************/
  241. /* Function do_wild() */   /* for porting:  dir separator; match(ignore_case) */
  242. /**********************/
  243.  
  244. char *do_wild(wildspec)
  245.     char *wildspec;         /* only used first time on a given dir */
  246. {
  247.     static DIR *dir = NULL;
  248.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  249.     static int firstcall=TRUE, have_dirname, dirnamelen;
  250.     struct dirent *file;
  251.     BPTR lok = 0;
  252.     /* Even when we're just returning wildspec, we *always* do so in
  253.      * matchname[]--calling routine is allowed to append four characters
  254.      * to the returned string, and wildspec may be a pointer to argv[].
  255.      */
  256.     if (firstcall) {        /* first call:  must initialize everything */
  257.         firstcall = FALSE;
  258.         /* avoid needless readdir() scans: */
  259.         if (!ispattern(wildspec) || (lok = Lock(wildspec, ACCESS_READ))) {
  260.             if (lok) UnLock(lok);
  261.             have_dirname = FALSE;
  262.             strcpy(matchname, wildspec);
  263.             return matchname;
  264.         }
  265.  
  266.         /* break the wildspec into a directory part and a wildcard filename */
  267.         if ((wildname = strrchr(wildspec, '/')) == NULL
  268.                         && (wildname = strrchr(wildspec, ':')) == NULL) {
  269.             dirname = "";               /* current dir */
  270.             dirnamelen = 1;
  271.             have_dirname = FALSE;
  272.             wildname = wildspec;
  273.         } else {
  274.             ++wildname;     /* point at character after '/' or ':' */
  275.             dirnamelen = wildname - wildspec;
  276.             if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  277.                 fprintf(stderr, "warning:  can't allocate wildcard buffers\n");
  278.                 strcpy(matchname, wildspec);
  279.                 return matchname;   /* but maybe filespec was not a wildcard */
  280.             }
  281.             strncpy(dirname, wildspec, dirnamelen);
  282.             dirname[dirnamelen] = 0;
  283.             have_dirname = TRUE;
  284.         }
  285.  
  286.         if ((dir = opendir(dirname)) != NULL) {
  287.             while ((file = readdir(dir)) != NULL) {
  288.                 if (match(file->d_name, wildname, 1)) {  /* case insensitive */
  289.                     if (have_dirname) {
  290.                         strcpy(matchname, dirname);
  291.                         strcpy(matchname+dirnamelen, file->d_name);
  292.                     } else
  293.                         strcpy(matchname, file->d_name);
  294.                     return matchname;
  295.                 }
  296.             }
  297.             /* if we get to here directory is exhausted, so close it */
  298.             closedir(dir);
  299.             dir = NULL;
  300.         }
  301.  
  302.         /* return the raw wildspec in case that works (e.g., directory not
  303.          * searchable, but filespec was not wild and file is readable) */
  304.         strcpy(matchname, wildspec);
  305.         return matchname;
  306.     }
  307.  
  308.     /* last time through, might have failed opendir but returned raw wildspec */
  309.     if (dir == NULL) {
  310.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  311.         if (have_dirname)
  312.             free(dirname);
  313.         return (char *)NULL;
  314.     }
  315.  
  316.     /* If we've gotten this far, we've read and matched at least one entry
  317.      * successfully (in a previous call), so dirname has been copied into
  318.      * matchname already.
  319.      */
  320.     while ((file = readdir(dir)) != NULL)
  321.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  322.             if (have_dirname) {
  323.                 /* strcpy(matchname, dirname); */
  324.                 strcpy(matchname+dirnamelen, file->d_name);
  325.             } else
  326.                 strcpy(matchname, file->d_name);
  327.             return matchname;
  328.         }
  329.  
  330.     closedir(dir);     /* have read at least one dir entry; nothing left */
  331.     dir = NULL;
  332.     firstcall = TRUE;  /* reset for new wildspec */
  333.     if (have_dirname)
  334.         free(dirname);
  335.     return (char *)NULL;
  336.  
  337. } /* end function do_wild() */
  338.  
  339.  
  340.  
  341. /***********************/
  342. /* Function checkdir() */
  343. /***********************/
  344.  
  345. int checkdir(pathcomp, flag)
  346.     char *pathcomp;
  347.     int flag;
  348. /*
  349.  * returns:  1 - (on APPEND_xxx) truncated path component
  350.  *           2 - path doesn't exist, not allowed to create
  351.  *           3 - path doesn't exist, tried to create and failed; or
  352.  *               path exists and is not a directory, but is supposed to be
  353.  *          10 - can't allocate memory for filename buffers
  354.  */
  355. {
  356.     static int rootlen = 0;   /* length of rootpath */
  357.     static char *rootpath;    /* user's "extract-to" directory */
  358.     static char *buildpath;   /* full path (so far) to extracted file */
  359.     static char *end;         /* pointer to end of buildpath ('\0') */
  360.  
  361. #   define FN_MASK   7
  362. #   define FUNCTION  (flag & FN_MASK)
  363.  
  364.  
  365.  
  366. /*---------------------------------------------------------------------------
  367.     APPEND_DIR:  append the path component to the path being built and check
  368.     for its existence.  If doesn't exist and we are creating directories, do
  369.     so for this one; else signal success or error as appropriate.
  370.   ---------------------------------------------------------------------------*/
  371.  
  372. /* GRR:  check path length after each segment:  warn about truncation */
  373.  
  374.     if (FUNCTION == APPEND_DIR) {
  375.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  376.         while ((*end = *pathcomp++))
  377.             ++end;
  378.         if (stat(buildpath, &statbuf)) {   /* path doesn't exist */
  379.             if (!create_dirs) {   /* told not to create (freshening) */
  380.                 free(buildpath);
  381.                 return 2;         /* path doesn't exist:  nothing to do */
  382.             }
  383.             if (MKDIR(buildpath, 0777) == -1) {   /* create the directory */
  384.                 fprintf(stderr, 
  385.                 "checkdir:  can't create %s\n           unable to process %s.\n"
  386.                   , buildpath, filename);
  387.                 fflush(stderr);
  388.                 free(buildpath);
  389.                 return 3;      /* path didn't exist, tried to create, failed */
  390.             }
  391.             created_dir = TRUE;
  392.         } else if (!S_ISDIR(statbuf.st_mode)) {
  393.             fprintf(stderr, "checkdir:  %s exists but is not a directory\n\
  394.            unable to process %s.\n", buildpath, filename);
  395.             fflush(stderr);
  396.             free(buildpath);
  397.             return 3;          /* path existed but wasn't dir */
  398.         }
  399.         *end++ = '/';
  400.         *end = '\0';
  401.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  402.         return 0;
  403.  
  404.     } /* end if (FUNCTION == APPEND_DIR) */
  405.  
  406. /*---------------------------------------------------------------------------
  407.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  408.     buildpath.
  409.   ---------------------------------------------------------------------------*/
  410.  
  411.     if (FUNCTION == GETPATH) {
  412.         strcpy(pathcomp, buildpath);  /* DO ERROR CHECKING:  TOO LONG? */
  413.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  414.         free(buildpath);
  415.         buildpath = end = NULL;
  416.         return 0;
  417.     }
  418.  
  419. /*---------------------------------------------------------------------------
  420.     APPEND_NAME:  assume the path component is the filename; append it and
  421.     return without checking for existence.
  422.   ---------------------------------------------------------------------------*/
  423.  
  424.     if (FUNCTION == APPEND_NAME) {                /* DO ERROR CHECKING */
  425.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  426.         while ((*end = *pathcomp++))
  427.             ++end;
  428.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  429.         return 0;  /* could check for existence here, prompt for new name... */
  430.     }
  431.  
  432. /*---------------------------------------------------------------------------
  433.     INIT:  allocate and initialize buffer space for the file currently being
  434.     extracted.  If file was renamed with an absolute path, don't prepend the
  435.     extract-to path.
  436.   ---------------------------------------------------------------------------*/
  437.  
  438.     if (FUNCTION == INIT) {
  439.         Trace((stderr, "initializing buildpath to "));
  440.         if ((buildpath = (char *)malloc(strlen(filename)+rootlen+1)) == NULL)
  441.             return 10;
  442.         if ((rootlen > 0) && !renamed_fullpath) {
  443.             strcpy(buildpath, rootpath);
  444.             end = buildpath + rootlen;
  445.         } else {
  446.             *buildpath = '\0';
  447.             end = buildpath;
  448.         }
  449.         Trace((stderr, "[%s]\n", buildpath));
  450.         return 0;
  451.     }
  452.  
  453. /*---------------------------------------------------------------------------
  454.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  455.     sary; else assume it's a zipfile member and return.  This path segment
  456.     gets used in extracting all members from every zipfile specified on the
  457.     command line.
  458.   ---------------------------------------------------------------------------*/
  459.  
  460.     if (FUNCTION == ROOT) {
  461.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  462.         if (pathcomp == NULL) {
  463.             rootlen = 0;
  464.             return 0;
  465.         }
  466.         if ((rootlen = strlen(pathcomp)) > 0) {
  467.             int had_trailing_pathsep=FALSE;
  468.  
  469.             if (pathcomp[rootlen-1] == '/') {
  470.                 pathcomp[--rootlen] = '\0';
  471.                 had_trailing_pathsep = TRUE;
  472.             }
  473.             if (stat(pathcomp, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
  474.                 /* path does not exist */
  475.                 if (!create_dirs || !had_trailing_pathsep) {
  476.                     rootlen = 0;
  477.                     return 2;   /* treat as stored file */
  478.                 }
  479. /* GRR:  scan for wildcard characters?  OS-dependent...  if find any, return 2:
  480.  * treat as stored file(s) */
  481.                 /* create the directory (could add loop here to scan pathcomp
  482.                  * and create more than one level, but why really necessary?) */
  483.                 if (MKDIR(pathcomp, 0777) == -1) {
  484.                     fprintf(stderr,
  485.                       "checkdir:  can't create extraction directory: %s\n",
  486.                       pathcomp);
  487.                     fflush(stderr);
  488.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  489.                     return 3;  /* failed:  file exists, or 2+ levels required */
  490.                 }
  491.             }
  492.             if ((rootpath = (char *)malloc(rootlen+2)) == NULL) {
  493.                 rootlen = 0;
  494.                 return 10;
  495.             }
  496.             strcpy(rootpath, pathcomp);
  497.             if (rootpath[rootlen - 1] != ':')
  498.                 rootpath[rootlen++] = '/';
  499.             rootpath[rootlen] = '\0';
  500.         }
  501.         Trace((stderr, "rootpath now = [%s]\n", rootpath));
  502.         return 0;
  503.     }
  504.  
  505. /*---------------------------------------------------------------------------
  506.     END:  free rootpath, immediately prior to program exit.
  507.   ---------------------------------------------------------------------------*/
  508.  
  509.     if (FUNCTION == END) {
  510.         Trace((stderr, "freeing rootpath\n"));
  511.         if (rootlen > 0)
  512.             free(rootpath);
  513.         return 0;
  514.     }
  515.  
  516.     return 99;  /* should never reach */
  517.  
  518. } /* end function checkdir() */
  519.  
  520.  
  521. /**********************/
  522. /* Function cmptime() */
  523. /**********************/
  524.  
  525. /* cmptime() clone pinched from from Zip1.9h,
  526.  * by Mark Adler, Jean-loup Gailly, et al., circa 1991.  
  527.  * Incorporated into UnZip 5.1d by John Bush
  528.  */
  529.  
  530. int cmptime(p, q)
  531. struct tm *p, *q;       /* times to compare */
  532. /* Return negative if time p is before time q, positive if after, and
  533.    zero if the same */
  534. {
  535.   int r;                /* temporary variable */
  536.  
  537.   if (p == NULL)
  538.     return -1;
  539.   else if ((r = p->tm_year - q->tm_year) != 0)
  540.     return r;
  541.   else if ((r = p->tm_mon - q->tm_mon) != 0)
  542.     return r;
  543.   else if ((r = p->tm_mday - q->tm_mday) != 0)
  544.     return r;
  545.   else if ((r = p->tm_hour - q->tm_hour) != 0)
  546.     return r;
  547.   else if ((r = p->tm_min - q->tm_min) != 0)
  548.     return r;
  549.   else
  550.     return p->tm_sec - q->tm_sec;
  551. }
  552.  
  553.  
  554. /***********************/
  555. /* Function invlocal() */
  556. /***********************/
  557.  
  558. /* mktime() clone pinched from from Zip1.9h,
  559.  * by Mark Adler and Jean-loup Gailly, et.al, circa 1991.  
  560.  * Incorporated into UnZip 5.1d by John Bush
  561.  */
  562. time_t invlocal(t)
  563. struct tm *t;           /* time to convert */
  564. /* Find inverse of localtime() using bisection.  This routine assumes that
  565.    time_t is an integer type, either signed or unsigned.  The expectation
  566.    is that sometime before the year 2038, time_t will be made a 64-bit
  567.    integer, and this routine will still work. */
  568. {
  569.   time_t i;             /* midpoint of current root range */
  570.   time_t l;             /* lower end of root range */
  571.   time_t u;             /* upper end of root range */
  572.  
  573.   /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  574.      integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  575.      the Unix systems in the world come to a grinding halt.  Either that, or
  576.      all those systems will suddenly find themselves transported to December
  577.      of 1901 ... */
  578.   l = 0;
  579.   u = 1;
  580.   while (u < (u << 1))
  581.     u = (u << 1) + 1;
  582.  
  583.   /* Find the root */
  584.   while (u - l > 1)
  585.   {
  586.     i = l + ((u - l) >> 1);
  587.     if (cmptime(localtime(&i), t) <= 0)
  588.       l = i;
  589.     else
  590.       u = i;
  591.   }
  592.   return l;
  593. }
  594.  
  595.  
  596.  
  597. /**************************************/
  598. /* Function close_outfile() */
  599. /**************************************/
  600. /* this part differs slightly with Zip */
  601. /*-------------------------------------*/
  602.  
  603. void close_outfile(void)
  604. {
  605.     struct tm t;                /* good ole time structure */
  606.     time_t u[2];                /* mean ole time stamp */
  607.     ulg dd,dt;                  /* DOS format time stamps */
  608.     LONG FileDate();
  609.     time_t invlocal();
  610.  
  611.     if (cflag)                  /* can't set time on stdout */
  612.         return;
  613.  
  614.   /* close the file *before* setting its time under AmigaDos */
  615.  
  616.     fclose(outfile);
  617.  
  618.   /* assign date and time to local variables */
  619.  
  620.     dd = lrec.last_mod_file_date;
  621.     dt = lrec.last_mod_file_time;
  622.  
  623.   /* Convert DOS time to time_t format in (time_t)u */
  624.  
  625.     t.tm_sec =   (int) (dt <<  1) & 0x3e;
  626.     t.tm_min =   (int) (dt >>  5) & 0x3f;
  627.     t.tm_hour =  (int) (dt >> 11) & 0x1f;
  628.  
  629.     t.tm_mday =  (int) (dd        & 0x1f);
  630.     t.tm_mon =  ((int) (dd >>  5) & 0xf ) - 1;
  631.     t.tm_year = ((int) (dd >>  9) & 0x7f) + 80;
  632.  
  633.   /* invlocal() is equivalent to mktime() */
  634.  
  635.     u[0] = u[1] = invlocal(&t); 
  636.  
  637. #ifdef DEBUG
  638.     fprintf (stderr,"\nclose_outfile(): u=%s\n",ctime(&u[0]));
  639. #endif
  640.  
  641.     if (!FileDate(filename, u))
  642.         fprintf(stderr, "warning:  can't set the time for %s\n", filename);
  643.  
  644.   /* set file perms after closing (not done at creation)--see mapattr() */
  645.  
  646.     chmod(filename, pInfo->file_attr);
  647.  
  648. } /* end function close_outfile() */
  649.  
  650.  
  651. /********************************************************************/
  652. /* Load filedate as a separate external file; it's used by Zip, too.*/
  653. /*                                                                  */
  654. #include "amiga/filedate.c"                                      /* */
  655. /*                                                                  */
  656. /********************************************************************/
  657.  
  658. /**************** for Aztec, do linewise with stat.c ****************/
  659.  
  660. #ifdef AZTEC_C
  661. #  include "amiga/stat.c"
  662. /* this is the exact same stat.c used for Aztec by Zip */
  663.  
  664. #  include <stdio.h>
  665. #  include "crypt.h"
  666.  
  667. void _abort(void)               /* called when ^C is pressed */
  668. {
  669.     echon();
  670.     close_leftover_open_dirs();
  671.     fflush(stdout);
  672.     fputs("\n^C\n", stderr);
  673.     exit(1);
  674. }
  675. #endif /* AZTEC_C */
  676.  
  677.  
  678. #ifndef SFX
  679.  
  680. /************************/
  681. /*  Function version()  */
  682. /************************/
  683.  
  684.  
  685. /* NOTE:  the following include depends upon the environment 
  686.  *        variable $Workbench to be set correctly.  (Set by
  687.  *        default, by kickstart during startup)
  688.  */
  689. int WBversion = (int)
  690. #include "ENV:Workbench"
  691. ;
  692.  
  693. void version()
  694. {
  695.  
  696. /* Define buffers. */
  697.  
  698.    char buf1[16];  /* compiler name */
  699.    char buf2[16];  /* revstamp */
  700.    char buf3[16];  /* OS */
  701.    char buf4[16];  /* Date */
  702. /*   char buf5[16];  /* Time */
  703.  
  704. /* format "with" name strings */
  705.  
  706. #ifdef AMIGA
  707. # ifdef __SASC
  708.    strcpy(buf1,"SAS/C ");
  709. # else
  710. #  ifdef LATTICE
  711.     strcpy(buf1,"Lattice C ");
  712. #  else
  713. #   ifdef AZTEC_C
  714.      strcpy(buf1,"Manx Aztec C ");
  715. #   else
  716.      strcpy(buf1,"UNKNOWN ");
  717. #   endif
  718. #  endif
  719. # endif
  720. /* "under" */
  721.   sprintf(buf3,"AmigaDOS v%d",WBversion);
  722. #else
  723.   strcpy(buf1,"Unknown compiler ");
  724.   strcpy(buf3,"Unknown OS");
  725. #endif
  726.  
  727. /* Define revision, date, and time strings.  
  728.  * NOTE:  Do not calculate run time, be sure to use time compiled.
  729.  * Pass these strings via your makefile if undefined.
  730.  */
  731.  
  732. #if defined(__VERSION__) && defined(__REVISION__)
  733.   sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
  734. #else
  735. # ifdef __VERSION__
  736.   sprintf(buf2,"version %d",__VERSION__);
  737. # else
  738.   sprintf(buf2,"unknown version");
  739. # endif
  740. #endif
  741.  
  742. #ifdef __DATE__
  743.   sprintf(buf4," on %s",__DATE__);
  744. #else
  745.   strcpy(buf4," unknown date");
  746. #endif
  747.  
  748. /******
  749. #ifdef __TIME__
  750.   sprintf(buf5," at %s",__TIME__);
  751. #else
  752.   strcpy(buf5," unknown time");
  753. #endif
  754. ******/
  755.  
  756. /* Print strings using "CompiledWith" mask defined in unzip.c (used by all).
  757.  *  ("Compiled with %s%s under %s%s%s%s.")
  758.  */
  759.  
  760.    printf(LoadFarString(CompiledWith),
  761.      buf1,
  762.      buf2, 
  763.      buf3,
  764.      buf4,
  765.      /* buf5, */ "",
  766.      "" );  /* buf6 not used */
  767.  
  768. } /* end function version() */
  769.  
  770. #endif /* !SFX */
  771.