home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip512.zip / human68k / human68k.c < prev    next >
C/C++ Source or Header  |  1994-08-16  |  21KB  |  631 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   human68k.c
  4.  
  5.   Human68K-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.  
  7.   Contains:  do_wild()
  8.              mapattr()
  9.              mapname()
  10.              checkdir()
  11.              close_outfile()
  12.              version()
  13.              TwentyOne()
  14.              normalize_name()
  15.  
  16.   ---------------------------------------------------------------------------*/
  17.  
  18.  
  19. #include <dirent.h>
  20. #include <sys/dos.h>
  21. #include <sys/xunistd.h>
  22. #include <jstring.h>
  23. #include "unzip.h"
  24.  
  25.  
  26. static void normalize_name(char *);
  27.  
  28. static int created_dir;        /* used in mapname(), checkdir() */
  29. static int renamed_fullpath;   /* ditto */
  30.  
  31. /**********************/
  32. /* Function do_wild() */
  33. /**********************/
  34.  
  35. char *do_wild(wildspec)
  36.     char *wildspec;         /* only used first time on a given dir */
  37. {
  38.     static DIR *dir = NULL;
  39.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  40.     static int firstcall=TRUE, have_dirname, dirnamelen;
  41.     struct dirent *file;
  42.  
  43.  
  44.     /* Even when we're just returning wildspec, we *always* do so in
  45.      * matchname[]--calling routine is allowed to append four characters
  46.      * to the returned string, and wildspec may be a pointer to argv[].
  47.      */
  48.     if (firstcall) {        /* first call:  must initialize everything */
  49.         firstcall = FALSE;
  50.  
  51.         /* break the wildspec into a directory part and a wildcard filename */
  52.         if ((wildname = strrchr(wildspec, '/')) == NULL) {
  53.             dirname = ".";
  54.             dirnamelen = 1;
  55.             have_dirname = FALSE;
  56.             wildname = wildspec;
  57.         } else {
  58.             ++wildname;     /* point at character after '/' */
  59.             dirnamelen = wildname - wildspec;
  60.             if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  61.                 fprintf(stderr, "warning:  can't allocate wildcard buffers\n");
  62.                 strcpy(matchname, wildspec);
  63.                 return matchname;   /* but maybe filespec was not a wildcard */
  64.             }
  65.             strncpy(dirname, wildspec, dirnamelen);
  66.             dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  67.             have_dirname = TRUE;
  68.         }
  69.  
  70.         if ((dir = opendir(dirname)) != NULL) {
  71.             while ((file = readdir(dir)) != NULL) {
  72.                 if (file->d_name[0] == '.' && wildname[0] != '.')
  73.                     continue;  /* Unix:  '*' and '?' do not match leading dot */
  74.                 if (match(file->d_name, wildname, 0)) {  /* 0 == case sens. */
  75.                     if (have_dirname) {
  76.                         strcpy(matchname, dirname);
  77.                         strcpy(matchname+dirnamelen, file->d_name);
  78.                     } else
  79.                         strcpy(matchname, file->d_name);
  80.                     return matchname;
  81.                 }
  82.             }
  83.             /* if we get to here directory is exhausted, so close it */
  84.             closedir(dir);
  85.             dir = NULL;
  86.         }
  87.  
  88.         /* return the raw wildspec in case that works (e.g., directory not
  89.          * searchable, but filespec was not wild and file is readable) */
  90.         strcpy(matchname, wildspec);
  91.         return matchname;
  92.     }
  93.  
  94.     /* last time through, might have failed opendir but returned raw wildspec */
  95.     if (dir == NULL) {
  96.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  97.         if (have_dirname)
  98.             free(dirname);
  99.         return (char *)NULL;
  100.     }
  101.  
  102.     /* If we've gotten this far, we've read and matched at least one entry
  103.      * successfully (in a previous call), so dirname has been copied into
  104.      * matchname already.
  105.      */
  106.     while ((file = readdir(dir)) != NULL)
  107.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  108.             if (have_dirname) {
  109.                 /* strcpy(matchname, dirname); */
  110.                 strcpy(matchname+dirnamelen, file->d_name);
  111.             } else
  112.                 strcpy(matchname, file->d_name);
  113.             return matchname;
  114.         }
  115.  
  116.     closedir(dir);     /* have read at least one dir entry; nothing left */
  117.     dir = NULL;
  118.     firstcall = TRUE;  /* reset for new wildspec */
  119.     if (have_dirname)
  120.         free(dirname);
  121.     return (char *)NULL;
  122.  
  123. } /* end function do_wild() */
  124.  
  125.  
  126.  
  127.  
  128.  
  129. /**********************/
  130. /* Function mapattr() */
  131. /**********************/
  132.  
  133. int mapattr()
  134. {
  135.     ulg  tmp = crec.external_file_attributes;
  136.  
  137.     if (pInfo->hostnum == UNIX_ || pInfo->hostnum == VMS_)
  138.     pInfo->file_attr = _mode2dos(tmp >> 16);
  139.     else
  140.     /* set archive bit (file is not backed up): */
  141.     pInfo->file_attr = (unsigned)(crec.external_file_attributes|32) & 0xff;
  142.     return 0;
  143.  
  144. } /* end function mapattr() */
  145.  
  146.  
  147.  
  148.  
  149.  
  150. /**********************/
  151. /* Function mapname() */
  152. /**********************/
  153.  
  154. int mapname(renamed)  /* return 0 if no error, 1 if caution (filename trunc), */
  155.     int renamed;      /* 2 if warning (skip file because dir doesn't exist), */
  156. {                     /* 3 if error (skip file), 10 if no memory (skip file) */
  157.     char pathcomp[FILNAMSIZ];   /* path-component buffer */
  158.     char *pp, *cp=NULL;         /* character pointers */
  159.     char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
  160.     int quote = FALSE;          /* flags */
  161.     int error = 0;
  162.     register unsigned workch;   /* hold the character being tested */
  163.  
  164.  
  165. /*---------------------------------------------------------------------------
  166.     Initialize various pointers and counters and stuff.
  167.   ---------------------------------------------------------------------------*/
  168.  
  169.     if (pInfo->vollabel)
  170.         return IZ_VOL_LABEL;    /* can't set disk volume labels in Unix */
  171.  
  172.     /* can create path as long as not just freshening, or if user told us */
  173.     create_dirs = (!fflag || renamed);
  174.  
  175.     created_dir = FALSE;        /* not yet */
  176.  
  177.     /* user gave full pathname:  don't prepend rootpath */
  178.     renamed_fullpath = (renamed && (*filename == '/'));
  179.  
  180.     if (checkdir((char *)NULL, INIT) == 10)
  181.         return 10;              /* initialize path buffer, unless no memory */
  182.  
  183.     *pathcomp = '\0';           /* initialize translation buffer */
  184.     pp = pathcomp;              /* point to translation buffer */
  185.     if (jflag)                  /* junking directories */
  186.         cp = (char *)strrchr(filename, '/');
  187.     if (cp == NULL)             /* no '/' or not junking dirs */
  188.         cp = filename;          /* point to internal zipfile-member pathname */
  189.     else
  190.         ++cp;                   /* point to start of last component of path */
  191.  
  192. /*---------------------------------------------------------------------------
  193.     Begin main loop through characters in filename.
  194.   ---------------------------------------------------------------------------*/
  195.  
  196.     while ((workch = (uch)*cp++) != 0) {
  197.     if (iskanji(workch)) {
  198.         *pp++ = (char)workch;
  199.         quote = TRUE;
  200.     } else if (quote) {                 /* if character quoted, */
  201.             *pp++ = (char)workch;    /*  include it literally */
  202.             quote = FALSE;
  203.         } else
  204.             switch (workch) {
  205.             case '/':             /* can assume -j flag not given */
  206.                 *pp = '\0';
  207.                 if ((error = checkdir(pathcomp, APPEND_DIR)) > 1)
  208.                     return error;
  209.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  210.                 lastsemi = NULL;  /* leave directory semi-colons alone */
  211.                 break;
  212.  
  213.             case ';':             /* VMS version (or DEC-20 attrib?) */
  214.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  215.                 *pp++ = (char)workch;  /*  later, if requested */
  216.                 break;
  217.  
  218.             case '\026':          /* control-V quote for special chars */
  219.                 quote = TRUE;     /* set flag for next character */
  220.                 break;
  221.  
  222.             case ' ':             /* change spaces to underscore under */
  223.                 *pp++ = '_';      /*  MTS; leave as spaces under Unix */
  224.                 break;
  225.  
  226.             default:
  227.                 /* allow European characters in filenames: */
  228.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  229.                     *pp++ = (char)workch;
  230.             } /* end switch */
  231.  
  232.     } /* end while loop */
  233.  
  234.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  235.  
  236.     /* if not saving them, remove VMS version numbers (appended ";###") */
  237.     if (!V_flag && lastsemi) {
  238.         pp = lastsemi + 1;
  239.         while (isdigit((uch)(*pp)))
  240.             ++pp;
  241.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  242.             *lastsemi = '\0';
  243.     }
  244.  
  245. /*---------------------------------------------------------------------------
  246.     Report if directory was created (and no file to create:  filename ended
  247.     in '/'), check name to be sure it exists, and combine path and name be-
  248.     fore exiting.
  249.   ---------------------------------------------------------------------------*/
  250.  
  251.     if (filename[strlen(filename) - 1] == '/') {
  252.         checkdir(filename, GETPATH);
  253.         if (created_dir && QCOND2) {
  254.             fprintf(stdout, "   creating: %s\n", filename);
  255.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  256.         }
  257.         return 2;   /* dir existed already; don't look for data to extract */
  258.     }
  259.  
  260.     if (*pathcomp == '\0') {
  261.         fprintf(stderr, "mapname:  conversion of %s failed\n", filename);
  262.         return 3;
  263.     }
  264.  
  265.     checkdir(pathcomp, APPEND_NAME);   /* returns 1 if truncated:  care? */
  266.     checkdir(filename, GETPATH);
  267.  
  268.     return error;
  269.  
  270. } /* end function mapname() */
  271.  
  272.  
  273.  
  274.  
  275.  
  276. /***********************/
  277. /* Function checkdir() */
  278. /***********************/
  279.  
  280. int checkdir(pathcomp, flag)
  281.     char *pathcomp;
  282.     int flag;
  283. /*
  284.  * returns:  1 - (on APPEND_NAME) truncated filename
  285.  *           2 - path doesn't exist, not allowed to create
  286.  *           3 - path doesn't exist, tried to create and failed; or
  287.  *               path exists and is not a directory, but is supposed to be
  288.  *           4 - path is too long
  289.  *          10 - can't allocate memory for filename buffers
  290.  */
  291. {
  292.     static int rootlen = 0;   /* length of rootpath */
  293.     static char *rootpath;    /* user's "extract-to" directory */
  294.     static char *buildpath;   /* full path (so far) to extracted file */
  295.     static char *end;         /* pointer to end of buildpath ('\0') */
  296.  
  297. #   define FN_MASK   7
  298. #   define FUNCTION  (flag & FN_MASK)
  299.  
  300.  
  301.  
  302. /*---------------------------------------------------------------------------
  303.     APPEND_DIR:  append the path component to the path being built and check
  304.     for its existence.  If doesn't exist and we are creating directories, do
  305.     so for this one; else signal success or error as appropriate.
  306.   ---------------------------------------------------------------------------*/
  307.  
  308.     if (FUNCTION == APPEND_DIR) {
  309.         int too_long = FALSE;
  310.         char *old_end = end;
  311.  
  312.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  313.         while ((*end = *pathcomp++) != '\0')
  314.             ++end;
  315.     normalize_name(old_end);
  316.  
  317.         /* GRR:  could do better check, see if overrunning buffer as we go:
  318.          * check end-buildpath after each append, set warning variable if
  319.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  320.          * appending.  Clear variable when begin new path. */
  321.  
  322.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
  323.             too_long = TRUE;                /* check if extracting directory? */
  324.         if (stat(buildpath, &statbuf)) {    /* path doesn't exist */
  325.             if (!create_dirs) {   /* told not to create (freshening) */
  326.                 free(buildpath);
  327.                 return 2;         /* path doesn't exist:  nothing to do */
  328.             }
  329.             if (too_long) {
  330.                 fprintf(stderr, "checkdir error:  path too long: %s\n",
  331.                   buildpath);
  332.                 fflush(stderr);
  333.                 free(buildpath);
  334.                 return 4;         /* no room for filenames:  fatal */
  335.             }
  336.             if (mkdir(buildpath, 0666) == -1) {   /* create the directory */
  337.                 fprintf(stderr, "checkdir error:  can't create %s\n\
  338.                  unable to process %s.\n", buildpath, filename);
  339.                 fflush(stderr);
  340.                 free(buildpath);
  341.                 return 3;      /* path didn't exist, tried to create, failed */
  342.             }
  343.             created_dir = TRUE;
  344.         } else if (!S_ISDIR(statbuf.st_mode)) {
  345.             fprintf(stderr, "checkdir error:  %s exists but is not directory\n\
  346.                  unable to process %s.\n", buildpath, filename);
  347.             fflush(stderr);
  348.             free(buildpath);
  349.             return 3;          /* path existed but wasn't dir */
  350.         }
  351.         if (too_long) {
  352.             fprintf(stderr, "checkdir error:  path too long: %s\n", buildpath);
  353.             fflush(stderr);
  354.             free(buildpath);
  355.             return 4;         /* no room for filenames:  fatal */
  356.         }
  357.         *end++ = '/';
  358.         *end = '\0';
  359.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  360.         return 0;
  361.  
  362.     } /* end if (FUNCTION == APPEND_DIR) */
  363.  
  364. /*---------------------------------------------------------------------------
  365.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  366.     buildpath.
  367.   ---------------------------------------------------------------------------*/
  368.  
  369.     if (FUNCTION == GETPATH) {
  370.         strcpy(pathcomp, buildpath);
  371.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  372.         free(buildpath);
  373.         buildpath = end = NULL;
  374.         return 0;
  375.     }
  376.  
  377. /*---------------------------------------------------------------------------
  378.     APPEND_NAME:  assume the path component is the filename; append it and
  379.     return without checking for existence.
  380.   ---------------------------------------------------------------------------*/
  381.  
  382.     if (FUNCTION == APPEND_NAME) {
  383.         char *old_end = end;
  384.  
  385.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  386.         while ((*end = *pathcomp++) != '\0') {
  387.             ++end;
  388.         normalize_name(old_end);
  389.             if ((end-buildpath) >= FILNAMSIZ) {
  390.                 *--end = '\0';
  391.                 fprintf(stderr, "checkdir warning:  path too long; truncating\n\
  392. checkdir warning:  path too long; truncating\n\
  393.                    %s\n                -> %s\n", filename, buildpath);
  394.                 fflush(stderr);
  395.                 return 1;   /* filename truncated */
  396.             }
  397.         }
  398.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  399.         return 0;  /* could check for existence here, prompt for new name... */
  400.     }
  401.  
  402. /*---------------------------------------------------------------------------
  403.     INIT:  allocate and initialize buffer space for the file currently being
  404.     extracted.  If file was renamed with an absolute path, don't prepend the
  405.     extract-to path.
  406.   ---------------------------------------------------------------------------*/
  407.  
  408. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  409.  
  410.     if (FUNCTION == INIT) {
  411.         Trace((stderr, "initializing buildpath to "));
  412.         if ((buildpath = (char *)malloc(strlen(filename)+rootlen+1)) == NULL)
  413.             return 10;
  414.         if ((rootlen > 0) && !renamed_fullpath) {
  415.             strcpy(buildpath, rootpath);
  416.             end = buildpath + rootlen;
  417.         } else {
  418.             *buildpath = '\0';
  419.             end = buildpath;
  420.         }
  421.         Trace((stderr, "[%s]\n", buildpath));
  422.         return 0;
  423.     }
  424.  
  425. /*---------------------------------------------------------------------------
  426.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  427.     sary; else assume it's a zipfile member and return.  This path segment
  428.     gets used in extracting all members from every zipfile specified on the
  429.     command line.
  430.   ---------------------------------------------------------------------------*/
  431.  
  432. #if (!defined(SFX) || defined(SFX_EXDIR))
  433.     if (FUNCTION == ROOT) {
  434.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  435.         if (pathcomp == NULL) {
  436.             rootlen = 0;
  437.             return 0;
  438.         }
  439.         if ((rootlen = strlen(pathcomp)) > 0) {
  440.             int had_trailing_pathsep=FALSE;
  441.  
  442.             if (pathcomp[rootlen-1] == '/') {
  443.                 pathcomp[--rootlen] = '\0';
  444.                 had_trailing_pathsep = TRUE;
  445.             }
  446.             if (rootlen > 0 && (stat(pathcomp, &statbuf) ||
  447.                 !S_ISDIR(statbuf.st_mode)))          /* path does not exist */
  448.             {
  449.                 if (!create_dirs                     /* || iswild(pathcomp) */
  450. #ifdef OLD_EXDIR
  451.                                  || !had_trailing_pathsep
  452. #endif
  453.                                                          ) {
  454.                     rootlen = 0;
  455.                     return 2;   /* skip (or treat as stored file) */
  456.                 }
  457.                 /* create the directory (could add loop here to scan pathcomp
  458.                  * and create more than one level, but why really necessary?) */
  459.                 if (mkdir(pathcomp, 0777) == -1) {
  460.                     fprintf(stderr,
  461.                       "checkdir:  can't create extraction directory: %s\n",
  462.                       pathcomp);
  463.                     fflush(stderr);
  464.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  465.                     return 3;  /* failed:  file exists, or 2+ levels required */
  466.                 }
  467.             }
  468.             if ((rootpath = (char *)malloc(rootlen+2)) == NULL) {
  469.                 rootlen = 0;
  470.                 return 10;
  471.             }
  472.             strcpy(rootpath, pathcomp);
  473.             rootpath[rootlen++] = '/';
  474.             rootpath[rootlen] = '\0';
  475.         }
  476.         Trace((stderr, "rootpath now = [%s]\n", rootpath));
  477.         return 0;
  478.     }
  479. #endif /* !SFX || SFX_EXDIR */
  480.  
  481. /*---------------------------------------------------------------------------
  482.     END:  free rootpath, immediately prior to program exit.
  483.   ---------------------------------------------------------------------------*/
  484.  
  485.     if (FUNCTION == END) {
  486.         Trace((stderr, "freeing rootpath\n"));
  487.         if (rootlen > 0)
  488.             free(rootpath);
  489.         return 0;
  490.     }
  491.  
  492.     return 99;  /* should never reach */
  493.  
  494. } /* end function checkdir() */
  495.  
  496.  
  497.  
  498.  
  499.  
  500. /****************************/
  501. /* Function close_outfile() */
  502. /****************************/
  503.  
  504. void close_outfile()
  505. {
  506.     if (cflag) {
  507.     fclose(outfile);
  508.         return;
  509.     }
  510.  
  511.     _dos_filedate(fileno(outfile),
  512.       (ulg)lrec.last_mod_file_date << 16 | lrec.last_mod_file_time);
  513.     fclose(outfile);
  514.     _dos_chmod(filename, pInfo->file_attr);
  515.  
  516. } /* end function close_outfile() */
  517.  
  518.  
  519.  
  520.  
  521. #ifndef SFX
  522.  
  523. /************************/
  524. /*  Function version()  */
  525. /************************/
  526.  
  527. void version()
  528. {
  529.     extern char Far  CompiledWith[];
  530. #if 0
  531.     char buf[40];
  532. #endif
  533.  
  534.     printf(LoadFarString(CompiledWith),
  535.  
  536. #ifdef __GNUC__
  537.       "gcc ", __VERSION__,
  538. #else
  539. #  if 0
  540.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  541. #  else
  542.       "unknown compiler", "",
  543. #  endif
  544. #endif
  545.  
  546.       "Human68k", " (X68000)",
  547.  
  548. #ifdef __DATE__
  549.       " on ", __DATE__
  550. #else
  551.       "", ""
  552. #endif
  553.       );
  554.  
  555. } /* end function version() */
  556.  
  557. #endif /* !SFX */
  558.  
  559.  
  560.  
  561.  
  562.  
  563. /* Human68K-specific routines */
  564.  
  565. #define VALID_CHAR "&#()@_^{}!"
  566.  
  567. extern ulg TwentyOneOptions(void);
  568.  
  569. static int multi_period = 0;
  570. static int special_char = 0;
  571.  
  572. void
  573. InitTwentyOne(void)
  574. {
  575.     ulg stat;
  576.  
  577.     stat = TwentyOneOptions();
  578.     if (stat == 0 || stat == (unsigned long) -1) {
  579.     special_char = 0;
  580.     multi_period = 0;
  581.     return;
  582.     }
  583.     if (stat & (1UL << 29))
  584.     special_char = 1;
  585.     if (stat & (1UL << 28))
  586.     multi_period = 1;
  587. }
  588.  
  589. static void
  590. normalize_name(char *name)
  591. {
  592.     char *dot;
  593.     char *p;
  594.  
  595.     if (strlen(name) > 18) {    /* too long */
  596.     char base[18 + 1];
  597.     char ext[4 + 1];
  598.  
  599.     if ((dot = jstrrchr(name, '.')) != NULL)
  600.         *dot = '\0';
  601.     strncpy(base, name, 18);
  602.     base[18] = '\0';
  603.     if (dot) {
  604.         *dot = '.';
  605.         strncpy(ext, dot, 4);
  606.         ext[4] = '\0';
  607.     } else
  608.         *ext = '\0';
  609.     strcpy(name, base);
  610.     strcat(name, ext);
  611.     }
  612.     dot = NULL;
  613.     for (p = name; *p; p++) {
  614.     if (iskanji((unsigned char)*p) && p[1] != '\0')
  615.         p++;
  616.     else if (*p == '.') {
  617.         if (!multi_period) {
  618.         dot = p;
  619.         *p = '_';
  620.         }
  621.     } else if (!special_char && !isalnum (*p)
  622.            && strchr(VALID_CHAR, *p) == NULL)
  623.         *p = '_';
  624.     }
  625.     if (dot != NULL) {
  626.     *dot = '.';
  627.     if (strlen(dot) > 4)
  628.         dot[4] = '\0';
  629.     }
  630. }
  631.