home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip540.zip / flexos / flexos.c < prev    next >
C/C++ Source or Header  |  1998-06-09  |  33KB  |  862 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   flexos.c
  4.  
  5.   FlexOS-specific routines for use with Info-ZIP's UnZip 5.2 and later.
  6.  
  7.   Based upon the MSDOS version of this file (msdos/msdos.c)
  8.  
  9.   Contains:  do_wild()
  10.              mapattr()
  11.              mapname()
  12.              map2fat()
  13.              checkdir()
  14.              close_outfile()
  15.              dateformat()
  16.              version()
  17.              _wildarg()
  18.  
  19.   ---------------------------------------------------------------------------*/
  20.  
  21.  
  22.  
  23. #define UNZIP_INTERNAL
  24. #include "unzip.h"
  25.  
  26. #include <flexif.h>
  27.  
  28. /* The following should really be a static declaration,  but the compiler
  29.    complains (crappy compiler can't cope with a static forward declaration).
  30.  */
  31. extern void map2fat OF((char *pathcomp, char *last_dot));
  32.  
  33. static int created_dir;        /* used by mapname(), checkdir() */
  34. static int renamed_fullpath;   /* ditto */
  35.  
  36. /*****************************/
  37. /*  Strings used in flexos.c  */
  38. /*****************************/
  39.  
  40. #ifndef SFX
  41.   static char Far CantAllocateWildcard[] =
  42.     "warning:  cannot allocate wildcard buffers\n";
  43. #endif
  44. static char Far Creating[] = "   creating: %s\n";
  45. static char Far ConversionFailed[] = "mapname:  conversion of %s failed\n";
  46. static char Far PathTooLong[] = "checkdir error:  path too long: %s\n";
  47. static char Far CantCreateDir[] = "checkdir error:  cannot create %s\n\
  48.                  unable to process %s.\n";
  49. static char Far DirIsntDirectory[] =
  50.   "checkdir error:  %s exists but is not directory\n\
  51.                  unable to process %s.\n";
  52. static char Far PathTooLongTrunc[] =
  53.   "checkdir warning:  path too long; truncating\n                   %s\n\
  54.                 -> %s\n";
  55. #if (!defined(SFX) || defined(SFX_EXDIR))
  56.    static char Far CantCreateExtractDir[] =
  57.      "checkdir:  cannot create extraction directory: %s\n";
  58. #endif
  59.  
  60. #include <dirent.h>
  61.  
  62. #ifndef SFX
  63.  
  64. /************************/
  65. /*  Function do_wild()  */   /* identical to OS/2 version */
  66. /************************/
  67.  
  68. char *do_wild(__G__ wildspec)
  69.     __GDEF
  70.     char *wildspec;          /* only used first time on a given dir */
  71. {
  72.     static DIR *dir = (DIR *)NULL;
  73.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  74.     static int firstcall=TRUE, have_dirname, dirnamelen;
  75.     char *fnamestart;
  76.     struct dirent *file;
  77.  
  78.  
  79.     /* Even when we're just returning wildspec, we *always* do so in
  80.      * matchname[]--calling routine is allowed to append four characters
  81.      * to the returned string, and wildspec may be a pointer to argv[].
  82.      */
  83.     if (firstcall) {        /* first call:  must initialize everything */
  84.         firstcall = FALSE;
  85.  
  86.         if (!iswild(wildspec)) {
  87.             strcpy(matchname, wildspec);
  88.             have_dirname = FALSE;
  89.             dir = NULL;
  90.             return matchname;
  91.         }
  92.  
  93.         /* break the wildspec into a directory part and a wildcard filename */
  94.         if ((wildname = strrchr(wildspec, '/')) == (char *)NULL &&
  95.             (wildname = strrchr(wildspec, ':')) == (char *)NULL) {
  96.             dirname = ".";
  97.             dirnamelen = 1;
  98.             have_dirname = FALSE;
  99.             wildname = wildspec;
  100.         } else {
  101.             ++wildname;     /* point at character after '/' or ':' */
  102.             dirnamelen = (int)(wildname - wildspec);
  103.             if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
  104.                 Info(slide, 1, ((char *)slide,
  105.                   LoadFarString(CantAllocateWildcard)));
  106.                 strcpy(matchname, wildspec);
  107.                 return matchname;   /* but maybe filespec was not a wildcard */
  108.             }
  109. /* GRR:  cannot strip trailing char for opendir since might be "d:/" or "d:"
  110.  *       (would have to check for "./" at end--let opendir handle it instead) */
  111.             strncpy(dirname, wildspec, dirnamelen);
  112.             dirname[dirnamelen] = '\0';       /* terminate for strcpy below */
  113.             have_dirname = TRUE;
  114.         }
  115.         Trace((stderr, "do_wild:  dirname = [%s]\n", dirname));
  116.  
  117.         if ((dir = opendir(dirname)) != (DIR *)NULL) {
  118.             if (have_dirname) {
  119.                 strcpy(matchname, dirname);
  120.                 fnamestart = matchname + dirnamelen;
  121.             } else
  122.                 fnamestart = matchname;
  123.             while ((file = readdir(dir)) != (struct dirent *)NULL) {
  124.                 Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  125.                 strcpy(fnamestart, file->d_name);
  126.                 if (strrchr(fnamestart, '.') == (char *)NULL)
  127.                     strcat(fnamestart, ".");
  128.                 if (match(fnamestart, wildname, 1) &&  /* 1 == ignore case */
  129.                     /* skip "." and ".." directory entries */
  130.                     strcmp(fnamestart, ".") && strcmp(fnamestart, "..")) {
  131.                     Trace((stderr, "do_wild:  match() succeeds\n"));
  132.                     /* remove trailing dot */
  133.                     fnamestart += strlen(fnamestart) - 1;
  134.                     if (*fnamestart == '.')
  135.                         *fnamestart = '\0';
  136.                     return matchname;
  137.                 }
  138.             }
  139.             /* if we get to here directory is exhausted, so close it */
  140.             closedir(dir);
  141.             dir = (DIR *)NULL;
  142.         }
  143. #ifdef DEBUG
  144.         else {
  145.             Trace((stderr, "do_wild:  opendir(%s) returns NULL\n", dirname));
  146.         }
  147. #endif /* DEBUG */
  148.  
  149.         /* return the raw wildspec in case that works (e.g., directory not
  150.          * searchable, but filespec was not wild and file is readable) */
  151.         strcpy(matchname, wildspec);
  152.         return matchname;
  153.     }
  154.  
  155.     /* last time through, might have failed opendir but returned raw wildspec */
  156.     if (dir == (DIR *)NULL) {
  157.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  158.         if (have_dirname)
  159.             free(dirname);
  160.         return (char *)NULL;
  161.     }
  162.  
  163.     /* If we've gotten this far, we've read and matched at least one entry
  164.      * successfully (in a previous call), so dirname has been copied into
  165.      * matchname already.
  166.      */
  167.     if (have_dirname) {
  168.         /* strcpy(matchname, dirname); */
  169.         fnamestart = matchname + dirnamelen;
  170.     } else
  171.         fnamestart = matchname;
  172.     while ((file = readdir(dir)) != (struct dirent *)NULL) {
  173.         Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
  174.         strcpy(fnamestart, file->d_name);
  175.         if (strrchr(fnamestart, '.') == (char *)NULL)
  176.             strcat(fnamestart, ".");
  177.         if (match(fnamestart, wildname, 1)) {   /* 1 == ignore case */
  178.             Trace((stderr, "do_wild:  match() succeeds\n"));
  179.             /* remove trailing dot */
  180.             fnamestart += strlen(fnamestart) - 1;
  181.             if (*fnamestart == '.')
  182.                 *fnamestart = '\0';
  183.             return matchname;
  184.         }
  185.     }
  186.  
  187.     closedir(dir);     /* have read at least one dir entry; nothing left */
  188.     dir = (DIR *)NULL;
  189.     firstcall = TRUE;  /* reset for new wildspec */
  190.     if (have_dirname)
  191.         free(dirname);
  192.     return (char *)NULL;
  193.  
  194. } /* end function do_wild() */
  195.  
  196. #endif /* !SFX */
  197.  
  198.  
  199.  
  200. /**********************/
  201. /* Function mapattr() */
  202. /**********************/
  203.  
  204. int mapattr(__G)
  205.     __GDEF
  206. {
  207.     /* set archive bit (file is not backed up): */
  208.     G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes & 7) | 32;
  209.     return 0;
  210. }
  211.  
  212.  
  213.  
  214. /************************/
  215. /*  Function mapname()  */
  216. /************************/
  217.  
  218.                              /* return 0 if no error, 1 if caution (filename */
  219. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  220.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  221.     int renamed;             /*  or 10 if out of memory (skip file) */
  222. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  223.     char pathcomp[FILNAMSIZ];      /* path-component buffer */
  224.     char *pp, *cp=(char *)NULL;    /* character pointers */
  225.     char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
  226.     char *last_dot=(char *)NULL;   /* last dot not converted to underscore */
  227.     int dotname = FALSE;           /* path component begins with dot? */
  228.     int error = 0;
  229.     register unsigned workch;      /* hold the character being tested */
  230.  
  231.  
  232.     if (G.pInfo->vollabel)
  233.         return IZ_VOL_LABEL;    /* Cannot set disk volume labels in FlexOS */
  234.  
  235. /*---------------------------------------------------------------------------
  236.     Initialize various pointers and counters and stuff.
  237.   ---------------------------------------------------------------------------*/
  238.  
  239.     /* can create path as long as not just freshening, or if user told us */
  240.     G.create_dirs = (!uO.fflag || renamed);
  241.  
  242.     created_dir = FALSE;        /* not yet */
  243.     renamed_fullpath = FALSE;
  244.  
  245.     if (renamed) {
  246.         cp = G.filename - 1;    /* point to beginning of renamed name... */
  247.         while (*++cp)
  248.             if (*cp == '\\')    /* convert backslashes to forward */
  249.                 *cp = '/';
  250.         cp = G.filename;
  251.         /* use temporary rootpath if user gave full pathname */
  252.         if (G.filename[0] == '/') {
  253.             renamed_fullpath = TRUE;
  254.             pathcomp[0] = '/';  /* copy the '/' and terminate */
  255.             pathcomp[1] = '\0';
  256.             ++cp;
  257.         } else if (isalpha(G.filename[0]) && G.filename[1] == ':') {
  258.             renamed_fullpath = TRUE;
  259.             pp = pathcomp;
  260.             *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
  261.             *pp++ = *cp++;
  262.             if (*cp == '/')
  263.                 *pp++ = *cp++;  /* otherwise add "./"? */
  264.             *pp = '\0';
  265.         }
  266.     }
  267.  
  268.     /* pathcomp is ignored unless renamed_fullpath is TRUE: */
  269.     if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* initialize path buf */
  270.         return error;           /* ...unless no mem or vol label on hard disk */
  271.  
  272.     *pathcomp = '\0';           /* initialize translation buffer */
  273.     pp = pathcomp;              /* point to translation buffer */
  274.     if (!renamed) {             /* cp already set if renamed */
  275.         if (uO.jflag)           /* junking directories */
  276.             cp = (char *)strrchr(G.filename, '/');
  277.         if (cp == (char *)NULL) /* no '/' or not junking dirs */
  278.             cp = G.filename;    /* point to internal zipfile-member pathname */
  279.         else
  280.             ++cp;               /* point to start of last component of path */
  281.     }
  282.  
  283. /*---------------------------------------------------------------------------
  284.     Begin main loop through characters in filename.
  285.   ---------------------------------------------------------------------------*/
  286.  
  287.     while ((workch = (uch)*cp++) != 0) {
  288.  
  289.         switch (workch) {
  290.             case '/':             /* can assume -j flag not given */
  291.                 *pp = '\0';
  292.                 map2fat(pathcomp, last_dot);   /* 8.3 truncation (in place) */
  293.                 last_dot = (char *)NULL;
  294.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  295.                     return error;
  296.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  297.                 lastsemi = (char *)NULL; /* leave directory semi-colons alone */
  298.                 break;
  299.  
  300.             /* drive names are not stored in zipfile, so no colons allowed;
  301.              *  no brackets or most other punctuation either (all of which
  302.              *  can appear in Unix-created archives; backslash is particularly
  303.              *  bad unless all necessary directories exist) */
  304.             case '[':          /* these punctuation characters forbidden */
  305.             case ']':          /*  only on plain FAT file systems */
  306.             case '+':
  307.             case ',':
  308.             case '=':
  309.             case ':':           /* special shell characters of command.com */
  310.             case '\\':          /*  (device and directory limiters, wildcard */
  311.             case '"':           /*  characters, stdin/stdout redirection and */
  312.             case '<':           /*  pipe indicators and the quote sign) are */
  313.             case '>':           /*  never allowed in filenames on (V)FAT */
  314.             case '|':
  315.             case '*':
  316.             case '?':
  317.                 *pp++ = '_';
  318.                 break;
  319.  
  320.             case '.':
  321.                 if (pp == pathcomp) {     /* nothing appended yet... */
  322.                     if (*cp == '/') {     /* don't bother appending a "./" */
  323.                         ++cp;             /*  component to the path:  skip */
  324.                         break;            /*  to next char after the '/' */
  325.                     } else if (*cp == '.' && cp[1] == '/') {   /* "../" */
  326.                         *pp++ = '.';      /* add first dot, unchanged... */
  327.                         ++cp;             /* skip second dot, since it will */
  328.                     } else {              /*  be "added" at end of if-block */
  329.                         *pp++ = '_';      /* FAT doesn't allow null filename */
  330.                         dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
  331.                     }                     /*  (extra '_' now, "dot" below) */
  332.                 } else if (dotname) {     /* found a second dot, but still */
  333.                     dotname = FALSE;      /*  have extra leading underscore: */
  334.                     *pp = '\0';           /*  remove it by shifting chars */
  335.                     pp = pathcomp + 1;    /*  left one space (e.g., .p1.p2: */
  336.                     while (pp[1]) {       /*  __p1 -> _p1_p2 -> _p1.p2 when */
  337.                         *pp = pp[1];      /*  finished) [opt.:  since first */
  338.                         ++pp;             /*  two chars are same, can start */
  339.                     }                     /*  shifting at second position] */
  340.                 }
  341.                 last_dot = pp;    /* point at last dot so far... */
  342.                 *pp++ = '_';      /* convert dot to underscore for now */
  343.                 break;
  344.  
  345.             case ';':             /* start of VMS version? */
  346.                 lastsemi = pp;
  347.                 break;
  348.  
  349.             case ' ':                      /* change spaces to underscores */
  350.                 if (uO.sflag)              /*  only if requested */
  351.                     *pp++ = '_';
  352.                 else
  353.                     *pp++ = (char)workch;
  354.                 break;
  355.  
  356.             default:
  357.                 /* allow ASCII 255 and European characters in filenames: */
  358.                 if (isprint(workch) || workch >= 127)
  359.                     *pp++ = (char)workch;
  360.  
  361.         } /* end switch */
  362.     } /* end while loop */
  363.  
  364.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  365.  
  366.     /* if not saving them, remove VMS version numbers (appended ";###") */
  367.     if (!uO.V_flag && lastsemi) {
  368.         pp = lastsemi;            /* semi-colon was omitted:  expect all #'s */
  369.         while (isdigit((uch)(*pp)))
  370.             ++pp;
  371.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  372.             *lastsemi = '\0';
  373.     }
  374.  
  375.     map2fat(pathcomp, last_dot);  /* 8.3 truncation (in place) */
  376.  
  377. /*---------------------------------------------------------------------------
  378.     Report if directory was created (and no file to create:  filename ended
  379.     in '/'), check name to be sure it exists, and combine path and name be-
  380.     fore exiting.
  381.   ---------------------------------------------------------------------------*/
  382.  
  383.     if (G.filename[strlen(G.filename) - 1] == '/') {
  384.         checkdir(__G__ G.filename, GETPATH);
  385.         if (created_dir) {
  386.             if (QCOND2) {
  387.                 Info(slide, 0, ((char *)slide, LoadFarString(Creating),
  388.                   FnFilter1(G.filename)));
  389.             }
  390.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  391.         }
  392.         return 2;   /* dir existed already; don't look for data to extract */
  393.     }
  394.  
  395.     if (*pathcomp == '\0') {
  396.         Info(slide, 1, ((char *)slide, LoadFarString(ConversionFailed),
  397.           FnFilter1(G.filename)));
  398.         return 3;
  399.     }
  400.  
  401.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  402.     checkdir(__G__ G.filename, GETPATH);
  403.  
  404.     return error;
  405.  
  406. } /* end function mapname() */
  407.  
  408.  
  409.  
  410. /**********************/
  411. /* Function map2fat() */
  412. /**********************/
  413.  
  414. static void map2fat(pathcomp, last_dot)
  415.     char *pathcomp, *last_dot;
  416. {
  417.     char *pEnd = pathcomp + strlen(pathcomp);
  418.  
  419. /*---------------------------------------------------------------------------
  420.     Case 1:  filename has no dot, so figure out if we should add one.  Note
  421.     that the algorithm does not try to get too fancy:  if there are no dots
  422.     already, the name either gets truncated at 8 characters or the last un-
  423.     derscore is converted to a dot (only if more characters are saved that
  424.     way).  In no case is a dot inserted between existing characters.
  425.  
  426.               GRR:  have problem if filename is volume label??
  427.  
  428.   ---------------------------------------------------------------------------*/
  429.  
  430.     /* pEnd = pathcomp + strlen(pathcomp); */
  431.     if (last_dot == (char *)NULL) {   /* no dots:  check for underscores... */
  432.         char *plu = strrchr(pathcomp, '_');   /* pointer to last underscore */
  433.  
  434.         if (plu == (char *)NULL) {  /* no dots, no underscores:  truncate at */
  435.             if (pEnd > pathcomp+8)  /* 8 chars (could insert '.' and keep 11) */
  436.                 *(pEnd = pathcomp+8) = '\0';
  437.         } else if (MIN(plu - pathcomp, 8) + MIN(pEnd - plu - 1, 3) > 8) {
  438.             last_dot = plu;       /* be lazy:  drop through to next if-block */
  439.         } else if ((pEnd - pathcomp) > 8)    /* more fits into just basename */
  440.             pathcomp[8] = '\0';    /* than if convert last underscore to dot */
  441.         /* else whole thing fits into 8 chars or less:  no change */
  442.     }
  443.  
  444. /*---------------------------------------------------------------------------
  445.     Case 2:  filename has dot in it, so truncate first half at 8 chars (shift
  446.     extension if necessary) and second half at three.
  447.   ---------------------------------------------------------------------------*/
  448.  
  449.     if (last_dot != (char *)NULL) {   /* one dot (or two, in the case of */
  450.         *last_dot = '.';              /*  "..") is OK:  put it back in */
  451.  
  452.         if ((last_dot - pathcomp) > 8) {
  453.             char *p=last_dot, *q=pathcomp+8;
  454.             int i;
  455.  
  456.             for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
  457.                 *q++ = *p++;                   /*  shift extension left and */
  458.             *q = '\0';                         /*  truncate/terminate it */
  459.         } else if ((pEnd - last_dot) > 4)
  460.             last_dot[4] = '\0';                /* too many chars in extension */
  461.         /* else filename is fine as is:  no change */
  462.     }
  463. } /* end function map2fat() */
  464.  
  465.  
  466.  
  467. /***********************/
  468. /* Function checkdir() */
  469. /***********************/
  470.  
  471. int checkdir(__G__ pathcomp, flag)
  472.     __GDEF
  473.     char *pathcomp;
  474.     int flag;
  475. /*
  476.  * returns:  1 - (on APPEND_NAME) truncated filename
  477.  *           2 - path doesn't exist, not allowed to create
  478.  *           3 - path doesn't exist, tried to create and failed; or
  479.  *               path exists and is not a directory, but is supposed to be
  480.  *           4 - path is too long
  481.  *          10 - can't allocate memory for filename buffers
  482.  */
  483. {
  484.     static int rootlen = 0;   /* length of rootpath */
  485.     static char *rootpath;    /* user's "extract-to" directory */
  486.     static char *buildpath;   /* full path (so far) to extracted file */
  487.     static char *end;         /* pointer to end of buildpath ('\0') */
  488.  
  489. #   define FN_MASK   7
  490. #   define FUNCTION  (flag & FN_MASK)
  491.  
  492.  
  493.  
  494. /*---------------------------------------------------------------------------
  495.     APPEND_DIR:  append the path component to the path being built and check
  496.     for its existence.  If doesn't exist and we are creating directories, do
  497.     so for this one; else signal success or error as appropriate.
  498.   ---------------------------------------------------------------------------*/
  499.  
  500.     if (FUNCTION == APPEND_DIR) {
  501.         int too_long = FALSE;
  502.  
  503.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  504.         while ((*end = *pathcomp++) != '\0')
  505.             ++end;
  506.  
  507.         /* GRR:  could do better check, see if overrunning buffer as we go:
  508.          * check end-buildpath after each append, set warning variable if
  509.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  510.          * appending.  Clear variable when begin new path. */
  511.  
  512.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
  513.             too_long = TRUE;                /* check if extracting directory? */
  514.         if (stat(buildpath, &G.statbuf))    /* path doesn't exist */
  515.         {
  516.             if (!G.create_dirs) { /* told not to create (freshening) */
  517.                 free(buildpath);
  518.                 return 2;         /* path doesn't exist:  nothing to do */
  519.             }
  520.             if (too_long) {
  521.                 Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
  522.                   FnFilter1(buildpath)));
  523.                 free(buildpath);
  524.                 return 4;         /* no room for filenames:  fatal */
  525.             }
  526.             if (mkdir(buildpath, 0777) == -1) {   /* create the directory */
  527.                 Info(slide, 1, ((char *)slide, LoadFarString(CantCreateDir),
  528.                   FnFilter2(buildpath), FnFilter1(G.filename)));
  529.                 free(buildpath);
  530.                 return 3;      /* path didn't exist, tried to create, failed */
  531.             }
  532.             created_dir = TRUE;
  533.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  534.             Info(slide, 1, ((char *)slide, LoadFarString(DirIsntDirectory),
  535.               FnFilter2(buildpath), FnFilter1(G.filename)));
  536.             free(buildpath);
  537.             return 3;          /* path existed but wasn't dir */
  538.         }
  539.         if (too_long) {
  540.             Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
  541.               FnFilter1(buildpath)));
  542.             free(buildpath);
  543.             return 4;         /* no room for filenames:  fatal */
  544.         }
  545.         *end++ = '/';
  546.         *end = '\0';
  547.         Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
  548.         return 0;
  549.  
  550.     } /* end if (FUNCTION == APPEND_DIR) */
  551.  
  552. /*---------------------------------------------------------------------------
  553.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  554.     buildpath.
  555.   ---------------------------------------------------------------------------*/
  556.  
  557.     if (FUNCTION == GETPATH) {
  558.         strcpy(pathcomp, buildpath);
  559.         Trace((stderr, "getting and freeing path [%s]\n",
  560.           FnFilter1(pathcomp)));
  561.         free(buildpath);
  562.         buildpath = end = (char *)NULL;
  563.         return 0;
  564.     }
  565.  
  566. /*---------------------------------------------------------------------------
  567.     APPEND_NAME:  assume the path component is the filename; append it and
  568.     return without checking for existence.
  569.   ---------------------------------------------------------------------------*/
  570.  
  571.     if (FUNCTION == APPEND_NAME) {
  572.         Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
  573.         while ((*end = *pathcomp++) != '\0') {
  574.             ++end;
  575.             if ((end-buildpath) >= FILNAMSIZ) {
  576.                 *--end = '\0';
  577.                 Info(slide, 1, ((char *)slide, LoadFarString(PathTooLongTrunc),
  578.                   FnFilter1(G.filename), FnFilter2(buildpath)));
  579.                 return 1;   /* filename truncated */
  580.             }
  581.         }
  582.         Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
  583.         return 0;  /* could check for existence here, prompt for new name... */
  584.     }
  585.  
  586. /*---------------------------------------------------------------------------
  587.     INIT:  allocate and initialize buffer space for the file currently being
  588.     extracted.  If file was renamed with an absolute path, don't prepend the
  589.     extract-to path.
  590.   ---------------------------------------------------------------------------*/
  591.  
  592.     if (FUNCTION == INIT) {
  593.         Trace((stderr, "initializing buildpath to "));
  594.         /* allocate space for full filename, root path, and maybe "./" */
  595.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+3)) ==
  596.             (char *)NULL)
  597.             return 10;
  598.         if (renamed_fullpath) {   /* pathcomp = valid data */
  599.             end = buildpath;
  600.             while ((*end = *pathcomp++) != '\0')
  601.                 ++end;
  602.         } else if (rootlen > 0) {
  603.             strcpy(buildpath, rootpath);
  604.             end = buildpath + rootlen;
  605.         } else {
  606.             *buildpath = '\0';
  607.             end = buildpath;
  608.         }
  609.         Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
  610.         return 0;
  611.     }
  612.  
  613. /*---------------------------------------------------------------------------
  614.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  615.     sary; else assume it's a zipfile member and return.  This path segment
  616.     gets used in extracting all members from every zipfile specified on the
  617.     command line.  Note that under FlexOS, if a candidate extract-to
  618.     directory specification includes a drive letter (leading "x:"), it is
  619.     treated just as if it had a trailing '/'--that is, one directory level
  620.     will be created if the path doesn't exist, unless this is otherwise pro-
  621.     hibited (e.g., freshening).
  622.   ---------------------------------------------------------------------------*/
  623.  
  624. #if (!defined(SFX) || defined(SFX_EXDIR))
  625.     if (FUNCTION == ROOT) {
  626.         Trace((stderr, "initializing root path to [%s]\n",
  627.           FnFilter1(pathcomp)));
  628.         if (pathcomp == (char *)NULL) {
  629.             rootlen = 0;
  630.             return 0;
  631.         }
  632.         if ((rootlen = strlen(pathcomp)) > 0) {
  633.             int had_trailing_pathsep=FALSE, xtra=2;
  634.  
  635.             if (pathcomp[rootlen-1] == '/' || pathcomp[rootlen-1] == '\\') {
  636.                 pathcomp[--rootlen] = '\0';
  637.                 had_trailing_pathsep = TRUE;
  638.             }
  639.             if (pathcomp[rootlen-1] == ':') {
  640.                 if (!had_trailing_pathsep)   /* i.e., original wasn't "xxx:/" */
  641.                     xtra = 3;      /* room for '.' + '/' + 0 at end of "xxx:" */
  642.             } else if (rootlen > 0) {     /* need not check "xxx:." and "xxx:/" */
  643.                 if (stat(pathcomp,&G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
  644.                 {
  645.                     /* path does not exist */
  646.                     if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  647.                         rootlen = 0;
  648.                         return 2;   /* treat as stored file */
  649.                     }
  650. /* GRR:  scan for wildcard characters?  OS-dependent...  if find any, return 2:
  651.  * treat as stored file(s) */
  652.                     /* create directory (could add loop here to scan pathcomp
  653.                      * and create more than one level, but really necessary?) */
  654.                     if (mkdir(pathcomp, 0777) == -1) {
  655.                         Info(slide, 1, ((char *)slide,
  656.                           LoadFarString(CantCreateExtractDir),
  657.                           FnFilter1(pathcomp)));
  658.                         rootlen = 0;   /* path didn't exist, tried to create, */
  659.                         return 3;  /* failed:  file exists, or need 2+ levels */
  660.                     }
  661.                 }
  662.             }
  663.             if ((rootpath = (char *)malloc(rootlen+xtra)) == (char *)NULL) {
  664.                 rootlen = 0;
  665.                 return 10;
  666.             }
  667.             strcpy(rootpath, pathcomp);
  668.             if (xtra == 3)                  /* had just "x:", make "x:." */
  669.                 rootpath[rootlen++] = '.';
  670.             rootpath[rootlen++] = '/';
  671.             rootpath[rootlen] = '\0';
  672.             Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
  673.         }
  674.         return 0;
  675.     }
  676. #endif /* !SFX || SFX_EXDIR */
  677.  
  678. /*---------------------------------------------------------------------------
  679.     END:  free rootpath, immediately prior to program exit.
  680.   ---------------------------------------------------------------------------*/
  681.  
  682.     if (FUNCTION == END) {
  683.         Trace((stderr, "freeing rootpath\n"));
  684.         if (rootlen > 0) {
  685.             free(rootpath);
  686.             rootlen = 0;
  687.         }
  688.         return 0;
  689.     }
  690.  
  691.     return 99;  /* should never reach */
  692. }
  693.  
  694. /****************************/
  695. /* Function close_outfile() */
  696. /****************************/
  697.  
  698. void close_outfile(__G)
  699.     __GDEF
  700.  /*
  701.   * FlexOS VERSION
  702.   *
  703.   * Set the output file date/time stamp according to information from the
  704.   * zipfile directory record for this member, then close the file and set
  705.   * its permissions (archive, hidden, read-only, system).  Aside from closing
  706.   * the file, this routine is optional (but most compilers support it).
  707.   */
  708. {
  709.     DISKFILE    df;
  710.     LONG        fnum;
  711.  
  712.     struct {                /* date and time words */
  713.         union {             /* DOS file modification time word */
  714.             ush ztime;
  715.             struct {
  716.                 unsigned zt_se : 5;
  717.                 unsigned zt_mi : 6;
  718.                 unsigned zt_hr : 5;
  719.             } _tf;
  720.         } _t;
  721.         union {             /* DOS file modification date word */
  722.             ush zdate;
  723.             struct {
  724.                 unsigned zd_dy : 5;
  725.                 unsigned zd_mo : 4;
  726.                 unsigned zd_yr : 7;
  727.             } _df;
  728.         } _d;
  729.     } zt;
  730.  
  731. #ifdef USE_EF_UT_TIME
  732.     iztimes z_utime;
  733.     struct tm *t;
  734. #endif /* ?USE_EF_UT_TIME */
  735.  
  736.     fclose(G.outfile);
  737.  
  738.     if ((fnum = s_open(A_SET, G.filename)) < 0) {
  739.         Info(slide, 0x201, ((char *)slide,
  740.           "warning:  cannot open %s to set the time\n", G.filename));
  741.         return;
  742.     }
  743.  
  744.     if (s_get(T_FILE, fnum, &df, DSKFSIZE) < 0) {
  745.         s_close(0, fnum);
  746.  
  747.         Info(slide, 0x201, ((char *)slide,
  748.           "warning:  cannot get info on %s\n", G.filename));
  749.         return;
  750.     }
  751.  
  752. /*---------------------------------------------------------------------------
  753.     Copy and/or convert time and date variables, if necessary; then fill in
  754.     the file time/date.
  755.   ---------------------------------------------------------------------------*/
  756.  
  757. #ifdef USE_EF_UT_TIME
  758.     if (G.extra_field &&
  759. #ifdef IZ_CHECK_TZ
  760.         G.tz_is_valid &&
  761. #endif
  762.         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  763.          G.lrec.last_mod_dos_datetime, &z_utime, NULL) & EB_UT_FL_MTIME))
  764.     {
  765.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
  766.           z_utime.mtime));
  767.         t = localtime(&(z_utime.mtime));
  768.     } else
  769.         t = (struct tm *)NULL;
  770.     if (t != (struct tm *)NULL) {
  771.         if (t->tm_year < 80) {
  772.             df.df_modyear = 1980;
  773.             df.df_modmonth = 1;
  774.             df.df_modday = 1;
  775.             df.df_modhr = 0;
  776.             df.df_modmin = 0;
  777.             df.df_modsec = 0;
  778.         } else {
  779.             df.df_modyear = t->tm_year + 1900;
  780.             df.df_modmonth = t->tm_mon + 1;
  781.             df.df_modday = t->tm_mday;
  782.             df.df_modhr = t->tm_hour;
  783.             df.df_modmin = t->tm_min;
  784.             df.df_modsec = t->tm_sec;
  785.         }
  786.     } else
  787. #endif /* ?USE_EF_UX_TIME */
  788.     {
  789.         zt._t.ztime = (ush)(G.lrec.last_mod_dos_datetime) & 0xffff;
  790.         zt._d.zdate = (ush)(G.lrec.last_mod_dos_datetime >> 16);
  791.  
  792.         df.df_modyear = 1980 + zt._d._df.zd_yr;
  793.         df.df_modmonth = zt._d._df.zd_mo;
  794.         df.df_modday = zt._d._df.zd_dy;
  795.         df.df_modhr = zt._t._tf.zt_hr;
  796.         df.df_modmin = zt._t._tf.zt_mi;
  797.         df.df_modsec = zt._t._tf.zt_se << 1;
  798.     }
  799.  
  800. /*---------------------------------------------------------------------------
  801.     Fill in the file attributes.
  802.   ---------------------------------------------------------------------------*/
  803.  
  804.     df.df_attr1 = (UBYTE)G.pInfo->file_attr;
  805.  
  806. /*---------------------------------------------------------------------------
  807.     Now we try to set the attributes & date/time.
  808.   ---------------------------------------------------------------------------*/
  809.  
  810.     if (s_set(T_FILE, fnum, &df, DSKFSIZE) < 0)
  811.         Info(slide, 0x201, ((char *)slide,
  812.           "warning:  cannot set info for %s\n", G.filename));
  813.  
  814.     s_close(0, fnum);
  815. }
  816.  
  817. #ifndef SFX
  818.  
  819. /*************************/
  820. /* Function dateformat() */
  821. /*************************/
  822.  
  823. int dateformat()
  824. {
  825.     return DF_DMY;   /* default for systems without locale info */
  826. }
  827.  
  828. /************************/
  829. /*  Function version()  */
  830. /************************/
  831.  
  832. void version(__G)
  833.     __GDEF
  834. {
  835.     int len;
  836.  
  837.     len = sprintf((char *)slide, LoadFarString(CompiledWith),
  838.             "MetaWare High C",
  839.             "",
  840.             "FlexOS",
  841.             " (16-bit, big)",
  842.  
  843. #ifdef __DATE__
  844.       " on ", __DATE__
  845. #else
  846.       "", ""
  847. #endif
  848.     );
  849.  
  850.     (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  851. }
  852.  
  853. #endif /* !SFX */
  854.  
  855. /************************/
  856. /*  Function _wildarg() */
  857. /************************/
  858.  
  859. /* This prevents the PORTLIB startup code from preforming argument globbing */
  860.  
  861. _wildarg() {}
  862.