Annotation of coherent/b/bin/unzip/match.c, revision 1.1

1.1     ! root        1: /*---------------------------------------------------------------------------
        !             2: 
        !             3:   match.c
        !             4: 
        !             5:   The match() routine recursively compares a string to a "pattern" (regular
        !             6:   expression), returning TRUE if a match is found or FALSE if not.  This
        !             7:   version is specifically for use with unzip.c:  as did the previous match()
        !             8:   from SEA, it leaves the case (upper, lower, or mixed) of the string alone,
        !             9:   but converts any uppercase characters in the pattern to lowercase if indi-
        !            10:   cated by the global var pInfo->lcflag (which is to say, string is assumed
        !            11:   to have been converted to lowercase already, if such was necessary).
        !            12: 
        !            13:   ---------------------------------------------------------------------------*/
        !            14: 
        !            15: 
        !            16: #ifdef ZIPINFO
        !            17: #  undef ZIPINFO   /* make certain there is only one version of match.o */
        !            18: #endif /* ZIPINFO */
        !            19: #include "unzip.h"
        !            20: 
        !            21: static int  matche              __((register char *p, register char *t));
        !            22: static int  matche_after_star   __((register char *p, register char *t));
        !            23: 
        !            24: /* #include "filmatch.h": */
        !            25: #ifndef BOOLEAN
        !            26: #  define BOOLEAN short int      /* v1.2 made it short */
        !            27: #endif
        !            28: 
        !            29: /* match defines */
        !            30: #define MATCH_PATTERN  6    /* bad pattern */
        !            31: #define MATCH_LITERAL  5    /* match failure on literal match */
        !            32: #define MATCH_RANGE    4    /* match failure on [..] construct */
        !            33: #define MATCH_ABORT    3    /* premature end of text string */
        !            34: #define MATCH_END      2    /* premature end of pattern string */
        !            35: #define MATCH_VALID    1    /* valid match */
        !            36: 
        !            37: /* pattern defines */
        !            38: #define PATTERN_VALID  0    /* valid pattern */
        !            39: #define PATTERN_ESC   -1    /* literal escape at end of pattern */
        !            40: #define PATTERN_RANGE -2    /* malformed range in [..] construct */
        !            41: #define PATTERN_CLOSE -3    /* no end bracket in [..] construct */
        !            42: #define PATTERN_EMPTY -4    /* [..] contstruct is empty */
        !            43: 
        !            44: /*----------------------------------------------------------------------------
        !            45: *
        !            46: *  Match the pattern PATTERN against the string TEXT;
        !            47: *
        !            48: *       match() returns TRUE if pattern matches, FALSE otherwise.
        !            49: *       matche() returns MATCH_VALID if pattern matches, or an errorcode
        !            50: *           as follows otherwise:
        !            51: *
        !            52: *            MATCH_PATTERN  - bad pattern
        !            53: *            MATCH_RANGE    - match failure on [..] construct
        !            54: *            MATCH_ABORT    - premature end of text string
        !            55: *            MATCH_END      - premature end of pattern string
        !            56: *            MATCH_VALID    - valid match
        !            57: *
        !            58: *
        !            59: *  A match means the entire string TEXT is used up in matching.
        !            60: *
        !            61: *  In the pattern string:
        !            62: *       `*' matches any sequence of characters (zero or more)
        !            63: *       `?' matches any character
        !            64: *       [SET] matches any character in the specified set,
        !            65: *       [!SET] or [^SET] matches any character not in the specified set.
        !            66: *
        !            67: *  A set is composed of characters or ranges; a range looks like
        !            68: *  character hyphen character (as in 0-9 or A-Z).  [0-9a-zA-Z_] is the
        !            69: *  minimal set of characters allowed in the [..] pattern construct.
        !            70: *  Other characters are allowed (ie. 8 bit characters) if your system
        !            71: *  will support them.
        !            72: *
        !            73: *  To suppress the special syntactic significance of any of `[]*?!^-\',
        !            74: *  in a [..] construct and match the character exactly, precede it
        !            75: *  with a `\'.
        !            76: *
        !            77: ----------------------------------------------------------------------------*/
        !            78: 
        !            79: /*----------------------------------------------------------------------------
        !            80: *
        !            81: *  Match the pattern PATTERN against the string TEXT;
        !            82: *
        !            83: *  returns MATCH_VALID if pattern matches, or an errorcode as follows
        !            84: *  otherwise:
        !            85: *
        !            86: *            MATCH_PATTERN  - bad pattern
        !            87: *            MATCH_RANGE    - match failure on [..] construct
        !            88: *            MATCH_ABORT    - premature end of text string
        !            89: *            MATCH_END      - premature end of pattern string
        !            90: *            MATCH_VALID    - valid match
        !            91: *
        !            92: *
        !            93: *  A match means the entire string TEXT is used up in matching.
        !            94: *
        !            95: *  In the pattern string:
        !            96: *       `*' matches any sequence of characters (zero or more)
        !            97: *       `?' matches any character
        !            98: *       [SET] matches any character in the specified set,
        !            99: *       [!SET] or [^SET] matches any character not in the specified set.
        !           100: *       \ is allowed within a set to escape a character like ']' or '-'
        !           101: *
        !           102: *  A set is composed of characters or ranges; a range looks like
        !           103: *  character hyphen character (as in 0-9 or A-Z).  [0-9a-zA-Z_] is the
        !           104: *  minimal set of characters allowed in the [..] pattern construct.
        !           105: *  Other characters are allowed (ie. 8 bit characters) if your system
        !           106: *  will support them.
        !           107: *
        !           108: *  To suppress the special syntactic significance of any of `[]*?!^-\',
        !           109: *  within a [..] construct and match the character exactly, precede it
        !           110: *  with a `\'.
        !           111: *
        !           112: ----------------------------------------------------------------------------*/
        !           113: 
        !           114: static int matche(p, t)
        !           115: register char *p;
        !           116: register char *t;
        !           117: {
        !           118:     register char range_start, range_end;  /* start and end in range */
        !           119: 
        !           120:     BOOLEAN invert;             /* is this [..] or [!..] */
        !           121:     BOOLEAN member_match;       /* have I matched the [..] construct? */
        !           122:     BOOLEAN loop;               /* should I terminate? */
        !           123: 
        !           124:     for (;  *p;  p++, t++) {
        !           125: 
        !           126:         /* if this is the end of the text then this is the end of the match */
        !           127:         if (!*t)
        !           128:             return ((*p == '*') && (*++p == '\0'))?  MATCH_VALID : MATCH_ABORT;
        !           129: 
        !           130:         /* determine and react to pattern type */
        !           131:         switch (*p) {
        !           132: 
        !           133:             /* single any character match */
        !           134:             case '?':
        !           135:                 break;
        !           136: 
        !           137:             /* multiple any character match */
        !           138:             case '*':
        !           139:                 return matche_after_star (p, t);
        !           140: 
        !           141:             /* [..] construct, single member/exclusion character match */
        !           142:             case '[': {
        !           143: 
        !           144:                 /* move to beginning of range */
        !           145:                 p++;
        !           146: 
        !           147:                 /* check if this is a member match or exclusion match */
        !           148:                 invert = FALSE;
        !           149:                 if ((*p == '!') || (*p == '^')) {
        !           150:                     invert = TRUE;
        !           151:                     p++;
        !           152:                 }
        !           153: 
        !           154:                 /* if closing bracket here or at range start then we have a
        !           155:                    malformed pattern */
        !           156:                 if (*p == ']')
        !           157:                     return MATCH_PATTERN;
        !           158: 
        !           159:                 member_match = FALSE;
        !           160:                 loop = TRUE;
        !           161: 
        !           162:                 while (loop) {
        !           163: 
        !           164:                     /* if end of construct then loop is done */
        !           165:                     if (*p == ']') {
        !           166:                         loop = FALSE;
        !           167:                         continue;
        !           168:                     }
        !           169: 
        !           170:                     /* matching a '!', '^', '-', '\' or a ']' */
        !           171:                     if (*p == '\\')
        !           172:                         range_start = range_end = *++p;
        !           173:                     else
        !           174:                         range_start = range_end = *p;
        !           175: 
        !           176:                     /* if end of pattern then bad pattern (Missing ']') */
        !           177:                     if (!*p)
        !           178:                         return MATCH_PATTERN;
        !           179: 
        !           180:                     /* check for range bar */
        !           181:                     if (*++p == '-') {
        !           182: 
        !           183:                         /* get the range end */
        !           184:                         range_end = *++p;
        !           185: 
        !           186:                         /* if end of pattern or construct then bad pattern */
        !           187:                         if ((range_end == '\0') || (range_end == ']'))
        !           188:                             return MATCH_PATTERN;
        !           189: 
        !           190:                         /* special character range end */
        !           191:                         if (range_end == '\\') {
        !           192:                             range_end = *++p;
        !           193: 
        !           194:                             /* if end of text then we have a bad pattern */
        !           195:                             if (!range_end)
        !           196:                                 return MATCH_PATTERN;
        !           197:                         }
        !           198: 
        !           199:                         /* move just beyond this range */
        !           200:                         p++;
        !           201:                     }
        !           202: 
        !           203:                     /* if the text character is in range then match found.
        !           204:                      * make sure the range letters have the proper
        !           205:                      * relationship to one another before comparison
        !           206:                      */
        !           207:                     if (range_start < range_end) {
        !           208:                         if ((*t >= range_start) && (*t <= range_end)) {
        !           209:                             member_match = TRUE;
        !           210:                             loop = FALSE;
        !           211:                         }
        !           212:                     } else {
        !           213:                         if ((*t >= range_end) && (*t <= range_start)) {
        !           214:                             member_match = TRUE;
        !           215:                             loop = FALSE;
        !           216:                         }
        !           217:                     }
        !           218:                 }
        !           219: 
        !           220:                 /* if there was a match in an exclusion set then no match */
        !           221:                 /* if there was no match in a member set then no match */
        !           222:                 if ((invert && member_match) ||
        !           223:                    !(invert || member_match))
        !           224:                     return MATCH_RANGE;
        !           225: 
        !           226:                 /* if this is not an exclusion then skip the rest of the [...]
        !           227:                     construct that already matched. */
        !           228:                 if (member_match) {
        !           229:                     while (*p != ']') {
        !           230: 
        !           231:                         /* bad pattern (Missing ']') */
        !           232:                         if (!*p)
        !           233:                             return MATCH_PATTERN;
        !           234: 
        !           235:                         /* skip exact match */
        !           236:                         if (*p == '\\') {
        !           237:                             p++;
        !           238: 
        !           239:                             /* if end of text then we have a bad pattern */
        !           240:                             if (!*p)
        !           241:                                 return MATCH_PATTERN;
        !           242:                         }
        !           243: 
        !           244:                         /* move to next pattern char */
        !           245:                         p++;
        !           246:                     }
        !           247:                 }
        !           248: 
        !           249:                 break;
        !           250:             }  /* switch '[' */
        !           251: 
        !           252:             /* must match this character exactly */
        !           253:             default:
        !           254: #ifdef OLDSTUFF
        !           255:                 if (*p != *t)
        !           256: #else /* !OLDSTUFF */
        !           257:                 /* do it like arcmatch() (old unzip) did it (v1.2) */
        !           258:                 if (*t != (char) ((pInfo->lcflag && isupper((int)(*p)))?
        !           259:                     tolower((int)(*p)) : *p))
        !           260: #endif /* ?OLDSTUFF */
        !           261:                     return MATCH_LITERAL;
        !           262: 
        !           263:         }  /* switch */
        !           264:     }  /* for */
        !           265: 
        !           266:         /* if end of text not reached then the pattern fails */
        !           267:     if (*t)
        !           268:         return MATCH_END;
        !           269:     else
        !           270:         return MATCH_VALID;
        !           271: }
        !           272: 
        !           273: 
        !           274: /*----------------------------------------------------------------------------
        !           275: *
        !           276: * recursively call matche() with final segment of PATTERN and of TEXT.
        !           277: *
        !           278: ----------------------------------------------------------------------------*/
        !           279: 
        !           280: static int matche_after_star (p,t)
        !           281: register char *p;
        !           282: register char *t;
        !           283: {
        !           284:     register int match = 0;
        !           285:     register int nextp;
        !           286: 
        !           287:     /* pass over existing ? and * in pattern */
        !           288:     while ((*p == '?') || (*p == '*')) {
        !           289: 
        !           290:         /* take one char for each ? and +; if end of text then no match */
        !           291:         if ((*p == '?') && (!*t++))
        !           292:                 return MATCH_ABORT;
        !           293: 
        !           294:         /* move to next char in pattern */
        !           295:         p++;
        !           296:     }
        !           297: 
        !           298:     /* if end of pattern we have matched regardless of text left */
        !           299:     if (!*p)
        !           300:         return MATCH_VALID;
        !           301: 
        !           302:     /* get the next character to match which must be a literal or '[' */
        !           303:     nextp = *p;
        !           304: 
        !           305:     /* Continue until we run out of text or definite result seen */
        !           306:     do {
        !           307:         /* a precondition for matching is that the next character
        !           308:          * in the pattern match the next character in the text or that
        !           309:          * the next pattern char is the beginning of a range.  Increment
        !           310:          * text pointer as we go here.
        !           311:          */
        !           312:         if ((nextp == *t) || (nextp == '['))
        !           313:             match = matche(p, t);
        !           314: 
        !           315:         /* if the end of text is reached then no match */
        !           316:         if (!*t++)
        !           317:             match = MATCH_ABORT;
        !           318: 
        !           319:     } while ((match != MATCH_VALID) &&
        !           320:              (match != MATCH_ABORT) &&
        !           321:              (match != MATCH_PATTERN));
        !           322: 
        !           323:     /* return result */
        !           324:     return match;
        !           325: }
        !           326: 
        !           327: 
        !           328: /*----------------------------------------------------------------------------
        !           329: *
        !           330: * match() is a shell to matche() to return only BOOLEAN values.
        !           331: *
        !           332: ----------------------------------------------------------------------------*/
        !           333: 
        !           334: int match(string,pattern)
        !           335: char *string;
        !           336: char *pattern;
        !           337: {
        !           338:     int error_type;
        !           339:     error_type = matche(pattern,string);
        !           340:     return (error_type == MATCH_VALID ) ? TRUE : FALSE;
        !           341: }
        !           342: 
        !           343: 
        !           344: #ifdef TEST_MATCH
        !           345: 
        !           346: /*----------------------------------------------------------------------------
        !           347: *
        !           348: * Return TRUE if PATTERN has any special wildcard characters
        !           349: *
        !           350: ----------------------------------------------------------------------------*/
        !           351: 
        !           352: BOOLEAN is_pattern (char *pattern);
        !           353: 
        !           354: /*----------------------------------------------------------------------------
        !           355: *
        !           356: * Return TRUE if PATTERN has is a well formed regular expression according
        !           357: * to the above syntax
        !           358: *
        !           359: * error_type is a return code based on the type of pattern error.  Zero is
        !           360: * returned in error_type if the pattern is a valid one.  error_type return
        !           361: * values are as follows:
        !           362: *
        !           363: *   PATTERN_VALID - pattern is well formed
        !           364: *   PATTERN_RANGE - [..] construct has a no end range in a '-' pair (ie [a-])
        !           365: *   PATTERN_CLOSE - [..] construct has no end bracket (ie [abc-g )
        !           366: *   PATTERN_EMPTY - [..] construct is empty (ie [])
        !           367: *
        !           368: ----------------------------------------------------------------------------*/
        !           369: 
        !           370: BOOLEAN is_valid_pattern (char *pattern, int *error_type);
        !           371: int fast_match_after_star (register char *pattern, register char *text);
        !           372: 
        !           373: /*----------------------------------------------------------------------------
        !           374: *
        !           375: * Return TRUE if PATTERN has any special wildcard characters
        !           376: *
        !           377: ----------------------------------------------------------------------------*/
        !           378: 
        !           379: BOOLEAN is_pattern (char *p)
        !           380: {
        !           381:     while (*p)
        !           382:         switch (*p++) {
        !           383:             case '?':
        !           384:             case '*':
        !           385:             case '[':
        !           386:                 return TRUE;
        !           387:         }
        !           388:     return FALSE;
        !           389: }
        !           390: 
        !           391: 
        !           392: /*----------------------------------------------------------------------------
        !           393: *
        !           394: * Return TRUE if PATTERN has is a well formed regular expression according
        !           395: * to the above syntax
        !           396: *
        !           397: * error_type is a return code based on the type of pattern error.  Zero is
        !           398: * returned in error_type if the pattern is a valid one.  error_type return
        !           399: * values are as follows:
        !           400: *
        !           401: *   PATTERN_VALID - pattern is well formed
        !           402: *   PATTERN_RANGE - [..] construct has a no end range in a '-' pair (ie [a-])
        !           403: *   PATTERN_CLOSE - [..] construct has no end bracket (ie [abc-g )
        !           404: *   PATTERN_EMPTY - [..] construct is empty (ie [])
        !           405: *
        !           406: ----------------------------------------------------------------------------*/
        !           407: 
        !           408: BOOLEAN is_valid_pattern (char *p, int *error_type)
        !           409: {
        !           410:     /* init error_type */
        !           411:     *error_type = PATTERN_VALID;
        !           412: 
        !           413:     /* loop through pattern to EOS */
        !           414:     while (*p) {
        !           415: 
        !           416:         /* determine pattern type */
        !           417:         switch (*p) {
        !           418: 
        !           419:             /* the [..] construct must be well formed */
        !           420:             case '[':
        !           421:                 p++;
        !           422: 
        !           423:                 /* if the next character is ']' then bad pattern */
        !           424:                 if (*p == ']') {
        !           425:                     *error_type = PATTERN_EMPTY;
        !           426:                     return FALSE;
        !           427:                 }
        !           428: 
        !           429:                 /* if end of pattern here then bad pattern */
        !           430:                 if (!*p) {
        !           431:                     *error_type = PATTERN_CLOSE;
        !           432:                     return FALSE;
        !           433:                 }
        !           434: 
        !           435:                 /* loop to end of [..] construct */
        !           436:                 while (*p != ']') {
        !           437: 
        !           438:                     /* check for literal escape */
        !           439:                     if (*p == '\\') {
        !           440:                         p++;
        !           441: 
        !           442:                         /* if end of pattern here then bad pattern */
        !           443:                         if (!*p++) {
        !           444:                             *error_type = PATTERN_ESC;
        !           445:                             return FALSE;
        !           446:                         }
        !           447:                     } else
        !           448:                         p++;
        !           449: 
        !           450:                     /* if end of pattern here then bad pattern */
        !           451:                     if (!*p) {
        !           452:                         *error_type = PATTERN_CLOSE;
        !           453:                         return FALSE;
        !           454:                     }
        !           455: 
        !           456:                     /* if this a range */
        !           457:                     if (*p == '-') {
        !           458: 
        !           459:                         /* we must have an end of range */
        !           460:                         if (!*++p || (*p == ']')) {
        !           461:                             *error_type = PATTERN_RANGE;
        !           462:                             return FALSE;
        !           463:                         } else {
        !           464: 
        !           465:                             /* check for literal escape */
        !           466:                             if (*p == '\\')
        !           467:                                 p++;
        !           468: 
        !           469:                             /* if end of pattern here then bad pattern */
        !           470:                             if (!*p++) {
        !           471:                                 *error_type = PATTERN_ESC;
        !           472:                                 return FALSE;
        !           473:                             }
        !           474:                         }
        !           475:                     }
        !           476:                 }
        !           477:                 break;
        !           478: 
        !           479:             /* all other characters are valid pattern elements */
        !           480:             case '*':
        !           481:             case '?':
        !           482:             default:
        !           483:                 p++;                /* "normal" character */
        !           484:                 break;
        !           485:         }    /* switch */
        !           486:     }
        !           487: 
        !           488:     return TRUE;
        !           489: }
        !           490: 
        !           491: 
        !           492:     /*
        !           493:     * This test main expects as first arg the pattern and as second arg
        !           494:     * the match string.  Output is yay or nay on match.  If nay on
        !           495:     * match then the error code is parsed and written.
        !           496:     */
        !           497: 
        !           498: #include <stdio.h>
        !           499: 
        !           500: int main(int argc, char *argv[])
        !           501: {
        !           502:     int error;
        !           503:     int is_valid_error;
        !           504: 
        !           505:     if (argc != 3)
        !           506:         printf("Usage:  MATCH Pattern Text\n");
        !           507:     else {
        !           508:         printf("Pattern: %s\n", argv[1]);
        !           509:         printf("Text   : %s\n", argv[2]);
        !           510: 
        !           511:         if (!is_pattern(argv[1]))
        !           512:             printf("    First Argument Is Not A Pattern\n");
        !           513:         else {
        !           514:             match(argv[1],argv[2]) ? printf("TRUE") : printf("FALSE");
        !           515:             error = matche(argv[1],argv[2]);
        !           516:             is_valid_pattern(argv[1],&is_valid_error);
        !           517: 
        !           518:             switch (error) {
        !           519:                 case MATCH_VALID:
        !           520:                     printf("    Match Successful");
        !           521:                     if (is_valid_error != PATTERN_VALID)
        !           522:                         printf(" -- is_valid_pattern() is complaining\n");
        !           523:                     else
        !           524:                         printf("\n");
        !           525:                     break;
        !           526:                 case MATCH_RANGE:
        !           527:                     printf("    Match Failed on [..]\n");
        !           528:                     break;
        !           529:                 case MATCH_ABORT:
        !           530:                     printf("    Match Failed on Early Text Termination\n");
        !           531:                     break;
        !           532:                 case MATCH_END:
        !           533:                     printf("    Match Failed on Early Pattern Termination\n");
        !           534:                     break;
        !           535:                 case MATCH_PATTERN:
        !           536:                     switch (is_valid_error) {
        !           537:                         case PATTERN_VALID:
        !           538:                             printf("    Internal Disagreement On Pattern\n");
        !           539:                             break;
        !           540:                         case PATTERN_RANGE:
        !           541:                             printf("    No End of Range in [..] Construct\n");
        !           542:                             break;
        !           543:                         case PATTERN_CLOSE:
        !           544:                             printf("    [..] Construct is Open\n");
        !           545:                             break;
        !           546:                         case PATTERN_EMPTY:
        !           547:                             printf("    [..] Construct is Empty\n");
        !           548:                             break;
        !           549:                         default:
        !           550:                             printf("    Internal Error in is_valid_pattern()\n");
        !           551:                     }
        !           552:                     break;
        !           553:                 default:
        !           554:                     printf("    Internal Error in matche()\n");
        !           555:                     break;
        !           556:             } /* switch */
        !           557:         }
        !           558: 
        !           559:     }
        !           560:     return(0);
        !           561: }
        !           562: 
        !           563: #endif  /* TEST_MATCH */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.