home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip532.zip / amiga / amiga.c next >
C/C++ Source or Header  |  1997-10-21  |  30KB  |  878 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.               close_outfile()
  13.               stamp_file()
  14.               _abort()                (Aztec C only)
  15.              [dateformat()]           (currently not used)
  16.               windowheight()
  17.               version()
  18.  
  19.   ------------------------------------------------------------------------*/
  20.  
  21.  
  22. #define UNZIP_INTERNAL
  23. #ifdef AZTEC_C
  24. #  define NO_FCNTL_H
  25. #endif
  26. #include "unzip.h"
  27.  
  28. /* Globular varibundus -- now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h */
  29.  
  30. /* static int created_dir; */      /* used in mapname(), checkdir() */
  31. /* static int renamed_fullpath; */ /* ditto */
  32.  
  33. #define PERMS   0777
  34. #define MKDIR(path,mode) mkdir(path)
  35.  
  36.  
  37. #ifndef S_ISCRIPT          /* not having one implies you have none */
  38. #  define S_IARCHIVE 0020  /* not modified since this bit was last set */
  39. #  define S_IREAD    0010  /* can be opened for reading */
  40. #  define S_IWRITE   0004  /* can be opened for writing */
  41. #  define S_IDELETE  0001  /* can be deleted */
  42. #endif /* S_ISCRIPT */
  43.  
  44. #ifndef S_IRWD
  45. #  define S_IRWD     0015  /* useful combo of Amiga privileges */
  46. #endif /* !S_IRWD */
  47.  
  48. #ifndef S_IHIDDEN
  49. #  define S_IHIDDEN  0200  /* hidden supported in future AmigaDOS (someday) */
  50. #endif /* !S_HIDDEN */
  51.  
  52. #ifndef SFX
  53. /* Make sure the number here matches version.h in the *EXACT* form */
  54. /* UZ_MAJORVER "." UZ_MINORVER PATCHLEVEL vvvv     No non-digits!  */
  55. const char version_id[]  = "\0$VER: UnZip 5.30 ("
  56. #include "env:VersionDate"
  57.    ")\r\n";
  58. #endif /* SFX */
  59.  
  60.  
  61. /**********************/
  62. /* Function mapattr() */
  63. /**********************/
  64.  
  65. int mapattr(__G)      /* Amiga version */
  66.     __GDEF
  67. {
  68.     ulg  tmp = G.crec.external_file_attributes;
  69.  
  70.  
  71.     /* Amiga attributes = hsparwed = hidden, script, pure, archive,
  72.      * read, write, execute, delete */
  73.  
  74.     switch (G.pInfo->hostnum) {
  75.         case AMIGA_:
  76.             if ((tmp & 1) == (tmp>>18 & 1))
  77.                 tmp ^= 0x000F0000;      /* PKAZip compatibility kluge */
  78.             /* turn off archive bit for restored Amiga files */
  79.             G.pInfo->file_attr = (unsigned)((tmp>>16) & (~S_IARCHIVE));
  80.             break;
  81.  
  82.         case UNIX_:   /* preserve read, write, execute:  use logical-OR of */
  83.         case VMS_:    /* user, group, and other; if writable, set delete bit */
  84.         case ACORN_:
  85.         case ATARI_:
  86.         case BEOS_:
  87.         case QDOS_:
  88.             tmp >>= 16;
  89.             tmp = (( tmp>>6 | tmp>>3 | tmp) & 07) << 1;
  90.             G.pInfo->file_attr = (unsigned)(tmp&S_IWRITE? tmp|S_IDELETE : tmp);
  91.             break;
  92.  
  93.         /* all other platforms:  assume read-only bit in DOS half of attribute
  94.          * word is set correctly ==> will become READ or READ+WRITE+DELETE */
  95.         case FS_FAT_:
  96.         case FS_HPFS_:  /* can add S_IHIDDEN check to MSDOS/OS2/NT eventually */
  97.         case FS_NTFS_:
  98.         case MAC_:
  99.         case TOPS20_:
  100.         default:
  101.             G.pInfo->file_attr = (unsigned)(tmp&1? S_IREAD : S_IRWD);
  102.             break;
  103.  
  104.     } /* end switch (host-OS-created-by) */
  105.  
  106.     G.pInfo->file_attr &= 0xff;   /* mask off all but lower eight bits */
  107.     return 0;
  108.  
  109. } /* end function mapattr() */
  110.  
  111.  
  112.  
  113.  
  114. /************************/
  115. /*  Function mapname()  */
  116. /************************/
  117.  
  118. int mapname(__G__ renamed)  /* return 0 if no error, 1 if caution (truncate), */
  119.     __GDEF                  /* 2 if warning (skip because dir doesn't exist), */
  120.     int renamed;            /* 3 if error (skip file), 10 if no memory (skip) */
  121. {                           /*  [also IZ_CREATED_DIR] */
  122.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  123.     char *pp, *cp=NULL;         /* character pointers */
  124.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  125.     int error = 0;
  126.     register unsigned workch;   /* hold the character being tested */
  127.  
  128.  
  129. /*---------------------------------------------------------------------------
  130.     Initialize various pointers and counters and stuff.
  131.   ---------------------------------------------------------------------------*/
  132.  
  133.     /* can create path as long as not just freshening, or if user told us */
  134.     G.create_dirs = (!G.fflag || renamed);
  135.  
  136.     G.created_dir = FALSE;      /* not yet */
  137.  
  138.     /* user gave full pathname:  don't prepend G.rootpath */
  139.     G.renamed_fullpath = (renamed && strchr(G.filename, ':'));
  140.  
  141.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  142.         return 10;              /* initialize path buffer, unless no memory */
  143.  
  144.     *pathcomp = '\0';           /* initialize translation buffer */
  145.     pp = pathcomp;              /* point to translation buffer */
  146.     if (G.jflag)                /* junking directories */
  147.         cp = (char *)strrchr(G.filename, '/');
  148.     if (cp == NULL)             /* no '/' or not junking dirs */
  149.         cp = G.filename;        /* point to internal zipfile-member pathname */
  150.     else
  151.         ++cp;                   /* point to start of last component of path */
  152.  
  153. /*---------------------------------------------------------------------------
  154.     Begin main loop through characters in filename.
  155.   ---------------------------------------------------------------------------*/
  156.  
  157.     while ((workch = (uch)*cp++) != 0) {
  158.  
  159.         switch (workch) {
  160.         case '/':             /* can assume -j flag not given */
  161.             *pp = '\0';
  162.             if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  163.                 return error;
  164.             pp = pathcomp;    /* reset conversion buffer for next piece */
  165.             lastsemi = NULL;  /* leave directory semi-colons alone */
  166.             break;
  167.  
  168.         case ';':             /* VMS version (or DEC-20 attrib?) */
  169.             lastsemi = pp;         /* keep for now; remove VMS ";##" */
  170.             *pp++ = (char)workch;  /*  later, if requested */
  171.             break;
  172.  
  173.         default:
  174.             /* allow ISO European characters in filenames: */
  175.             if (isprint(workch) || (160 <= workch && workch <= 255))
  176.                 *pp++ = (char)workch;
  177.         } /* end switch */
  178.     } /* end while loop */
  179.  
  180.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  181.  
  182.     /* if not saving them, remove with VMS version numbers (appended ";###") */
  183.     if (!G.V_flag && lastsemi) {
  184.         pp = lastsemi + 1;
  185.         while (isdigit((uch)(*pp)))
  186.             ++pp;
  187.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  188.             *lastsemi = '\0';
  189.     }
  190.  
  191. /*---------------------------------------------------------------------------
  192.     Report if directory was created (and no file to create:  filename ended
  193.     in '/'), check name to be sure it exists, and combine path and name be-
  194.     fore exiting.
  195.   ---------------------------------------------------------------------------*/
  196.  
  197.     if (G.filename[strlen(G.filename) - 1] == '/') {
  198.         checkdir(__G__ G.filename, GETPATH);
  199.         if (G.created_dir) {
  200.             if (QCOND2) {
  201.                 Info(slide, 0, ((char *)slide, "   creating: %s\n",
  202.                   G.filename));
  203.             }
  204.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  205.         }
  206.         return 2;   /* dir existed already; don't look for data to extract */
  207.     }
  208.  
  209.     if (*pathcomp == '\0') {
  210.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  211.              G.filename));
  212.         return 3;
  213.     }
  214.  
  215.     if ((error = checkdir(__G__ pathcomp, APPEND_NAME)) == 1) {
  216.         /* GRR:  OK if truncated here:  warn and continue */
  217.         /* (warn in checkdir?) */
  218.     }
  219.     checkdir(__G__ G.filename, GETPATH);
  220.  
  221.     return error;
  222.  
  223. } /* end function mapname() */
  224.  
  225.  
  226. static int ispattern(char *p)
  227. {
  228.     register char c;
  229.     while (c = *p++)
  230.         if (c == '\\') {
  231.             if (!*++p)
  232.                 return FALSE;
  233.         } else if (c == '?' || c == '*')
  234.             return TRUE;
  235.         else if (c == '[') {
  236.             for (;;) {
  237.                 if (!(c = *p++))
  238.                     return FALSE;
  239.                 else if (c == '\\') {
  240.                     if (!*++p)
  241.                         return FALSE;
  242.                 } else if (c == ']')
  243.                     return TRUE;
  244.             }
  245.         }
  246.     return FALSE;
  247. }
  248.  
  249. /**********************/
  250. /* Function do_wild() */
  251. /**********************/
  252.  
  253. char *do_wild(__G__ wildspec)
  254.     __GDEF
  255.     char *wildspec;         /* only used first time on a given dir */
  256. {
  257. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h:
  258.     static DIR *wild_dir = NULL;
  259.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  260.     static int notfirstcall = FALSE, dirnamelen;
  261. */
  262.     struct dirent *file;
  263.     BPTR lok = 0;
  264.     /* Even when we're just returning wildspec, we *always* do so in
  265.      * matchname[]--calling routine is allowed to append four characters
  266.      * to the returned string, and wildspec may be a pointer to argv[].
  267.      */
  268.     if (!G.notfirstcall) {      /* first call:  must initialize everything */
  269.         G.notfirstcall = TRUE;
  270.         /* avoid needless readdir() scans: */
  271.         if (!ispattern(wildspec) || (lok = Lock(wildspec, ACCESS_READ))) {
  272.             if (lok) UnLock(lok);       /* ^^ we ignore wildcard chars if */
  273.             G.dirnamelen = 0;           /* the name matches a real file   */
  274.             strcpy(G.matchname, wildspec);
  275.             return G.matchname;
  276.         }
  277.  
  278.         /* break the wildspec into a directory part and a wildcard filename */
  279.         if ((G.wildname = strrchr(wildspec, '/')) == NULL
  280.                         && (G.wildname = strrchr(wildspec, ':')) == NULL) {
  281.             G.dirname = "";             /* current dir */
  282.             G.dirnamelen = 0;
  283.             G.wildname = wildspec;
  284.         } else {
  285.             ++G.wildname;     /* point at character after '/' or ':' */
  286.             G.dirnamelen = G.wildname - wildspec;
  287.             if ((G.dirname = (char *)malloc(G.dirnamelen+1)) == NULL) {
  288.                 Info(slide, 1, ((char *)slide,
  289.                      "warning:  cannot allocate wildcard buffers\n"));
  290.                 strcpy(G.matchname, wildspec);
  291.                 return G.matchname; /* but maybe filespec was not a wildcard */
  292.             }
  293.             strncpy(G.dirname, wildspec, G.dirnamelen);
  294.             G.dirname[G.dirnamelen] = 0;
  295.         }
  296.  
  297.         if ((G.wild_dir = opendir(G.dirname)) != NULL) {
  298.             while ((file = readdir(G.wild_dir)) != NULL) {
  299.                 if (match(file->d_name, G.wildname, 1)) {  /* ignore case */
  300.                     strcpy(G.matchname, G.dirname);
  301.                     strcpy(G.matchname + G.dirnamelen, file->d_name);
  302.                     return G.matchname;
  303.                 }
  304.             }
  305.             /* if we get to here directory is exhausted, so close it */
  306.             closedir(G.wild_dir);
  307.             G.wild_dir = NULL;
  308.         }
  309.  
  310.         /* return the raw wildspec in case that works (e.g., directory not
  311.          * searchable, but filespec was not wild and file is readable) */
  312.         strcpy(G.matchname, wildspec);
  313.         return G.matchname;
  314.     }
  315.  
  316.     /* last time through, might have failed opendir but returned raw wildspec */
  317.     if (G.wild_dir == NULL) {
  318.         G.notfirstcall = FALSE;    /* nothing left to try -- reset */
  319.         if (G.dirnamelen > 0)
  320.             free(G.dirname);
  321.         return (char *)NULL;
  322.     }
  323.  
  324.     /* If we've gotten this far, we've read and matched at least one entry
  325.      * successfully (in a previous call), so dirname has been copied into
  326.      * matchname already.
  327.      */
  328.     while ((file = readdir(G.wild_dir)) != NULL)
  329.         if (match(file->d_name, G.wildname, 1)) {   /* 1 == ignore case */
  330.             /* strcpy(G.matchname, dirname); */
  331.             strcpy(G.matchname + G.dirnamelen, file->d_name);
  332.             return G.matchname;
  333.         }
  334.  
  335.     closedir(G.wild_dir);  /* have read at least one dir entry; nothing left */
  336.     G.wild_dir = NULL;
  337.     G.notfirstcall = FALSE;  /* reset for new wildspec */
  338.     if (G.dirnamelen > 0)
  339.         free(G.dirname);
  340.     return (char *)NULL;
  341.  
  342. } /* end function do_wild() */
  343.  
  344.  
  345.  
  346. /***********************/
  347. /* Function checkdir() */
  348. /***********************/
  349.  
  350. int checkdir(__G__ pathcomp, flag)
  351.     __GDEF
  352.     char *pathcomp;
  353.     int flag;
  354. /*
  355.  * returns:  1 - (on APPEND_xxx) truncated path component
  356.  *           2 - path doesn't exist, not allowed to create
  357.  *           3 - path doesn't exist, tried to create and failed; or
  358.  *               path exists and is not a directory, but is supposed to be
  359.  *           4 - path is too long
  360.  *          10 - can't allocate memory for filename buffers
  361.  */
  362. {
  363. /* these statics are now declared in SYSTEM_SPECIFIC_GLOBALS in amiga.h: */
  364. /*  static int rootlen = 0; */   /* length of rootpath */
  365. /*  static char *rootpath;  */   /* user's "extract-to" directory */
  366. /*  static char *buildpath; */   /* full path (so far) to extracted file */
  367. /*  static char *end;       */   /* pointer to end of buildpath ('\0') */
  368.  
  369. #   define FN_MASK   7
  370. #   define FUNCTION  (flag & FN_MASK)
  371.  
  372.  
  373.  
  374. /*---------------------------------------------------------------------------
  375.     APPEND_DIR:  append the path component to the path being built and check
  376.     for its existence.  If doesn't exist and we are creating directories, do
  377.     so for this one; else signal success or error as appropriate.
  378.   ---------------------------------------------------------------------------*/
  379.  
  380. /* GRR:  check path length after each segment:  warn about truncation */
  381.  
  382.     if (FUNCTION == APPEND_DIR) {
  383.         int too_long = FALSE;
  384.  
  385.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  386.         while ((*G.build_end = *pathcomp++))
  387.             ++G.build_end;
  388.         /* Truncate components over 30 chars? Nah, the filesystem handles it. */
  389.         if ((G.build_end-G.buildpath) > FILNAMSIZ-3)       /* room for "/a\0" */
  390.             too_long = TRUE;                /* check if extracting directory? */
  391.         if (stat(G.buildpath, &G.statbuf)) {  /* path doesn't exist */
  392.             if (!G.create_dirs) { /* told not to create (freshening) */
  393.                 free(G.buildpath);
  394.                 return 2;         /* path doesn't exist:  nothing to do */
  395.             }
  396.             if (too_long) {
  397.                 Info(slide, 1, ((char *)slide,
  398.                   "checkdir error:  path too long: %s\n", G.buildpath));
  399.                 free(G.buildpath);
  400.                 return 4;         /* no room for filenames:  fatal */
  401.             }
  402.             if (MKDIR(G.buildpath, 0777) == -1) {   /* create the directory */
  403.                 Info(slide, 1, ((char *)slide,
  404.                  "checkdir error:  cannot create %s\n\
  405.                  unable to process %s.\n", G.buildpath, G.filename));
  406.                 free(G.buildpath);
  407.                 return 3;      /* path didn't exist, tried to create, failed */
  408.             }
  409.             G.created_dir = TRUE;
  410.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  411.             Info(slide, 1, ((char *)slide,
  412.                  "checkdir error:  %s exists but is not a directory\n\
  413.                  unable to process %s.\n", G.buildpath, G.filename));
  414.             free(G.buildpath);
  415.             return 3;          /* path existed but wasn't dir */
  416.         }
  417.         if (too_long) {
  418.             Info(slide, 1, ((char *)slide,
  419.                  "checkdir error:  path too long: %s\n", G.buildpath));
  420.             free(G.buildpath);
  421.             return 4;         /* no room for filenames:  fatal */
  422.         }
  423.         *G.build_end++ = '/';
  424.         *G.build_end = '\0';
  425.         Trace((stderr, "buildpath now = [%s]\n", G.buildpath));
  426.         return 0;
  427.  
  428.     } /* end if (FUNCTION == APPEND_DIR) */
  429.  
  430. /*---------------------------------------------------------------------------
  431.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  432.     G.buildpath.  Not our responsibility to worry whether pathcomp has room.
  433.   ---------------------------------------------------------------------------*/
  434.  
  435.     if (FUNCTION == GETPATH) {
  436.         strcpy(pathcomp, G.buildpath);
  437.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  438.         free(G.buildpath);
  439.         G.buildpath = G.build_end = NULL;
  440.         return 0;
  441.     }
  442.  
  443. /*---------------------------------------------------------------------------
  444.     APPEND_NAME:  assume the path component is the filename; append it and
  445.     return without checking for existence.
  446.   ---------------------------------------------------------------------------*/
  447.  
  448.     if (FUNCTION == APPEND_NAME) {
  449.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  450.         while ((*G.build_end = *pathcomp++)) {
  451.             ++G.build_end;
  452.             if ((G.build_end-G.buildpath) >= FILNAMSIZ) {
  453.                 *--G.build_end = '\0';
  454.                 Info(slide, 1, ((char *)slide,
  455.                    "checkdir warning:  path too long; truncating\n\
  456.                    %s\n                -> %s\n", G.filename, G.buildpath));
  457.                 return 1;   /* filename truncated */
  458.             }
  459.         }
  460.         Trace((stderr, "buildpath static now = [%s]\n", G.buildpath));
  461.         return 0;  /* could check for existence here, prompt for new name... */
  462.     }
  463.  
  464. /*---------------------------------------------------------------------------
  465.     INIT:  allocate and initialize buffer space for the file currently being
  466.     extracted.  If file was renamed with an absolute path, don't prepend the
  467.     extract-to path.
  468.   ---------------------------------------------------------------------------*/
  469.  
  470.     if (FUNCTION == INIT) {
  471.         Trace((stderr, "initializing buildpath static to "));
  472.         if ((G.buildpath = (char *)malloc(strlen(G.filename)+G.rootlen+1))
  473.               == NULL)
  474.             return 10;
  475.         if ((G.rootlen > 0) && !G.renamed_fullpath) {
  476.             strcpy(G.buildpath, G.rootpath);
  477.             G.build_end = G.buildpath + G.rootlen;
  478.         } else {
  479.             *G.buildpath = '\0';
  480.             G.build_end = G.buildpath;
  481.         }
  482.         Trace((stderr, "[%s]\n", G.buildpath));
  483.         return 0;
  484.     }
  485.  
  486. /*---------------------------------------------------------------------------
  487.     ROOT:  if appropriate, store the path in G.rootpath and create it if
  488.     necessary; else assume it's a zipfile member and return.  This path
  489.     segment gets used in extracting all members from every zipfile specified
  490.     on the command line.
  491.   ---------------------------------------------------------------------------*/
  492.  
  493. #if (!defined(SFX) || defined(SFX_EXDIR))
  494.     if (FUNCTION == ROOT) {
  495.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  496.         if (pathcomp == NULL) {
  497.             G.rootlen = 0;
  498.             return 0;
  499.         }
  500.         if ((G.rootlen = strlen(pathcomp)) > 0) {
  501.             if (stat(pathcomp, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode)) {
  502.                 /* path does not exist */
  503.                 if (!G.create_dirs) {
  504.                     G.rootlen = 0;
  505.                     return 2;   /* treat as stored file */
  506.                 }
  507.                 /* create the directory (could add loop here to scan pathcomp
  508.                  * and create more than one level, but why really necessary?) */
  509.                 if (MKDIR(pathcomp, 0777) == -1) {
  510.                     Info(slide, 1, ((char *)slide,
  511.                          "checkdir:  cannot create extraction directory: %s\n",
  512.                          pathcomp));
  513.                     G.rootlen = 0; /* path didn't exist, tried to create, and */
  514.                     return 3;  /* failed:  file exists, or 2+ levels required */
  515.                 }
  516.             }
  517.             if ((G.rootpath = (char *)malloc(G.rootlen+2)) == NULL) {
  518.                 G.rootlen = 0;
  519.                 return 10;
  520.             }
  521.             strcpy(G.rootpath, pathcomp);
  522.             if (G.rootpath[G.rootlen-1] != ':' && G.rootpath[G.rootlen-1] != '/')
  523.                 G.rootpath[G.rootlen++] = '/';
  524.             G.rootpath[G.rootlen] = '\0';
  525.             Trace((stderr, "rootpath now = [%s]\n", G.rootpath));
  526.         }
  527.         return 0;
  528.     }
  529. #endif /* !SFX || SFX_EXDIR */
  530.  
  531. /*---------------------------------------------------------------------------
  532.     END:  free G.rootpath, immediately prior to program exit.
  533.   ---------------------------------------------------------------------------*/
  534.  
  535.     if (FUNCTION == END) {
  536.         Trace((stderr, "freeing rootpath\n"));
  537.         if (G.rootlen > 0) {
  538.             free(G.rootpath);
  539.             rootlen = 0;
  540.         }
  541.         return 0;
  542.     }
  543.  
  544.     return 99;  /* should never reach */
  545.  
  546. } /* end function checkdir() */
  547.  
  548.  
  549. /**************************************/
  550. /* Function close_outfile() */
  551. /**************************************/
  552. /* this part differs slightly with Zip */
  553. /*-------------------------------------*/
  554.  
  555. void close_outfile(__G)
  556.     __GDEF
  557. {
  558.     time_t m_time;
  559. #ifdef USE_EF_UT_TIME
  560.     iztimes z_utime;
  561. #endif
  562.     LONG FileDate();
  563.  
  564.     if (G.cflag)                /* can't set time or filenote on stdout */
  565.         return;
  566.  
  567.   /* close the file *before* setting its time under AmigaDos */
  568.  
  569.     fclose(G.outfile);
  570.  
  571. #ifdef USE_EF_UT_TIME
  572.     if (G.extra_field &&
  573.         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  574.                           G.lrec.last_mod_file_date, &z_utime, NULL)
  575.          & EB_UT_FL_MTIME))
  576.     {
  577.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
  578.                          z_utime.mtime));
  579.         m_time = z_utime.mtime;
  580.     } else {
  581.         /* Convert DOS time to time_t format */
  582.         m_time = dos_to_unix_time(G.lrec.last_mod_file_date,
  583.                                   G.lrec.last_mod_file_time);
  584.     }
  585. #else /* !USE_EF_UT_TIME */
  586.     /* Convert DOS time to time_t format */
  587.     m_time = dos_to_unix_time(G.lrec.last_mod_file_date,
  588.                               G.lrec.last_mod_file_time);
  589. #endif /* ?USE_EF_UT_TIME */
  590.  
  591. #ifdef DEBUG
  592.     Info(slide, 1, ((char *)slide, "\nclose_outfile(): m_time=%s\n",
  593.                          ctime(&m_time)));
  594. #endif
  595.  
  596.     if (!FileDate(G.filename, &m_time))
  597.         Info(slide, 1, ((char *)slide,
  598.              "warning:  cannot set the time for %s\n", G.filename));
  599.  
  600.   /* set file perms after closing (not done at creation)--see mapattr() */
  601.  
  602.     chmod(G.filename, G.pInfo->file_attr);
  603.  
  604.   /* give it a filenote from the zipfile comment, if appropriate */
  605.  
  606.     if (G.N_flag && G.filenotes[G.filenote_slot]) {
  607.         SetComment(G.filename, G.filenotes[G.filenote_slot]);
  608.         free(G.filenotes[G.filenote_slot]);
  609.         G.filenotes[G.filenote_slot] = NULL;
  610.     }
  611.  
  612. } /* end function close_outfile() */
  613.  
  614.  
  615. #ifdef TIMESTAMP
  616.  
  617. /*************************/
  618. /* Function stamp_file() */
  619. /*************************/
  620.  
  621. int stamp_file(fname, modtime)
  622.     ZCONST char *fname;
  623.     time_t modtime;
  624. {
  625.     time_t m_time;
  626.     LONG FileDate();
  627.  
  628.     m_time = modtime;
  629.     return (FileDate((char *)fname, &m_time));
  630.  
  631. } /* end function stamp_file() */
  632.  
  633. #endif /* TIMESTAMP */
  634.  
  635.  
  636. /********************************************************************/
  637. /* Load filedate as a separate external file; it's used by Zip, too.*/
  638. /*                                                                  */
  639. #include "amiga/filedate.c"                                      /* */
  640. /*                                                                  */
  641. /********************************************************************/
  642.  
  643. /********************* do linewise with stat.c **********************/
  644.  
  645. #  include "amiga/stat.c"
  646. /* this is the exact same stat.c used by Zip */
  647.  
  648. #  include <stdio.h>
  649.  
  650. void _abort(void)               /* called when ^C is pressed */
  651. {
  652.     /* echon(); */
  653.     close_leftover_open_dirs();
  654.     fflush(stdout);
  655.     fputs("\n^C\n", stderr);
  656.     exit(1);
  657. }
  658.  
  659.  
  660. /**************************************************************/
  661. /* function windowheight() -- uses sendpkt() from filedate.c: */
  662. /**************************************************************/
  663.  
  664. #include <devices/conunit.h>
  665. #include <dos/dosextens.h>
  666. #include <exec/memory.h>
  667. #include <clib/exec_protos.h>
  668.  
  669. extern long sendpkt(struct MsgPort *pid, long action, long *args, long nargs);
  670.  
  671. int windowheight(BPTR fh)
  672. {
  673.     if (fh && IsInteractive(fh)) {
  674.         struct ConUnit *conunit = NULL;
  675.         void *conp = ((struct FileHandle *) (fh << 2))->fh_Type;
  676.         struct InfoData *ind = AllocMem(sizeof(*ind), MEMF_PUBLIC);
  677.         long argp = ((unsigned long) ind) >> 2;
  678.  
  679.         if (ind && conp && sendpkt(conp, ACTION_DISK_INFO, &argp, 1))
  680.             conunit = (void *) ((struct IOStdReq *) ind->id_InUse)->io_Unit;
  681.         if (ind)
  682.             FreeMem(ind, sizeof(*ind));
  683.         if (conunit)
  684.             return conunit->cu_YMax + 1;
  685.     }
  686.     return INT_MAX;
  687. }
  688.  
  689.  
  690. #ifdef AMIGA_VOLUME_LABELS
  691. /* This function is for if we someday implement -$ on the Amiga. */
  692. #  include <dos/dosextens.h>
  693. #  include <dos/filehandler.h>
  694. #  include <clib/macros.h>
  695.  
  696. BOOL is_floppy(char *path)
  697. {
  698.     BOOL okay = FALSE;
  699.     char devname[32], *debna;
  700.     ushort i;
  701.     BPTR lok = Lock(path, ACCESS_READ), pok;
  702.     struct FileSysStartupMsg *fart;
  703.     struct DeviceNode *debb, devlist = (void *) BADDR((struct DosInfo *)
  704.                                 BADDR(DOSBase->dl_Root->rn_Info)->di_DevInfo);
  705.     if (!lok)
  706.         return FALSE;                   /* should not happen */
  707.     if (pok = ParentDir(path)) {
  708.         UnLock(lok);
  709.         UnLock(pok);
  710.         return FALSE;                   /* it's not a root directory path */
  711.     }
  712.     Forbid();
  713.     for (debb = devlist; debb; debb = BADDR(debb->dn_Next))
  714.         if (debb->dn_Type == DLT_DEVICE && (debb->dn_Task == lick->fl_Task))
  715.             if (fart = BADDR(debb->dn_Startup)) {
  716.                 debna = (char *) BADDR(fart->fssm_Device) + 1;
  717.                 if ((i = debna[-1]) > 31) i = 30;
  718.                 strncpy(devname, debna, i);
  719.                 devname[i] = 0;
  720.                 okay = !strcmp(devname, "trackdisk.device")
  721.                                 || !strcmp(devname, "mfm.device")
  722.                                 || !strcmp(devname, "messydisk.device");
  723.                 break;  /* We only support obvious floppy drives, not tricky */
  724.             }           /* things like removable cartrige hard drives, or    */
  725.     Permit();           /* any unusual kind of floppy device driver.         */
  726.     return okay;
  727. }
  728. #endif /* AMIGA_VOLUME_LABELS */
  729.  
  730.  
  731. #ifndef SFX
  732.  
  733. # if 0
  734. /* As far as I can tell, all the locales AmigaDOS 2.1 knows about all */
  735. /* happen to use DF_MDY ordering, so there's no point in using this.  */
  736.  
  737. /*************************/
  738. /* Function dateformat() */
  739. /*************************/
  740.  
  741. #include <clib/locale_protos.h>
  742. #ifdef AZTEC_C
  743. #  include <pragmas/locale_lib.h>
  744. #endif
  745.  
  746. int dateformat()
  747. {
  748. /*---------------------------------------------------------------------------
  749.     For those operating systems which support it, this function returns a
  750.     value which tells how national convention says that numeric dates are
  751.     displayed.  Return values are DF_YMD, DF_DMY and DF_MDY (the meanings
  752.     should be fairly obvious).
  753.   ---------------------------------------------------------------------------*/
  754.     struct Library *LocaleBase;
  755.     struct Locale *ll;
  756.     int result = DF_MDY;        /* the default */
  757.  
  758.     if ((LocaleBase = OpenLibrary("locale.library", 0))) {
  759.         if (ll = OpenLocale(NULL)) {
  760.             uch *f = ll->loc_ShortDateFormat;
  761.             /* In this string, %y|%Y is year, %b|%B|%h|%m is month, */
  762.             /* %d|%e is day day, and %D|%x is short for mo/da/yr.   */
  763.             if (!strstr(f, "%D") && !strstr(f, "%x")) {
  764.                 uch *da, *mo, *yr;
  765.                 if (!(mo = strstr(f, "%b")) && !(mo = strstr(f, "%B"))
  766.                                     && !(mo = strstr(f, "%h")))
  767.                     mo = strstr(f, "%m");
  768.                 if (!(da = strstr(f, "%d")))
  769.                     da = strstr(f, "%e");
  770.                 if (!(yr = strstr(f, "%y")))
  771.                     yr = strstr(f, "%Y");
  772.                 if (yr && yr < mo)
  773.                     result = DF_YMD;
  774.                 else if (da && da < mo)
  775.                     result = DF_DMY;
  776.             }
  777.             CloseLocale(ll);
  778.         }
  779.         CloseLibrary(LocaleBase);
  780.     }
  781.     return result;
  782. }
  783.  
  784. # endif /* 0 */
  785.  
  786.  
  787. /************************/
  788. /*  Function version()  */
  789. /************************/
  790.  
  791.  
  792. /* NOTE:  the following include depends upon the environment
  793.  *        variable $Workbench to be set correctly.  (Set by
  794.  *        default, by kickstart during startup)
  795.  */
  796. int WBversion = (int)
  797. #include "ENV:Workbench"
  798. ;
  799.  
  800. void version(__G)
  801.    __GDEF
  802. {
  803. /* Define buffers. */
  804.  
  805.    char buf1[16];  /* compiler name */
  806.    char buf2[16];  /* revstamp */
  807.    char buf3[16];  /* OS */
  808.    char buf4[16];  /* Date */
  809. /*   char buf5[16];  /* Time */
  810.  
  811. /* format "with" name strings */
  812.  
  813. #ifdef AMIGA
  814. # ifdef __SASC
  815.    strcpy(buf1,"SAS/C ");
  816. # else
  817. #  ifdef LATTICE
  818.     strcpy(buf1,"Lattice C ");
  819. #  else
  820. #   ifdef AZTEC_C
  821.      strcpy(buf1,"Manx Aztec C ");
  822. #   else
  823.      strcpy(buf1,"UNKNOWN ");
  824. #   endif
  825. #  endif
  826. # endif
  827. /* "under" */
  828.   sprintf(buf3,"AmigaDOS v%d",WBversion);
  829. #else
  830.   strcpy(buf1,"Unknown compiler ");
  831.   strcpy(buf3,"Unknown OS");
  832. #endif
  833.  
  834. /* Define revision, date, and time strings.
  835.  * NOTE:  Do not calculate run time, be sure to use time compiled.
  836.  * Pass these strings via your makefile if undefined.
  837.  */
  838.  
  839. #if defined(__VERSION__) && defined(__REVISION__)
  840.   sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
  841. #else
  842. # ifdef __VERSION__
  843.   sprintf(buf2,"version %d",__VERSION__);
  844. # else
  845.   sprintf(buf2,"unknown version");
  846. # endif
  847. #endif
  848.  
  849. #ifdef __DATE__
  850.   sprintf(buf4," on %s",__DATE__);
  851. #else
  852.   strcpy(buf4," unknown date");
  853. #endif
  854.  
  855. /******
  856. #ifdef __TIME__
  857.   sprintf(buf5," at %s",__TIME__);
  858. #else
  859.   strcpy(buf5," unknown time");
  860. #endif
  861. ******/
  862.  
  863. /* Print strings using "CompiledWith" mask defined in unzip.c (used by all).
  864.  *  ("Compiled with %s%s under %s%s%s%s.")
  865.  */
  866.  
  867.    printf(LoadFarString(CompiledWith),
  868.      buf1,
  869.      buf2,
  870.      buf3,
  871.      buf4,
  872.      "",    /* buf5 not used */
  873.      "" );  /* buf6 not used */
  874.  
  875. } /* end function version() */
  876.  
  877. #endif /* !SFX */
  878.