File:  [gforth] / gforth / engine / fnmatch.c
Revision 1.1: download - view: text, annotated - select for diffs
Sat Jul 1 20:48:53 2000 UTC (21 years, 10 months ago) by anton
Branches: MAIN
CVS tags: HEAD
added fnmatch replacement and configure stuff
enhanced portability of gforthmi
the disassembler now works on MIPS (+ assorted bugfixes)

    1: /* Copyright (C) 1991-1993, 1996-1999, 2000 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3: 
    4:    This library is free software; you can redistribute it and/or
    5:    modify it under the terms of the GNU Library General Public License as
    6:    published by the Free Software Foundation; either version 2 of the
    7:    License, or (at your option) any later version.
    8: 
    9:    This library is distributed in the hope that it will be useful,
   10:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12:    Library General Public License for more details.
   13: 
   14:    You should have received a copy of the GNU Library General Public
   15:    License along with this library; see the file COPYING.LIB.  If not,
   16:    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   17:    Boston, MA 02111-1307, USA.  */
   18: 
   19: #if HAVE_CONFIG_H
   20: # include <config.h>
   21: #endif
   22: 
   23: /* Enable GNU extensions in fnmatch.h.  */
   24: #ifndef _GNU_SOURCE
   25: # define _GNU_SOURCE	1
   26: #endif
   27: 
   28: #include <errno.h>
   29: #include <fnmatch.h>
   30: #include <ctype.h>
   31: 
   32: #if HAVE_STRING_H || defined _LIBC
   33: # include <string.h>
   34: #else
   35: # include <strings.h>
   36: #endif
   37: 
   38: #if defined STDC_HEADERS || defined _LIBC
   39: # include <stdlib.h>
   40: #endif
   41: 
   42: /* For platform which support the ISO C amendement 1 functionality we
   43:    support user defined character classes.  */
   44: #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
   45: /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
   46: # include <wchar.h>
   47: # include <wctype.h>
   48: #endif
   49: 
   50: /* Comment out all this code if we are using the GNU C Library, and are not
   51:    actually compiling the library itself.  This code is part of the GNU C
   52:    Library, but also included in many other GNU distributions.  Compiling
   53:    and linking in this code is a waste when using the GNU C library
   54:    (especially if it is a shared library).  Rather than having every GNU
   55:    program understand `configure --with-gnu-libc' and omit the object files,
   56:    it is simpler to just do this in the source for each such file.  */
   57: 
   58: #if defined _LIBC || !defined __GNU_LIBRARY__
   59: 
   60: 
   61: # if defined STDC_HEADERS || !defined isascii
   62: #  define ISASCII(c) 1
   63: # else
   64: #  define ISASCII(c) isascii(c)
   65: # endif
   66: 
   67: #ifdef isblank
   68: # define ISBLANK(c) (ISASCII (c) && isblank (c))
   69: #else
   70: # define ISBLANK(c) ((c) == ' ' || (c) == '\t')
   71: #endif
   72: #ifdef isgraph
   73: # define ISGRAPH(c) (ISASCII (c) && isgraph (c))
   74: #else
   75: # define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
   76: #endif
   77: 
   78: #define ISPRINT(c) (ISASCII (c) && isprint (c))
   79: #define ISDIGIT(c) (ISASCII (c) && isdigit (c))
   80: #define ISALNUM(c) (ISASCII (c) && isalnum (c))
   81: #define ISALPHA(c) (ISASCII (c) && isalpha (c))
   82: #define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
   83: #define ISLOWER(c) (ISASCII (c) && islower (c))
   84: #define ISPUNCT(c) (ISASCII (c) && ispunct (c))
   85: #define ISSPACE(c) (ISASCII (c) && isspace (c))
   86: #define ISUPPER(c) (ISASCII (c) && isupper (c))
   87: #define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
   88: 
   89: # define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
   90: 
   91: # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
   92: /* The GNU C library provides support for user-defined character classes
   93:    and the functions from ISO C amendement 1.  */
   94: #  ifdef CHARCLASS_NAME_MAX
   95: #   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
   96: #  else
   97: /* This shouldn't happen but some implementation might still have this
   98:    problem.  Use a reasonable default value.  */
   99: #   define CHAR_CLASS_MAX_LENGTH 256
  100: #  endif
  101: 
  102: #  ifdef _LIBC
  103: #   define IS_CHAR_CLASS(string) __wctype (string)
  104: #  else
  105: #   define IS_CHAR_CLASS(string) wctype (string)
  106: #  endif
  107: # else
  108: #  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
  109: 
  110: #  define IS_CHAR_CLASS(string)						      \
  111:    (STREQ (string, "alpha") || STREQ (string, "upper")			      \
  112:     || STREQ (string, "lower") || STREQ (string, "digit")		      \
  113:     || STREQ (string, "alnum") || STREQ (string, "xdigit")		      \
  114:     || STREQ (string, "space") || STREQ (string, "print")		      \
  115:     || STREQ (string, "punct") || STREQ (string, "graph")		      \
  116:     || STREQ (string, "cntrl") || STREQ (string, "blank"))
  117: # endif
  118: 
  119: /* Avoid depending on library functions or files
  120:    whose names are inconsistent.  */
  121: 
  122: # if !defined _LIBC && !defined getenv
  123: extern char *getenv ();
  124: # endif
  125: 
  126: # ifndef errno
  127: extern int errno;
  128: # endif
  129: 
  130: /* Match STRING against the filename pattern PATTERN, returning zero if
  131:    it matches, nonzero if not.  */
  132: static int
  133: #ifdef _LIBC
  134: internal_function
  135: #endif
  136: internal_fnmatch (const char *pattern, const char *string,
  137: 		  int no_leading_period, int flags)
  138: {
  139:   register const char *p = pattern, *n = string;
  140:   register unsigned char c;
  141: 
  142: /* Note that this evaluates C many times.  */
  143: # ifdef _LIBC
  144: #  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
  145: # else
  146: #  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
  147: # endif
  148: 
  149:   while ((c = *p++) != '\0')
  150:     {
  151:       c = FOLD (c);
  152: 
  153:       switch (c)
  154: 	{
  155: 	case '?':
  156: 	  if (*n == '\0')
  157: 	    return FNM_NOMATCH;
  158: 	  else if (*n == '/' && (flags & FNM_FILE_NAME))
  159: 	    return FNM_NOMATCH;
  160: 	  else if (*n == '.' && no_leading_period
  161: 		   && (n == string
  162: 		       || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
  163: 	    return FNM_NOMATCH;
  164: 	  break;
  165: 
  166: 	case '\\':
  167: 	  if (!(flags & FNM_NOESCAPE))
  168: 	    {
  169: 	      c = *p++;
  170: 	      if (c == '\0')
  171: 		/* Trailing \ loses.  */
  172: 		return FNM_NOMATCH;
  173: 	      c = FOLD (c);
  174: 	    }
  175: 	  if (FOLD ((unsigned char) *n) != c)
  176: 	    return FNM_NOMATCH;
  177: 	  break;
  178: 
  179: 	case '*':
  180: 	  if (*n == '.' && no_leading_period
  181: 	      && (n == string
  182: 		  || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
  183: 	    return FNM_NOMATCH;
  184: 
  185: 	  for (c = *p++; c == '?' || c == '*'; c = *p++)
  186: 	    {
  187: 	      if (*n == '/' && (flags & FNM_FILE_NAME))
  188: 		/* A slash does not match a wildcard under FNM_FILE_NAME.  */
  189: 		return FNM_NOMATCH;
  190: 	      else if (c == '?')
  191: 		{
  192: 		  /* A ? needs to match one character.  */
  193: 		  if (*n == '\0')
  194: 		    /* There isn't another character; no match.  */
  195: 		    return FNM_NOMATCH;
  196: 		  else
  197: 		    /* One character of the string is consumed in matching
  198: 		       this ? wildcard, so *??? won't match if there are
  199: 		       less than three characters.  */
  200: 		    ++n;
  201: 		}
  202: 	    }
  203: 
  204: 	  if (c == '\0')
  205: 	    /* The wildcard(s) is/are the last element of the pattern.
  206: 	       If the name is a file name and contains another slash
  207: 	       this does mean it cannot match.  If the FNM_LEADING_DIR
  208: 	       flag is set and exactly one slash is following, we have
  209: 	       a match.  */
  210: 	    {
  211: 	      int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
  212: 
  213: 	      if (flags & FNM_FILE_NAME)
  214: 		{
  215: 		  const char *slashp = strchr (n, '/');
  216: 
  217: 		  if (flags & FNM_LEADING_DIR)
  218: 		    {
  219: 		      if (slashp != NULL
  220: 			  && strchr (slashp + 1, '/') == NULL)
  221: 			result = 0;
  222: 		    }
  223: 		  else
  224: 		    {
  225: 		      if (slashp == NULL)
  226: 			result = 0;
  227: 		    }
  228: 		}
  229: 
  230: 	      return result;
  231: 	    }
  232: 	  else
  233: 	    {
  234: 	      const char *endp;
  235: 
  236: 	      endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
  237: 
  238: 	      if (c == '[')
  239: 		{
  240: 		  int flags2 = ((flags & FNM_FILE_NAME)
  241: 				? flags : (flags & ~FNM_PERIOD));
  242: 
  243: 		  for (--p; n < endp; ++n)
  244: 		    if (internal_fnmatch (p, n,
  245: 					  (no_leading_period
  246: 					   && (n == string
  247: 					       || (n[-1] == '/'
  248: 						   && (flags
  249: 						       & FNM_FILE_NAME)))),
  250: 					  flags2)
  251: 			== 0)
  252: 		      return 0;
  253: 		}
  254: 	      else if (c == '/' && (flags & FNM_FILE_NAME))
  255: 		{
  256: 		  while (*n != '\0' && *n != '/')
  257: 		    ++n;
  258: 		  if (*n == '/'
  259: 		      && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
  260: 					    flags) == 0))
  261: 		    return 0;
  262: 		}
  263: 	      else
  264: 		{
  265: 		  int flags2 = ((flags & FNM_FILE_NAME)
  266: 				? flags : (flags & ~FNM_PERIOD));
  267: 
  268: 		  if (c == '\\' && !(flags & FNM_NOESCAPE))
  269: 		    c = *p;
  270: 		  c = FOLD (c);
  271: 		  for (--p; n < endp; ++n)
  272: 		    if (FOLD ((unsigned char) *n) == c
  273: 			&& (internal_fnmatch (p, n,
  274: 					      (no_leading_period
  275: 					       && (n == string
  276: 						   || (n[-1] == '/'
  277: 						       && (flags
  278: 							   & FNM_FILE_NAME)))),
  279: 					      flags2) == 0))
  280: 		      return 0;
  281: 		}
  282: 	    }
  283: 
  284: 	  /* If we come here no match is possible with the wildcard.  */
  285: 	  return FNM_NOMATCH;
  286: 
  287: 	case '[':
  288: 	  {
  289: 	    /* Nonzero if the sense of the character class is inverted.  */
  290: 	    static int posixly_correct;
  291: 	    register int not;
  292: 	    char cold;
  293: 
  294: 	    if (posixly_correct == 0)
  295: 	      posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
  296: 
  297: 	    if (*n == '\0')
  298: 	      return FNM_NOMATCH;
  299: 
  300: 	    if (*n == '.' && no_leading_period && (n == string
  301: 						   || (n[-1] == '/'
  302: 						       && (flags
  303: 							   & FNM_FILE_NAME))))
  304: 	      return FNM_NOMATCH;
  305: 
  306: 	    if (*n == '/' && (flags & FNM_FILE_NAME))
  307: 	      /* `/' cannot be matched.  */
  308: 	      return FNM_NOMATCH;
  309: 
  310: 	    not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
  311: 	    if (not)
  312: 	      ++p;
  313: 
  314: 	    c = *p++;
  315: 	    for (;;)
  316: 	      {
  317: 		unsigned char fn = FOLD ((unsigned char) *n);
  318: 
  319: 		if (!(flags & FNM_NOESCAPE) && c == '\\')
  320: 		  {
  321: 		    if (*p == '\0')
  322: 		      return FNM_NOMATCH;
  323: 		    c = FOLD ((unsigned char) *p);
  324: 		    ++p;
  325: 
  326: 		    if (c == fn)
  327: 		      goto matched;
  328: 		  }
  329: 		else if (c == '[' && *p == ':')
  330: 		  {
  331: 		    /* Leave room for the null.  */
  332: 		    char str[CHAR_CLASS_MAX_LENGTH + 1];
  333: 		    size_t c1 = 0;
  334: # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
  335: 		    wctype_t wt;
  336: # endif
  337: 		    const char *startp = p;
  338: 
  339: 		    for (;;)
  340: 		      {
  341: 			if (c1 == CHAR_CLASS_MAX_LENGTH)
  342: 			  /* The name is too long and therefore the pattern
  343: 			     is ill-formed.  */
  344: 			  return FNM_NOMATCH;
  345: 
  346: 			c = *++p;
  347: 			if (c == ':' && p[1] == ']')
  348: 			  {
  349: 			    p += 2;
  350: 			    break;
  351: 			  }
  352: 			if (c < 'a' || c >= 'z')
  353: 			  {
  354: 			    /* This cannot possibly be a character class name.
  355: 			       Match it as a normal range.  */
  356: 			    p = startp;
  357: 			    c = '[';
  358: 			    goto normal_bracket;
  359: 			  }
  360: 			str[c1++] = c;
  361: 		      }
  362: 		    str[c1] = '\0';
  363: 
  364: # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
  365: 		    wt = IS_CHAR_CLASS (str);
  366: 		    if (wt == 0)
  367: 		      /* Invalid character class name.  */
  368: 		      return FNM_NOMATCH;
  369: 
  370: 		    if (__iswctype (__btowc ((unsigned char) *n), wt))
  371: 		      goto matched;
  372: # else
  373: 		    if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
  374: 			|| (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
  375: 			|| (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
  376: 			|| (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
  377: 			|| (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
  378: 			|| (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
  379: 			|| (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
  380: 			|| (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
  381: 			|| (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
  382: 			|| (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
  383: 			|| (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
  384: 			|| (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
  385: 		      goto matched;
  386: # endif
  387: 		  }
  388: 		else if (c == '\0')
  389: 		  /* [ (unterminated) loses.  */
  390: 		  return FNM_NOMATCH;
  391: 		else
  392: 		  {
  393: 		    c = FOLD (c);
  394: 		  normal_bracket:
  395: 		    if (c == fn)
  396: 		      goto matched;
  397: 
  398: 		    cold = c;
  399: 		    c = *p++;
  400: 
  401: 		    if (c == '-' && *p != ']')
  402: 		      {
  403: 			/* It is a range.  */
  404: 			char lo[2];
  405: 			char fc[2];
  406: 			unsigned char cend = *p++;
  407: 			if (!(flags & FNM_NOESCAPE) && cend == '\\')
  408: 			  cend = *p++;
  409: 			if (cend == '\0')
  410: 			  return FNM_NOMATCH;
  411: 
  412: 			lo[0] = cold;
  413: 			lo[1] = '\0';
  414: 			fc[0] = fn;
  415: 			fc[1] = '\0';
  416: 			if (strcoll (lo, fc) <= 0)
  417: 			  {
  418: 			    char hi[2];
  419: 			    hi[0] = FOLD (cend);
  420: 			    hi[1] = '\0';
  421: 			    if (strcoll (fc, hi) <= 0)
  422: 			      goto matched;
  423: 			  }
  424: 
  425: 			c = *p++;
  426: 		      }
  427: 		  }
  428: 
  429: 		if (c == ']')
  430: 		  break;
  431: 	      }
  432: 
  433: 	    if (!not)
  434: 	      return FNM_NOMATCH;
  435: 	    break;
  436: 
  437: 	  matched:
  438: 	    /* Skip the rest of the [...] that already matched.  */
  439: 	    while (c != ']')
  440: 	      {
  441: 		if (c == '\0')
  442: 		  /* [... (unterminated) loses.  */
  443: 		  return FNM_NOMATCH;
  444: 
  445: 		c = *p++;
  446: 		if (!(flags & FNM_NOESCAPE) && c == '\\')
  447: 		  {
  448: 		    if (*p == '\0')
  449: 		      return FNM_NOMATCH;
  450: 		    /* XXX 1003.2d11 is unclear if this is right.  */
  451: 		    ++p;
  452: 		  }
  453: 		else if (c == '[' && *p == ':')
  454: 		  {
  455: 		    do
  456: 		      if (*++p == '\0')
  457: 			return FNM_NOMATCH;
  458: 		    while (*p != ':' || p[1] == ']');
  459: 		    p += 2;
  460: 		    c = *p;
  461: 		  }
  462: 	      }
  463: 	    if (not)
  464: 	      return FNM_NOMATCH;
  465: 	  }
  466: 	  break;
  467: 
  468: 	default:
  469: 	  if (c != FOLD ((unsigned char) *n))
  470: 	    return FNM_NOMATCH;
  471: 	}
  472: 
  473:       ++n;
  474:     }
  475: 
  476:   if (*n == '\0')
  477:     return 0;
  478: 
  479:   if ((flags & FNM_LEADING_DIR) && *n == '/')
  480:     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
  481:     return 0;
  482: 
  483:   return FNM_NOMATCH;
  484: 
  485: # undef FOLD
  486: }
  487: 
  488: 
  489: int
  490: fnmatch (pattern, string, flags)
  491:      const char *pattern;
  492:      const char *string;
  493:      int flags;
  494: {
  495:   return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
  496: }
  497: 
  498: #endif	/* _LIBC or not __GNU_LIBRARY__.  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>