Back to index

glibc  2.9
tst-fnmatch.c
Go to the documentation of this file.
00001 /* Tests for fnmatch function.
00002    Copyright (C) 2000, 2001 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <error.h>
00022 #include <fnmatch.h>
00023 #include <locale.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <sys/types.h>
00028 
00029 
00030 static char *next_input (char **line, int first, int last);
00031 static int convert_flags (const char *str);
00032 static char *flag_output (int flags);
00033 static char *escape (const char *str, size_t *reslenp, char **resbuf);
00034 
00035 
00036 int
00037 main (void)
00038 {
00039   char *linebuf = NULL;
00040   size_t linebuflen = 0;
00041   int ntests = 0;
00042   int nfailed = 0;
00043   char *escinput = NULL;
00044   size_t escinputlen = 0;
00045   char *escpattern = NULL;
00046   size_t escpatternlen = 0;
00047   int nr = 0;
00048 
00049   /* Read lines from stdin with the following format:
00050 
00051        locale  input-string  match-string  flags  result
00052 
00053      where `result' is either 0 or 1.  If the first character of a
00054      string is '"' we read until the next '"' and handled escaped '"'.  */
00055   while (! feof (stdin))
00056     {
00057       ssize_t n = getline (&linebuf, &linebuflen, stdin);
00058       char *cp;
00059       const char *locale;
00060       const char *input;
00061       const char *pattern;
00062       const char *result_str;
00063       int result;
00064       const char *flags;
00065       int flags_val;
00066       int fnmres;
00067       char numbuf[24];
00068 
00069       if (n == -1)
00070        break;
00071 
00072       if (n == 0)
00073        /* Maybe an empty line.  */
00074        continue;
00075 
00076       /* Skip over all leading white spaces.  */
00077       cp = linebuf;
00078 
00079       locale = next_input (&cp, 1, 0);
00080       if (locale == NULL)
00081        continue;
00082 
00083       input = next_input (&cp, 0, 0);
00084       if (input == NULL)
00085        continue;
00086 
00087       pattern = next_input (&cp, 0, 0);
00088       if (pattern == NULL)
00089        continue;
00090 
00091       result_str = next_input (&cp, 0, 0);
00092       if (result_str == NULL)
00093        continue;
00094 
00095       if (strcmp (result_str, "0") == 0)
00096        result = 0;
00097       else if  (strcasecmp (result_str, "NOMATCH") == 0)
00098        result = FNM_NOMATCH;
00099       else
00100        {
00101          char *endp;
00102          result = strtol (result_str, &endp, 0);
00103          if (*endp != '\0')
00104            continue;
00105        }
00106 
00107       flags = next_input (&cp, 0, 1);
00108       if (flags == NULL)
00109        /* We allow the flags missing.  */
00110        flags = "";
00111 
00112       /* Convert the text describing the flags in a numeric value.  */
00113       flags_val = convert_flags (flags);
00114       if (flags_val == -1)
00115        /* Something went wrong.  */
00116        continue;
00117 
00118       /* Now run the actual test.  */
00119       ++ntests;
00120 
00121       if (setlocale (LC_COLLATE, locale) == NULL
00122          || setlocale (LC_CTYPE, locale) == NULL)
00123        {
00124          puts ("*** Cannot set locale");
00125          ++nfailed;
00126          continue;
00127        }
00128 
00129       fnmres = fnmatch (pattern, input, flags_val);
00130 
00131       printf ("%3d: fnmatch (\"%s\", \"%s\", %s) = %s%c",
00132              ++nr,
00133              escape (pattern, &escpatternlen, &escpattern),
00134              escape (input, &escinputlen, &escinput),
00135              flag_output (flags_val),
00136              (fnmres == 0
00137               ? "0" : (fnmres == FNM_NOMATCH
00138                      ? "FNM_NOMATCH"
00139                      : (sprintf (numbuf, "%d", fnmres), numbuf))),
00140              (fnmres != 0) != (result != 0) ? ' ' : '\n');
00141 
00142       if ((fnmres != 0) != (result != 0))
00143        {
00144          printf ("(FAIL, expected %s) ***\n",
00145                 result == 0
00146                 ? "0" : (result == FNM_NOMATCH
00147                         ? "FNM_NOMATCH"
00148                         : (sprintf (numbuf, "%d", result), numbuf)));
00149          ++nfailed;
00150        }
00151     }
00152 
00153   printf ("=====================\n%3d tests, %3d failed\n", ntests, nfailed);
00154 
00155   free (escpattern);
00156   free (escinput);
00157   free (linebuf);
00158 
00159   return nfailed != 0;
00160 }
00161 
00162 
00163 static char *
00164 next_input (char **line, int first, int last)
00165 {
00166   char *cp = *line;
00167   char *result;
00168 
00169   while (*cp == ' ' || *cp == '\t')
00170     ++cp;
00171 
00172   /* We allow comment lines starting with '#'.  */
00173   if (first && *cp == '#')
00174     return NULL;
00175 
00176   if (*cp == '"')
00177     {
00178       char *wp;
00179 
00180       result = ++cp;
00181       wp = cp;
00182 
00183       while (*cp != '"' && *cp != '\0' && *cp != '\n')
00184        if (*cp == '\\')
00185          {
00186            if (cp[1] == '\n' || cp[1] == '\0')
00187              return NULL;
00188 
00189            ++cp;
00190            if (*cp == 't')
00191              *wp++ = '\t';
00192            else if (*cp == 'n')
00193              *wp++ = '\n';
00194            else
00195              *wp++ = *cp;
00196 
00197            ++cp;
00198          }
00199        else
00200          *wp++ = *cp++;
00201 
00202       if (*cp != '"')
00203        return NULL;
00204 
00205       if (wp != cp)
00206        *wp = '\0';
00207     }
00208   else
00209     {
00210       result = cp;
00211       while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t')
00212        ++cp;
00213 
00214       if (cp == result && ! last)
00215        /* Premature end of line.  */
00216        return NULL;
00217     }
00218 
00219   /* Terminate and skip over the next white spaces.  */
00220   *cp++ = '\0';
00221 
00222   *line = cp;
00223   return result;
00224 }
00225 
00226 
00227 static int
00228 convert_flags (const char *str)
00229 {
00230   int result = 0;
00231 
00232   while (*str != '\0')
00233     {
00234       int len;
00235 
00236       if (strncasecmp (str, "PATHNAME", 8) == 0
00237          && (str[8] == '|' || str[8] == '\0'))
00238        {
00239          result |= FNM_PATHNAME;
00240          len = 8;
00241        }
00242       else if (strncasecmp (str, "NOESCAPE", 8) == 0
00243               && (str[8] == '|' || str[8] == '\0'))
00244        {
00245          result |= FNM_NOESCAPE;
00246          len = 8;
00247        }
00248       else if (strncasecmp (str, "PERIOD", 6) == 0
00249               && (str[6] == '|' || str[6] == '\0'))
00250        {
00251          result |= FNM_PERIOD;
00252          len = 6;
00253        }
00254       else if (strncasecmp (str, "LEADING_DIR", 11) == 0
00255               && (str[11] == '|' || str[11] == '\0'))
00256        {
00257          result |= FNM_LEADING_DIR;
00258          len = 11;
00259        }
00260       else if (strncasecmp (str, "CASEFOLD", 8) == 0
00261               && (str[8] == '|' || str[8] == '\0'))
00262        {
00263          result |= FNM_CASEFOLD;
00264          len = 8;
00265        }
00266       else if (strncasecmp (str, "EXTMATCH", 8) == 0
00267               && (str[8] == '|' || str[8] == '\0'))
00268        {
00269          result |= FNM_EXTMATCH;
00270          len = 8;
00271        }
00272       else
00273        return -1;
00274 
00275       str += len;
00276       if (*str != '\0')
00277        ++str;
00278     }
00279 
00280   return result;
00281 }
00282 
00283 
00284 static char *
00285 flag_output (int flags)
00286 {
00287   static char buf[100];
00288   int first = 1;
00289   char *cp = buf;
00290 
00291   if (flags & FNM_PATHNAME)
00292     {
00293       cp = stpcpy (cp, "FNM_PATHNAME");
00294       first = 0;
00295     }
00296   if (flags & FNM_NOESCAPE)
00297     {
00298       if (! first)
00299        *cp++ = '|';
00300       cp = stpcpy (cp, "FNM_NOESCAPE");
00301       first = 0;
00302     }
00303   if (flags & FNM_PERIOD)
00304     {
00305       if (! first)
00306        *cp++ = '|';
00307       cp = stpcpy (cp, "FNM_PERIOD");
00308       first = 0;
00309     }
00310   if (flags & FNM_LEADING_DIR)
00311     {
00312       if (! first)
00313        *cp++ = '|';
00314       cp = stpcpy (cp, "FNM_LEADING_DIR");
00315       first = 0;
00316     }
00317   if (flags & FNM_CASEFOLD)
00318     {
00319       if (! first)
00320        *cp++ = '|';
00321       cp = stpcpy (cp, "FNM_CASEFOLD");
00322       first = 0;
00323     }
00324   if (flags & FNM_EXTMATCH)
00325     {
00326       if (! first)
00327        *cp++ = '|';
00328       cp = stpcpy (cp, "FNM_EXTMATCH");
00329       first = 0;
00330     }
00331   if (cp == buf)
00332     *cp++ = '0';
00333   *cp = '\0';
00334 
00335   return buf;
00336 }
00337 
00338 
00339 static char *
00340 escape (const char *str, size_t *reslenp, char **resbufp)
00341 {
00342   size_t reslen = *reslenp;
00343   char *resbuf = *resbufp;
00344   size_t len = strlen (str);
00345   char *wp;
00346 
00347   if (2 * len + 1 > reslen)
00348     {
00349       resbuf = (char *) realloc (resbuf, 2 * len + 1);
00350       if (resbuf == NULL)
00351        error (EXIT_FAILURE, errno, "while allocating buffer for printing");
00352       *reslenp = 2 * len + 1;
00353       *resbufp = resbuf;
00354     }
00355 
00356   wp = resbuf;
00357   while (*str != '\0')
00358     if (*str == '\t')
00359       {
00360        *wp++ = '\\';
00361        *wp++ = 't';
00362        ++str;
00363       }
00364     else if (*str == '\n')
00365       {
00366        *wp++ = '\\';
00367        *wp++ = 'n';
00368        ++str;
00369       }
00370     else if (*str == '"')
00371       {
00372        *wp++ = '\\';
00373        *wp++ = '"';
00374        ++str;
00375       }
00376     else if (*str == '\\')
00377       {
00378        *wp++ = '\\';
00379        *wp++ = '\\';
00380        ++str;
00381       }
00382     else
00383       *wp++ = *str++;
00384 
00385   *wp = '\0';
00386 
00387   return resbuf;
00388 }