home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / zip22.zip / util.c < prev    next >
C/C++ Source or Header  |  1997-08-23  |  18KB  |  621 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1997 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  util.c by Mark Adler.
  13.  */
  14.  
  15. #include "zip.h"
  16. #include "ebcdic.h"
  17. #include <ctype.h>
  18.  
  19. #ifdef MSDOS16
  20. #  include <dos.h>
  21. #endif
  22.  
  23. uch upper[256], lower[256];
  24. /* Country-dependent case map table */
  25.  
  26.  
  27. #ifndef UTIL /* UTIL picks out namecmp code (all utils) */
  28.  
  29. /* Local functions */
  30. local int recmatch OF((uch *, uch *));
  31. local int count_args OF((char *s));
  32.  
  33. #ifdef MSDOS16
  34.   local unsigned ident OF((unsigned chr));
  35. #endif
  36.  
  37. #ifdef NO_MKTIME
  38. #include "mktime.c"
  39. #endif
  40.  
  41. #ifndef HAVE_FSEEKABLE
  42. int fseekable(fp)
  43. FILE *fp;
  44. {
  45.     long x;
  46.  
  47.     return (fp == NULL || (fseek(fp, -1L, SEEK_CUR) == 0 &&
  48.             (x = ftell(fp)) >= 0 &&
  49.             fseek(fp,  1L, SEEK_CUR) == 0 &&
  50.             ftell(fp) == x + 1));
  51. }
  52. #endif /* HAVE_FSEEKABLE */
  53.  
  54. char *isshexp(p)
  55. char *p;                /* candidate sh expression */
  56. /* If p is a sh expression, a pointer to the first special character is
  57.    returned.  Otherwise, NULL is returned. */
  58. {
  59.   for (; *p; p++)
  60.     if (*p == '\\' && *(p+1))
  61.       p++;
  62. #ifdef VMS
  63.     else if (*p == '%' || *p == '*')
  64. #else /* !VMS */
  65.     else if (*p == '?' || *p == '*' || *p == '[')
  66. #endif /* ?VMS */
  67.       return p;
  68.   return NULL;
  69. }
  70.  
  71.  
  72. local int recmatch(p, s)
  73. uch *p;       /* sh pattern to match */
  74. uch *s;       /* string to match it to */
  75. /* Recursively compare the sh pattern p with the string s and return 1 if
  76.    they match, and 0 or 2 if they don't or if there is a syntax error in the
  77.    pattern.  This routine recurses on itself no deeper than the number of
  78.    characters in the pattern. */
  79. {
  80.   unsigned int c;       /* pattern char or start of range in [-] loop */
  81.   /* Get first character, the pattern for new recmatch calls follows */
  82.   c = *p++;
  83.  
  84.   /* If that was the end of the pattern, match if string empty too */
  85.   if (c == 0)
  86.     return *s == 0;
  87.  
  88.   /* '?' (or '%') matches any character (but not an empty string) */
  89. #ifdef VMS
  90.   if (c == '%')
  91. #else /* !VMS */
  92.   if (c == '?')
  93. #endif /* ?VMS */
  94.     return *s ? recmatch(p, s + 1) : 0;
  95.  
  96.   /* '*' matches any number of characters, including zero */
  97. #ifdef AMIGA
  98.   if (c == '#' && *p == '?')            /* "#?" is Amiga-ese for "*" */
  99.     c = '*', p++;
  100. #endif /* AMIGA */
  101.   if (c == '*')
  102.   {
  103.     if (*p == 0)
  104.       return 1;
  105.     for (; *s; s++)
  106.       if ((c = recmatch(p, s)) != 0)
  107.         return (int)c;
  108.     return 2;           /* 2 means give up--shmatch will return false */
  109.   }
  110.  
  111. #ifndef VMS             /* No bracket matching in VMS */
  112.   /* Parse and process the list of characters and ranges in brackets */
  113.   if (c == '[')
  114.   {
  115.     int e;              /* flag true if next char to be taken literally */
  116.     uch *q;   /* pointer to end of [-] group */
  117.     int r;              /* flag true to match anything but the range */
  118.  
  119.     if (*s == 0)                        /* need a character to match */
  120.       return 0;
  121.     p += (r = (*p == '!' || *p == '^')); /* see if reverse */
  122.     for (q = p, e = 0; *q; q++)         /* find closing bracket */
  123.       if (e)
  124.         e = 0;
  125.       else
  126.         if (*q == '\\')
  127.           e = 1;
  128.         else if (*q == ']')
  129.           break;
  130.     if (*q != ']')                      /* nothing matches if bad syntax */
  131.       return 0;
  132.     for (c = 0, e = *p == '-'; p < q; p++)      /* go through the list */
  133.     {
  134.       if (e == 0 && *p == '\\')         /* set escape flag if \ */
  135.         e = 1;
  136.       else if (e == 0 && *p == '-')     /* set start of range if - */
  137.         c = *(p-1);
  138.       else
  139.       {
  140.         uch cc = case_map(*s);
  141.         if (*(p+1) != '-')
  142.           for (c = c ? c : *p; c <= *p; c++)    /* compare range */
  143.             if (case_map(c) == cc)
  144.               return r ? 0 : recmatch(q + 1, s + 1);
  145.         c = e = 0;                      /* clear range, escape flags */
  146.       }
  147.     }
  148.     return r ? recmatch(q + 1, s + 1) : 0;      /* bracket match failed */
  149.   }
  150. #endif /* !VMS */
  151.  
  152.   /* If escape ('\'), just compare next character */
  153.   if (c == '\\')
  154.     if ((c = *p++) == 0)                /* if \ at end, then syntax error */
  155.       return 0;
  156.  
  157.   /* Just a character--compare it */
  158.   return case_map(c) == case_map(*s) ? recmatch(p, ++s) : 0;
  159. }
  160.  
  161.  
  162. int shmatch(p, s)
  163. char *p;                /* sh pattern to match */
  164. char *s;                /* string to match it to */
  165. /* Compare the sh pattern p with the string s and return true if they match,
  166.    false if they don't or if there is a syntax error in the pattern. */
  167. {
  168.   return recmatch((uch *) p, (uch *) s) == 1;
  169. }
  170.  
  171.  
  172. #if defined(DOS) || defined(WIN32)
  173. /* XXX  also suitable for OS2?  Atari?  Human68K?  TOPS-20?? */
  174.  
  175. int dosmatch(p, s)
  176. char *p;                /* dos pattern to match    */
  177. char *s;                /* string to match it to   */
  178. /* Treat filenames without periods as having an implicit trailing period */
  179. {
  180.   char *s1;             /* revised string to match */
  181.   int r;                /* result */
  182.  
  183.   if ((s1 = malloc(strlen(s) + 2)) == NULL)
  184.     return recmatch((uch *) p, (uch *) s) == 1;  /* will usually be correct */
  185.   strcpy(s1, s);
  186.   if (strchr(p, '.') && !strchr(s1, '.'))
  187.     strcat(s1, ".");
  188.   r = recmatch((uch *)p, (uch *)s1);
  189.   free((zvoid *)s1);
  190.   return r == 1;
  191. }
  192.  
  193. #endif /* DOS || WIN32 */
  194.  
  195. zvoid far **search(b, a, n, cmp)
  196. zvoid *b;               /* pointer to value to search for */
  197. zvoid far **a;          /* table of pointers to values, sorted */
  198. extent n;               /* number of pointers in a[] */
  199. int (*cmp) OF((ZCONST zvoid *, ZCONST zvoid far *)); /* comparison function */
  200.  
  201. /* Search for b in the pointer list a[0..n-1] using the compare function
  202.    cmp(b, c) where c is an element of a[i] and cmp() returns negative if
  203.    *b < *c, zero if *b == *c, or positive if *b > *c.  If *b is found,
  204.    search returns a pointer to the entry in a[], else search() returns
  205.    NULL.  The nature and size of *b and *c (they can be different) are
  206.    left up to the cmp() function.  A binary search is used, and it is
  207.    assumed that the list is sorted in ascending order. */
  208. {
  209.   zvoid far **i;        /* pointer to midpoint of current range */
  210.   zvoid far **l;        /* pointer to lower end of current range */
  211.   int r;                /* result of (*cmp)() call */
  212.   zvoid far **u;        /* pointer to upper end of current range */
  213.  
  214.   l = (zvoid far **)a;  u = l + (n-1);
  215.   while (u >= l) {
  216.     i = l + ((unsigned)(u - l) >> 1);
  217.     if ((r = (*cmp)(b, (char *)*(struct zlist **)i)) < 0)
  218.       u = i - 1;
  219.     else if (r > 0)
  220.       l = i + 1;
  221.     else
  222.       return (zvoid far **)i;
  223.   }
  224.   return NULL;          /* If b were in list, it would belong at l */
  225. }
  226.  
  227. #endif /* !UTIL */
  228.  
  229. #ifdef MSDOS16
  230.  
  231. local unsigned ident(unsigned chr)
  232. {
  233.    return chr; /* in al */
  234. }
  235.  
  236. void init_upper()
  237. {
  238.   static struct country {
  239.     uch ignore[18];
  240.     int (far *casemap)(int);
  241.     uch filler[16];
  242.   } country_info;
  243.  
  244.   struct country far *info = &country_info;
  245.   union REGS regs;
  246.   struct SREGS sregs;
  247.   int c;
  248.  
  249.   regs.x.ax = 0x3800; /* get country info */
  250.   regs.x.dx = FP_OFF(info);
  251.   sregs.ds  = FP_SEG(info);
  252.   intdosx(®s, ®s, &sregs);
  253.   for (c = 0; c < 128; c++) {
  254.     upper[c] = (uch) toupper(c);
  255.     lower[c] = (uch) c;
  256.   }
  257.   for (; c < sizeof(upper); c++) {
  258.     upper[c] = (uch) (*country_info.casemap)(ident(c));
  259.     /* ident() required because casemap takes its parameter in al */
  260.     lower[c] = (uch) c;
  261.   }
  262.   for (c = 0; c < sizeof(upper); c++ ) {
  263.     int u = upper[c];
  264.     if (u != c && lower[u] == (uch) u) {
  265.       lower[u] = (uch)c;
  266.     }
  267.   }
  268.   for (c = 'A'; c <= 'Z'; c++) {
  269.     lower[c] = (uch) (c - 'A' + 'a');
  270.   }
  271. }
  272. #else /* !MSDOS16 */
  273. #  ifndef OS2
  274.  
  275. void init_upper()
  276. {
  277.   int c;
  278. #if defined(ATARI) || defined(CMS_MVS)
  279. #include <ctype.h>
  280. /* this should be valid for all other platforms too.   (HD 11/11/95) */
  281.   for (c = 0; c< sizeof(upper); c++) {
  282.     upper[c] = islower(c) ? toupper(c) : c;
  283.     lower[c] = isupper(c) ? tolower(c) : c;
  284.   }
  285. #else
  286.   for (c = 0; c < sizeof(upper); c++) upper[c] = lower[c] = c;
  287.   for (c = 'a'; c <= 'z';        c++) upper[c] = c - 'a' + 'A';
  288.   for (c = 'A'; c <= 'Z';        c++) lower[c] = c - 'A' + 'a';
  289. #endif
  290. }
  291. #  endif /* !OS2 */
  292.  
  293. #endif /* ?MSDOS16 */
  294.  
  295. int namecmp(string1, string2)
  296.   char *string1, *string2;
  297. /* Compare the two strings ignoring case, and correctly taking into
  298.  * account national language characters. For operating systems with
  299.  * case sensitive file names, this function is equivalent to strcmp.
  300.  */
  301. {
  302.   int d;
  303.  
  304.   for (;;)
  305.   {
  306.     d = (int) (uch) case_map(*string1)
  307.       - (int) (uch) case_map(*string2);
  308.  
  309.     if (d || *string1 == 0 || *string2 == 0)
  310.       return d;
  311.  
  312.     string1++;
  313.     string2++;
  314.   }
  315. }
  316.  
  317. #ifdef EBCDIC
  318. char *strtoasc(char *str1, ZCONST char *str2)
  319. {
  320.   char *old;
  321.   old = str1;
  322.   while (*str1++ = (char)ascii[(uch)(*str2++)]);
  323.   return old;
  324. }
  325.  
  326. char *strtoebc(char *str1, ZCONST char *str2)
  327. {
  328.   char *old;
  329.   old = str1;
  330.   while (*str1++ = (char)ebcdic[(uch)(*str2++)]);
  331.   return old;
  332. }
  333.  
  334. char *memtoasc(char *mem1, ZCONST char *mem2, unsigned len)
  335. {
  336.   char *old;
  337.   old = mem1;
  338.   while (len--)
  339.      *mem1++ = (char)ascii[(uch)(*mem2++)];
  340.   return old;
  341. }
  342.  
  343. char *memtoebc(char *mem1, ZCONST char *mem2, unsigned len)
  344. {
  345.   char *old;
  346.   old = mem1;
  347.   while (len--)
  348.      *mem1++ = (char)ebcdic[(uch)(*mem2++)];
  349.   return old;
  350. }
  351. #endif /* EBCDIC */
  352.  
  353. #ifdef IZ_ISO2OEM_ARRAY
  354. char *str_iso_to_oem(dst, src)
  355.   ZCONST char *src;
  356.   char *dst;
  357. {
  358.   char *dest_start = dst;
  359.   while (*dst++ = (char)iso2oem[(uch)(*src++)]);
  360.   return dest_start;
  361. }
  362. #endif
  363.  
  364. #ifdef IZ_OEM2ISO_ARRAY
  365. char *str_oem_to_iso(dst, src)
  366.   ZCONST char *src;
  367.   char *dst;
  368. {
  369.   char *dest_start = dst;
  370.   while (*dst++ = (char)oem2iso[(uch)(*src++)]);
  371.   return dest_start;
  372. }
  373. #endif
  374.  
  375.  
  376. #ifndef UTIL
  377.  
  378. extern char *getenv OF((ZCONST char *));
  379.  
  380. /*****************************************************************
  381.  | envargs - add default options from environment to command line
  382.  |----------------------------------------------------------------
  383.  | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991.
  384.  | This program is in the public domain.
  385.  |----------------------------------------------------------------
  386.  | Minor program notes:
  387.  |  1. Yes, the indirection is a tad complex
  388.  |  2. Parenthesis were added where not needed in some cases
  389.  |     to make the action of the code less obscure.
  390.  ****************************************************************/
  391.  
  392. void envargs(Pargc, Pargv, envstr, envstr2)
  393.     int *Pargc;
  394.     char ***Pargv;
  395.     char *envstr;
  396.     char *envstr2;
  397. {
  398.     char *envptr;                     /* value returned by getenv */
  399.     char *bufptr;                     /* copy of env info */
  400.     int argc;                         /* internal arg count */
  401.     register int ch;                  /* spare temp value */
  402.     char **argv;                      /* internal arg vector */
  403.     char **argvect;                   /* copy of vector address */
  404.  
  405.     /* see if anything in the environment */
  406.     envptr = getenv(envstr);
  407.     if (envptr != NULL)                                /* usual var */
  408.         while (isspace(*envptr))           /* we must discard leading spaces */
  409.             envptr++;
  410.     if (envptr == NULL || *envptr == '\0')
  411.         if ((envptr = getenv(envstr2)) != NULL)                 /* alternate */
  412.             while (isspace(*envptr))
  413.                 envptr++;
  414.     if (envptr == NULL || *envptr == '\0')
  415.         return;
  416.  
  417.     /* count the args so we can allocate room for them */
  418.     argc = count_args(envptr);
  419.     bufptr = malloc(1 + strlen(envptr));
  420.     if (bufptr == NULL)
  421.         ziperr(ZE_MEM, "Can't get memory for arguments");
  422.     strcpy(bufptr, envptr);
  423.  
  424.     /* allocate a vector large enough for all args */
  425.     argv = (char **)malloc((argc + *Pargc + 1) * sizeof(char *));
  426.     if (argv == NULL) {
  427.         free(bufptr);
  428.         ziperr(ZE_MEM, "Can't get memory for arguments");
  429.     }
  430.     argvect = argv;
  431.  
  432.     /* copy the program name first, that's always true */
  433.     *(argv++) = *((*Pargv)++);
  434.  
  435.     /* copy the environment args first, may be changed */
  436.     do {
  437. #if defined(AMIGA) || defined(UNIX)
  438.         if (*bufptr == '"') {
  439.             char *argstart = ++bufptr;
  440.             *(argv++) = argstart;
  441.             for (ch = *bufptr; ch != '\0' && ch != '\"'; ch = *(++bufptr))
  442.                 if (ch == '\\' && bufptr[1] != '\0')
  443.                     ++bufptr;                  /* skip char after backslash */
  444.             if (ch != '\0') *(bufptr++) = '\0';     /* overwrite trailing " */
  445.  
  446.             /* remove escape characters */
  447.             while (argstart = strchr(argstart, '\\')) {
  448.                 strcpy(argstart, argstart + 1);
  449.                 if (*argstart)
  450.                     ++argstart;
  451.             }
  452.         } else {
  453.             *(argv++) = bufptr;
  454.             while ((ch = *bufptr) != '\0' && !isspace(ch)) ++bufptr;
  455.             if (ch != '\0') *(bufptr++) = '\0';
  456.         }
  457. #else
  458. #  ifdef WIN32
  459.         /* We do not support backslash-quoting of quotes in quoted */
  460.         /* strings under Win32, because backslashes are directory  */
  461.         /* separators and double quotes are illegal in filenames.  */
  462.         if (*bufptr == '"') {
  463.             *(argv++) = ++bufptr;
  464.             while ((ch = *bufptr) != '\0' && ch != '\"') ++bufptr;
  465.             if (ch != '\0') *(bufptr++) = '\0';
  466.         } else {
  467.             *(argv++) = bufptr;
  468.             while ((ch = *bufptr) != '\0' && !isspace(ch)) ++bufptr;
  469.             if (ch != '\0') *(bufptr++) = '\0';
  470.         }
  471. #  else
  472.         *(argv++) = bufptr;
  473.         while ((ch = *bufptr) != '\0' && !isspace(ch)) ++bufptr;
  474.         if (ch != '\0') *(bufptr++) = '\0';
  475. #  endif
  476. #endif /* ?(AMIGA || UNIX) */
  477.         while ((ch = *bufptr) != '\0' && isspace(ch)) ++bufptr;
  478.     } while (ch);
  479.  
  480.     /* now save old argc and copy in the old args */
  481.     argc += *Pargc;
  482.     while (--(*Pargc)) *(argv++) = *((*Pargv)++);
  483.  
  484.     /* finally, add a NULL after the last arg, like UNIX */
  485.     *argv = NULL;
  486.  
  487.     /* save the values and return */
  488.     *Pargv = argvect;
  489.     *Pargc = argc;
  490. }
  491.  
  492. static int count_args(s)
  493. char *s;
  494. {
  495.     int count = 0;
  496.     char ch;
  497.  
  498.     do {
  499.         /* count and skip args */
  500.         ++count;
  501. #if defined(AMIGA) || defined(UNIX)
  502.         if (*s == '\"') {
  503.             for (ch = *(++s); ch != '\0' && ch != '\"'; ch = *(++s))
  504.                 if (ch == '\\' && s[1] != '\0')
  505.                     ++s;
  506.             if (*s) ++s;        /* trailing quote */
  507.         } else
  508.             while ((ch = *s) != '\0' && !isspace(ch)) ++s;
  509. #else
  510. #  ifdef WIN32
  511.         if (*s == '\"') {
  512.             ++s;                /* leading quote */
  513.             while ((ch = *s) != '\0' && ch != '\"') ++s;
  514.             if (*s) ++s;        /* trailing quote */
  515.         } else
  516.             while ((ch = *s) != '\0' && !isspace(ch)) ++s;
  517. #  else
  518.         while ((ch = *s) != '\0' && !isspace(ch)) ++s;
  519. #  endif
  520. #endif /* ?(AMIGA || UNIX) */
  521.         while ((ch = *s) != '\0' && isspace(ch)) ++s;
  522.     } while (ch);
  523.  
  524.     return(count);
  525. }
  526.  
  527.  
  528.  
  529. /* Extended argument processing -- by Rich Wales
  530.  * This function currently deals only with the MKS shell, but could be
  531.  * extended later to understand other conventions.
  532.  *
  533.  * void expand_args(int *argcp, char ***argvp)
  534.  *
  535.  *    Substitutes the extended command line argument list produced by
  536.  *    the MKS Korn Shell in place of the command line info from DOS.
  537.  *
  538.  *    The MKS shell gets around DOS's 128-byte limit on the length of
  539.  *    a command line by passing the "real" command line in the envi-
  540.  *    ronment.  The "real" arguments are flagged by prepending a tilde
  541.  *    (~) to each one.
  542.  *
  543.  *    This "expand_args" routine creates a new argument list by scanning
  544.  *    the environment from the beginning, looking for strings begin-
  545.  *    ning with a tilde character.  The new list replaces the original
  546.  *    "argv" (pointed to by "argvp"), and the number of arguments
  547.  *    in the new list replaces the original "argc" (pointed to by
  548.  *    "argcp").
  549.  */
  550. void expand_args(argcp, argvp)
  551.       int *argcp;
  552.       char ***argvp;
  553. {
  554. #ifdef DOS
  555.  
  556. /* Do NEVER include (re)definiton of `environ' variable with any version
  557.    of MSC or BORLAND/Turbo C. These compilers supply an incompatible
  558.    definition in <stdlib.h>.  */
  559. #if defined(__GO32__) || defined(__EMX__)
  560.       extern char **environ;          /* environment */
  561. #endif /* __GO32__ || __EMX__ */
  562.       char        **envp;             /* pointer into environment */
  563.       char        **newargv;          /* new argument list */
  564.       char        **argp;             /* pointer into new arg list */
  565.       int           newargc;          /* new argument count */
  566.  
  567.       /* sanity check */
  568.       if (environ == NULL
  569.           || argcp == NULL
  570.           || argvp == NULL || *argvp == NULL)
  571.               return;
  572.       /* find out how many environment arguments there are */
  573.       for (envp = environ, newargc = 0;
  574.            *envp != NULL && (*envp)[0] == '~';
  575.            envp++, newargc++) ;
  576.       if (newargc == 0)
  577.               return;                 /* no environment arguments */
  578.       /* set up new argument list */
  579.       newargv = (char **) malloc(sizeof(char **) * (newargc+1));
  580.       if (newargv == NULL)
  581.               return;                 /* malloc failed */
  582.       for (argp = newargv, envp = environ;
  583.            *envp != NULL && (*envp)[0] == '~';
  584.            *argp++ = &(*envp++)[1]) ;
  585.       *argp = NULL;                   /* null-terminate the list */
  586.       /* substitute new argument list in place of old one */
  587.       *argcp = newargc;
  588.       *argvp = newargv;
  589. #else /* ?DOS */
  590.       if (argcp || argvp) return;
  591. #endif /* ?DOS */
  592. }
  593.  
  594. #endif /* UTIL */
  595.  
  596. #ifdef DEBUGNAMES
  597. #undef free
  598. int Free(x)
  599. void *x;
  600. {
  601.     if (x == (void *) 0xdeadbeef)
  602.         exit(-1);
  603.     free(x);
  604.     return 0;
  605. }
  606.  
  607. int printnames()
  608. {
  609.      struct zlist far *z;
  610.  
  611.      for (z = zfiles; z != NULL; z = z->nxt)
  612.            fprintf(stderr, "%s %s %s %p %p %p %08x %08x %08x\n",
  613.                             z->name, z->zname, z->iname,
  614.                             z->name, z->zname, z->iname,
  615.                             *((int *) z->name), *((int *) z->zname),
  616.                             *((int *) z->iname));
  617.      return 0;
  618. }
  619.  
  620. #endif
  621.