amiga.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:33k
源码类别:

压缩解压

开发平台:

MultiPlatform

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