(root)/
glibc-2.38/
posix/
tst-fnmatch.c
       1  /* Tests for fnmatch function.
       2     Copyright (C) 2000-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <error.h>
      21  #include <fnmatch.h>
      22  #include <locale.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <sys/types.h>
      27  #include <mcheck.h>
      28  
      29  
      30  static char *next_input (char **line, int first, int last);
      31  static int convert_flags (const char *str);
      32  static char *flag_output (int flags);
      33  static char *escape (const char *str, size_t *reslenp, char **resbuf);
      34  
      35  
      36  static int
      37  do_test (void)
      38  {
      39    char *linebuf = NULL;
      40    size_t linebuflen = 0;
      41    int ntests = 0;
      42    int nfailed = 0;
      43    char *escinput = NULL;
      44    size_t escinputlen = 0;
      45    char *escpattern = NULL;
      46    size_t escpatternlen = 0;
      47    int nr = 0;
      48  
      49    mtrace ();
      50  
      51    /* Read lines from stdin with the following format:
      52  
      53         locale  input-string  match-string  flags  result
      54  
      55       where `result' is either 0 or 1.  If the first character of a
      56       string is '"' we read until the next '"' and handled escaped '"'.  */
      57    while (! feof (stdin))
      58      {
      59        ssize_t n = getline (&linebuf, &linebuflen, stdin);
      60        char *cp;
      61        const char *locale;
      62        const char *input;
      63        const char *pattern;
      64        const char *result_str;
      65        int result;
      66        const char *flags;
      67        int flags_val;
      68        int fnmres;
      69        char numbuf[24];
      70  
      71        if (n == -1)
      72  	break;
      73  
      74        if (n == 0)
      75  	/* Maybe an empty line.  */
      76  	continue;
      77  
      78        /* Skip over all leading white spaces.  */
      79        cp = linebuf;
      80  
      81        locale = next_input (&cp, 1, 0);
      82        if (locale == NULL)
      83  	continue;
      84  
      85        input = next_input (&cp, 0, 0);
      86        if (input == NULL)
      87  	continue;
      88  
      89        pattern = next_input (&cp, 0, 0);
      90        if (pattern == NULL)
      91  	continue;
      92  
      93        result_str = next_input (&cp, 0, 0);
      94        if (result_str == NULL)
      95  	continue;
      96  
      97        if (strcmp (result_str, "0") == 0)
      98  	result = 0;
      99        else if  (strcasecmp (result_str, "NOMATCH") == 0)
     100  	result = FNM_NOMATCH;
     101        else
     102  	{
     103  	  char *endp;
     104  	  result = strtol (result_str, &endp, 0);
     105  	  if (*endp != '\0')
     106  	    continue;
     107  	}
     108  
     109        flags = next_input (&cp, 0, 1);
     110        if (flags == NULL)
     111  	/* We allow the flags missing.  */
     112  	flags = "";
     113  
     114        /* Convert the text describing the flags in a numeric value.  */
     115        flags_val = convert_flags (flags);
     116        if (flags_val == -1)
     117  	/* Something went wrong.  */
     118  	continue;
     119  
     120        /* Now run the actual test.  */
     121        ++ntests;
     122  
     123        if (setlocale (LC_COLLATE, locale) == NULL
     124  	  || setlocale (LC_CTYPE, locale) == NULL)
     125  	{
     126  	  puts ("*** Cannot set locale");
     127  	  ++nfailed;
     128  	  continue;
     129  	}
     130  
     131        fnmres = fnmatch (pattern, input, flags_val);
     132  
     133        printf ("%3d: fnmatch (\"%s\", \"%s\", %s) = %s%c",
     134  	      ++nr,
     135  	      escape (pattern, &escpatternlen, &escpattern),
     136  	      escape (input, &escinputlen, &escinput),
     137  	      flag_output (flags_val),
     138  	      (fnmres == 0
     139  	       ? "0" : (fnmres == FNM_NOMATCH
     140  			? "FNM_NOMATCH"
     141  			: (sprintf (numbuf, "%d", fnmres), numbuf))),
     142  	      (fnmres != 0) != (result != 0) ? ' ' : '\n');
     143  
     144        if ((fnmres != 0) != (result != 0))
     145  	{
     146  	  printf ("(FAIL, expected %s) ***\n",
     147  		  result == 0
     148  		  ? "0" : (result == FNM_NOMATCH
     149  			   ? "FNM_NOMATCH"
     150  			   : (sprintf (numbuf, "%d", result), numbuf)));
     151  	  ++nfailed;
     152  	}
     153      }
     154  
     155    printf ("=====================\n%3d tests, %3d failed\n", ntests, nfailed);
     156  
     157    free (escpattern);
     158    free (escinput);
     159    free (linebuf);
     160  
     161    return nfailed != 0;
     162  }
     163  
     164  
     165  static char *
     166  next_input (char **line, int first, int last)
     167  {
     168    char *cp = *line;
     169    char *result;
     170  
     171    while (*cp == ' ' || *cp == '\t')
     172      ++cp;
     173  
     174    /* We allow comment lines starting with '#'.  */
     175    if (first && *cp == '#')
     176      return NULL;
     177  
     178    if (*cp == '"')
     179      {
     180        char *wp;
     181  
     182        result = ++cp;
     183        wp = cp;
     184  
     185        while (*cp != '"' && *cp != '\0' && *cp != '\n')
     186  	if (*cp == '\\')
     187  	  {
     188  	    if (cp[1] == '\n' || cp[1] == '\0')
     189  	      return NULL;
     190  
     191  	    ++cp;
     192  	    if (*cp == 't')
     193  	      *wp++ = '\t';
     194  	    else if (*cp == 'n')
     195  	      *wp++ = '\n';
     196  	    else if (*cp >= '0' && *cp <= '7')
     197  	      {
     198  		int ndigits = 0;
     199  		int cval = 0;
     200  		while (ndigits < 3 && *cp >= '0' && *cp <= '7')
     201  		  {
     202  		    cval *= 8;
     203  		    cval += (*cp++) - '0';
     204  		    ndigits ++;
     205  		  }
     206  		*wp++ = cval;
     207  		--cp;
     208  	      }
     209  	    else
     210  	      *wp++ = *cp;
     211  
     212  	    ++cp;
     213  	  }
     214  	else
     215  	  *wp++ = *cp++;
     216  
     217        if (*cp != '"')
     218  	return NULL;
     219  
     220        if (wp != cp)
     221  	*wp = '\0';
     222      }
     223    else
     224      {
     225        result = cp;
     226        while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t')
     227  	++cp;
     228  
     229        if (cp == result && ! last)
     230  	/* Premature end of line.  */
     231  	return NULL;
     232      }
     233  
     234    /* Terminate and skip over the next white spaces.  */
     235    *cp++ = '\0';
     236  
     237    *line = cp;
     238    return result;
     239  }
     240  
     241  
     242  static int
     243  convert_flags (const char *str)
     244  {
     245    int result = 0;
     246  
     247    while (*str != '\0')
     248      {
     249        int len;
     250  
     251        if (strncasecmp (str, "PATHNAME", 8) == 0
     252  	  && (str[8] == '|' || str[8] == '\0'))
     253  	{
     254  	  result |= FNM_PATHNAME;
     255  	  len = 8;
     256  	}
     257        else if (strncasecmp (str, "NOESCAPE", 8) == 0
     258  	       && (str[8] == '|' || str[8] == '\0'))
     259  	{
     260  	  result |= FNM_NOESCAPE;
     261  	  len = 8;
     262  	}
     263        else if (strncasecmp (str, "PERIOD", 6) == 0
     264  	       && (str[6] == '|' || str[6] == '\0'))
     265  	{
     266  	  result |= FNM_PERIOD;
     267  	  len = 6;
     268  	}
     269        else if (strncasecmp (str, "LEADING_DIR", 11) == 0
     270  	       && (str[11] == '|' || str[11] == '\0'))
     271  	{
     272  	  result |= FNM_LEADING_DIR;
     273  	  len = 11;
     274  	}
     275        else if (strncasecmp (str, "CASEFOLD", 8) == 0
     276  	       && (str[8] == '|' || str[8] == '\0'))
     277  	{
     278  	  result |= FNM_CASEFOLD;
     279  	  len = 8;
     280  	}
     281        else if (strncasecmp (str, "EXTMATCH", 8) == 0
     282  	       && (str[8] == '|' || str[8] == '\0'))
     283  	{
     284  	  result |= FNM_EXTMATCH;
     285  	  len = 8;
     286  	}
     287        else
     288  	return -1;
     289  
     290        str += len;
     291        if (*str != '\0')
     292  	++str;
     293      }
     294  
     295    return result;
     296  }
     297  
     298  
     299  static char *
     300  flag_output (int flags)
     301  {
     302    static char buf[100];
     303    int first = 1;
     304    char *cp = buf;
     305  
     306    if (flags & FNM_PATHNAME)
     307      {
     308        cp = stpcpy (cp, "FNM_PATHNAME");
     309        first = 0;
     310      }
     311    if (flags & FNM_NOESCAPE)
     312      {
     313        if (! first)
     314  	*cp++ = '|';
     315        cp = stpcpy (cp, "FNM_NOESCAPE");
     316        first = 0;
     317      }
     318    if (flags & FNM_PERIOD)
     319      {
     320        if (! first)
     321  	*cp++ = '|';
     322        cp = stpcpy (cp, "FNM_PERIOD");
     323        first = 0;
     324      }
     325    if (flags & FNM_LEADING_DIR)
     326      {
     327        if (! first)
     328  	*cp++ = '|';
     329        cp = stpcpy (cp, "FNM_LEADING_DIR");
     330        first = 0;
     331      }
     332    if (flags & FNM_CASEFOLD)
     333      {
     334        if (! first)
     335  	*cp++ = '|';
     336        cp = stpcpy (cp, "FNM_CASEFOLD");
     337        first = 0;
     338      }
     339    if (flags & FNM_EXTMATCH)
     340      {
     341        if (! first)
     342  	*cp++ = '|';
     343        cp = stpcpy (cp, "FNM_EXTMATCH");
     344        first = 0;
     345      }
     346    if (cp == buf)
     347      *cp++ = '0';
     348    *cp = '\0';
     349  
     350    return buf;
     351  }
     352  
     353  
     354  static char *
     355  escape (const char *str, size_t *reslenp, char **resbufp)
     356  {
     357    size_t reslen = *reslenp;
     358    char *resbuf = *resbufp;
     359    size_t len = strlen (str);
     360    char *wp;
     361  
     362    if (2 * len + 1 > reslen)
     363      {
     364        resbuf = (char *) realloc (resbuf, 2 * len + 1);
     365        if (resbuf == NULL)
     366  	error (EXIT_FAILURE, errno, "while allocating buffer for printing");
     367        *reslenp = 2 * len + 1;
     368        *resbufp = resbuf;
     369      }
     370  
     371    wp = resbuf;
     372    while (*str != '\0')
     373      if (*str == '\t')
     374        {
     375  	*wp++ = '\\';
     376  	*wp++ = 't';
     377  	++str;
     378        }
     379      else if (*str == '\n')
     380        {
     381  	*wp++ = '\\';
     382  	*wp++ = 'n';
     383  	++str;
     384        }
     385      else if (*str == '"')
     386        {
     387  	*wp++ = '\\';
     388  	*wp++ = '"';
     389  	++str;
     390        }
     391      else if (*str == '\\')
     392        {
     393  	*wp++ = '\\';
     394  	*wp++ = '\\';
     395  	++str;
     396        }
     397      else
     398        *wp++ = *str++;
     399  
     400    *wp = '\0';
     401  
     402    return resbuf;
     403  }
     404  
     405  #define TEST_FUNCTION do_test ()
     406  #include "../test-skeleton.c"