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