home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8707 / 64 / arcdir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-13  |  8.5 KB  |  398 lines

  1. static char *RCSid = "$Header: arcdir.c,v 1.2 86/07/15 07:52:56 turner Exp $";
  2.  
  3. /*
  4.  * $Log:    arcdir.c,v $
  5.  * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
  6.  *     Bludgeoned into submission for VAX 11/780 BSD4.2
  7.  *    (ugly code, but fewer core dumps)
  8.  *
  9.  * Revision 1.2  86/07/15  07:52:56  turner
  10.  * 
  11.  * Revision 1.1  86/06/26  15:00:12  turner
  12.  * initial version
  13.  * 
  14.  */
  15.  
  16. /*  ARC - Archive utility - ARCDIR
  17. */
  18. #include <stdio.h>
  19. #include "arc.h"
  20.  
  21. #if MSDOS
  22. #include <dir.h>
  23. #endif
  24.  
  25. #if BSD
  26. #include <sys/types.h>
  27. #include <sys/dir.h>
  28. #endif
  29.  
  30. char *pattern;                  /* global so that fmatch can use them */
  31. INT filemode;
  32.  
  33. char *dir(filename,mode,NameList)               /* get files, one by one */
  34. char *filename;                        /* template, or NULL */
  35. INT mode;                              /* search mode bits */
  36. char *(*NameList[]);
  37. {
  38.         struct direct *(*namelist[]);
  39. #ifdef BSD
  40.     INT alphasort();
  41.     INT scandir();
  42. #endif BSD
  43.         INT fmatch();
  44.     static INT Nnum = 0,ii;
  45.     char *result;
  46.  
  47.     pattern = filename;
  48.     filemode = mode;        /* set up globals for fmatch */
  49.     if(Nnum == 0) {                  /* first call */
  50.             Nnum = scandir(".", namelist, fmatch, alphasort);
  51.             *NameList = (char **)malloc(Nnum*sizeof(char *));
  52.             for (ii=0; ii<Nnum; ii++) {
  53.                 (*NameList)[ii] = (char *)malloc((*namelist)[ii]->d_namlen+1);
  54.                 strcpy((*NameList)[ii],(*namelist)[ii]->d_name);
  55.             }
  56.             ii = 0;
  57.     }
  58.     if(ii >= Nnum) { /* all out of files */
  59.         if(Nnum) { /* there were some files found */
  60.             freedir(namelist);
  61.             }
  62.         Nnum = 0;
  63.         return(NULL);
  64.     }
  65.     else {
  66.         return((*NameList)[ii++]);
  67.     }
  68. }
  69.  
  70. #define ASTERISK '*'        /* The '*' metacharacter */
  71. #define QUESTION '?'        /* The '?' metacharacter */
  72. #define LEFT_BRACKET '['    /* The '[' metacharacter */
  73. #define RIGHT_BRACKET ']'    /* The ']' metacharacter */
  74.  
  75. #define IS_OCTAL(ch) (ch >= '0' && ch <= '7')
  76.  
  77. typedef INT BOOLEAN;
  78. #define VOID short
  79. #define TRUE 1
  80. #define FALSE 0
  81. #define EOS '\000'
  82.  
  83. static BOOLEAN do_list ();
  84. static char nextch ();
  85. static VOID list_parse ();
  86.  
  87.  
  88. /*
  89.  *  FUNCTION
  90.  *
  91.  *    match   test string for wildcard match
  92.  *
  93.  *  SYNOPSIS
  94.  *
  95.  *    BOOLEAN match (string, pattern)
  96.  *    register char *string;
  97.  *    register char *pattern;
  98.  *
  99.  *  DESCRIPTION
  100.  *
  101.  *    Test string for match using pattern.  The pattern may
  102.  *    contain the normal shell metacharacters for pattern
  103.  *    matching.  The '*' character matches any string,
  104.  *    including the null string.  The '?' character matches
  105.  *    any single character.  A list of characters enclosed
  106.  *    in '[' and ']' matches any character in the list.
  107.  *    If the first character following the beginning '['
  108.  *    is a '!' then any character not in the list is matched.
  109.  *
  110.  */
  111.  
  112.  
  113. /*
  114.  *  PSEUDO CODE
  115.  *
  116.  *    Begin match
  117.  *        Switch on type of pattern character
  118.  *        Case ASTERISK:
  119.  *            Attempt to match asterisk
  120.  *            Break
  121.  *        Case QUESTION MARK:
  122.  *            Attempt to match question mark
  123.  *            Break
  124.  *        Case EOS:
  125.  *            Match is result of EOS on string test
  126.  *            Break
  127.  *        Case default:
  128.  *            If explicit match then
  129.  *            Match is result of submatch
  130.  *            Else
  131.  *            Match is FALSE
  132.  *            End if
  133.  *            Break
  134.  *        End switch
  135.  *        Return result of match test
  136.  *    End match
  137.  *
  138.  */
  139.  
  140. static BOOLEAN match (string, pattern)
  141. register char *string;
  142. register char *pattern;
  143. {
  144.     register BOOLEAN ismatch;
  145.  
  146.     ismatch = FALSE;
  147.     switch (*pattern) {
  148.     case ASTERISK:
  149.         pattern++;
  150.         do {
  151.         ismatch = match (string, pattern);
  152.         } while (!ismatch && *string++ != EOS);
  153.         break;
  154.     case QUESTION:
  155.         if (*string != EOS) {
  156.         ismatch = match (++string, ++pattern);
  157.         }
  158.         break;
  159.     case EOS:
  160.         if (*string == EOS) {
  161.         ismatch = TRUE;
  162.         }
  163.         break;
  164.     case LEFT_BRACKET:
  165.         if (*string != EOS) {
  166.         ismatch = do_list (string, pattern);
  167.         }
  168.         break;
  169.     default:
  170.         if (tolower(*string) == tolower(*pattern))
  171.         {
  172.             string++;
  173.             pattern++;
  174.         ismatch = match (string, pattern);
  175.         } else {
  176.         ismatch = FALSE;
  177.         }
  178.         break;
  179.     }
  180.     return (ismatch);
  181. }
  182.  
  183.  
  184. /*
  185.  *  FUNCTION
  186.  *
  187.  *    do_list    process a list and following substring
  188.  *
  189.  *  SYNOPSIS
  190.  *
  191.  *    static BOOLEAN do_list (string, pattern)
  192.  *    register char *string;
  193.  *    register char *pattern;
  194.  *
  195.  *  DESCRIPTION
  196.  *
  197.  *    Called when a list is found in the pattern.  Returns
  198.  *    TRUE if the current character matches the list and
  199.  *    the remaining substring matches the remaining pattern.
  200.  *
  201.  *    Returns FALSE if either the current character fails to
  202.  *    match the list or the list matches but the remaining
  203.  *    substring and subpattern's don't.
  204.  *
  205.  *  RESTRICTIONS
  206.  *
  207.  *    The mechanism used to match characters in an inclusive
  208.  *    pair (I.E. [a-d]) may not be portable to machines
  209.  *    in which the native character set is not ASCII.
  210.  *
  211.  *    The rules implemented here are:
  212.  *
  213.  *        (1)    The backslash character may be
  214.  *            used to quote any special character.
  215.  *            I.E.  "\]" and "\-" anywhere in list,
  216.  *            or "\!" at start of list.
  217.  *
  218.  *        (2)    The sequence \nnn becomes the character
  219.  *            given by nnn (in octal).
  220.  *
  221.  *        (3)    Any non-escaped ']' marks the end of list.
  222.  *
  223.  *        (4)    A list beginning with the special character
  224.  *            '!' matches any character NOT in list.
  225.  *            The '!' character is only special if it
  226.  *            is the first character in the list.
  227.  *
  228.  */
  229.  
  230.  
  231. /*
  232.  *  PSEUDO CODE
  233.  *
  234.  *    Begin do_list
  235.  *        Default result is no match
  236.  *        Skip over the opening left bracket
  237.  *        If the next pattern character is a '!' then
  238.  *        List match gives FALSE
  239.  *        Skip over the '!' character
  240.  *        Else
  241.  *        List match gives TRUE
  242.  *        End if
  243.  *        While not at closing bracket or EOS
  244.  *        Get lower and upper bounds
  245.  *        If character in bounds then
  246.  *            Result is same as sense flag.
  247.  *            Skip over rest of list
  248.  *        End if
  249.  *        End while
  250.  *        If match found then
  251.  *        If not at end of pattern then
  252.  *            Call match with rest of pattern
  253.  *        End if
  254.  *        End if
  255.  *        Return match result
  256.  *    End do_list
  257.  *
  258.  */
  259.  
  260. static BOOLEAN do_list (string, pattern)
  261. register char *string;
  262. char *pattern;
  263. {
  264.     register BOOLEAN ismatch;
  265.     register BOOLEAN if_found;
  266.     register BOOLEAN if_not_found;
  267.     auto char lower;
  268.     auto char upper;
  269.  
  270.     pattern++;
  271.     if (*pattern == '!') {
  272.     if_found = FALSE;
  273.     if_not_found = TRUE;
  274.     pattern++;
  275.     } else {
  276.     if_found = TRUE;
  277.     if_not_found = FALSE;
  278.     }
  279.     ismatch = if_not_found;
  280.     while (*pattern != ']' && *pattern != EOS) {
  281.     list_parse (&pattern, &lower, &upper);
  282.     if (*string >= lower && *string <= upper) {
  283.         ismatch = if_found;
  284.         while (*pattern != ']' && *pattern != EOS) {pattern++;}
  285.     }
  286.     }
  287.     if (*pattern++ != ']') {
  288.     fprintf (stderr, "warning - character class error\n");
  289.     } else {
  290.     if (ismatch) {
  291.         ismatch = match (++string, pattern);
  292.     }
  293.     }
  294.     return (ismatch);
  295. }
  296.  
  297.  
  298. /*
  299.  *  FUNCTION
  300.  *
  301.  *    list_parse    parse part of list into lower and upper bounds
  302.  *
  303.  *  SYNOPSIS
  304.  *
  305.  *    static VOID list_parse (patp, lowp, highp)
  306.  *    char **patp;
  307.  *    char *lowp;
  308.  *    char *highp;
  309.  *
  310.  *  DESCRIPTION
  311.  *
  312.  *    Given pointer to a pattern pointer (patp), pointer to
  313.  *    a place to store lower bound (lowp), and pointer to a
  314.  *    place to store upper bound (highp), parses part of
  315.  *    the list, updating the pattern pointer in the process.
  316.  *
  317.  *    For list characters which are not part of a range,
  318.  *    the lower and upper bounds are set to that character.
  319.  *
  320.  */
  321.  
  322. static VOID list_parse (patp, lowp, highp)
  323. char **patp;
  324. char *lowp;
  325. char *highp;
  326. {
  327.     *lowp = nextch (patp);
  328.     if (**patp == '-') {
  329.     (*patp)++;
  330.     *highp = nextch (patp);
  331.     } else {
  332.     *highp = *lowp;
  333.     }
  334. }
  335.  
  336.  
  337. /*
  338.  *  FUNCTION
  339.  *
  340.  *    nextch    determine next character in a pattern
  341.  *
  342.  *  SYNOPSIS
  343.  *
  344.  *    static char nextch (patp)
  345.  *    char **patp;
  346.  *
  347.  *  DESCRIPTION
  348.  *
  349.  *    Given pointer to a pointer to a pattern, uses the pattern
  350.  *    pointer to determine the next character in the pattern,
  351.  *    subject to translation of backslash-char and backslash-octal
  352.  *    sequences.
  353.  *
  354.  *    The character pointer is updated to point at the next pattern
  355.  *    character to be processed.
  356.  *
  357.  */
  358.  
  359. static char nextch (patp)
  360. char **patp;
  361. {
  362.     register char ch;
  363.     register char chsum;
  364.     register INT count;
  365.  
  366.     ch = *(*patp)++;
  367.     if (ch == '\\') {
  368.     ch = *(*patp)++;
  369.     if (IS_OCTAL (ch)) {
  370.         chsum = 0;
  371.         for (count = 0; count < 3 && IS_OCTAL (ch); count++) {
  372.         chsum *= 8;
  373.         chsum += ch - '0';
  374.         ch = *(*patp)++;
  375.         }
  376.         (*patp)--;
  377.         ch = chsum;
  378.     }
  379.     }
  380.     return (ch);
  381. }
  382.  
  383. /*
  384.  *    Filename match - here, *.* matches everything
  385.  */
  386.  
  387. BOOLEAN fmatch (direntry)
  388. struct direct *direntry;
  389. {
  390.     char *ptr,*string;
  391.  
  392.     string = direntry->d_name;
  393.  
  394.     if(!strcmp(pattern, "") || !strcmp(pattern, "*.*"))
  395.         return(1);
  396.     return(match(string, pattern));
  397. }
  398.