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