123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- /* Tests for fnmatch function.
- Copyright (C) 2000, 2001 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
- #include <errno.h>
- #include <error.h>
- #include <fnmatch.h>
- #include <locale.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/types.h>
- static char *next_input (char **line, int first, int last);
- static int convert_flags (const char *str);
- static char *flag_output (int flags);
- static char *escape (const char *str, size_t *reslenp, char **resbuf);
- int str_isalpha(const char *str)
- {
- size_t i = strlen(str);
- while (i--)
- if (isascii(str[i]) == 0)
- return 0;
- return 1;
- }
- int str_has_funk(const char *str, const char x)
- {
- size_t i, max = strlen(str);
- for (i=0; i+1<max; ++i)
- if (str[i] == '[' && str[i+1] == x)
- return 1;
- return 0;
- }
- int
- main (void)
- {
- char *linebuf = NULL;
- size_t linebuflen = 0;
- int ntests = 0;
- int nfailed = 0;
- int nskipped = 0;
- char *escinput = NULL;
- size_t escinputlen = 0;
- char *escpattern = NULL;
- size_t escpatternlen = 0;
- int nr = 0;
- /* Read lines from stdin with the following format:
- locale input-string match-string flags result
- where `result' is either 0 or 1. If the first character of a
- string is '"' we read until the next '"' and handled escaped '"'. */
- while (! feof (stdin))
- {
- ssize_t n = getline (&linebuf, &linebuflen, stdin);
- char *cp;
- const char *locale;
- const char *input;
- const char *pattern;
- const char *result_str;
- int result;
- const char *flags;
- int flags_val;
- int fnmres;
- char numbuf[24];
- if (n == -1)
- break;
- if (n == 0)
- /* Maybe an empty line. */
- continue;
- /* Skip over all leading white spaces. */
- cp = linebuf;
- locale = next_input (&cp, 1, 0);
- if (locale == NULL)
- continue;
- input = next_input (&cp, 0, 0);
- if (input == NULL)
- continue;
- pattern = next_input (&cp, 0, 0);
- if (pattern == NULL)
- continue;
- result_str = next_input (&cp, 0, 0);
- if (result_str == NULL)
- continue;
- if (strcmp (result_str, "0") == 0)
- result = 0;
- else if (strcasecmp (result_str, "NOMATCH") == 0)
- result = FNM_NOMATCH;
- else
- {
- char *endp;
- result = strtol (result_str, &endp, 0);
- if (*endp != '\0')
- continue;
- }
- flags = next_input (&cp, 0, 1);
- if (flags == NULL)
- /* We allow the flags missing. */
- flags = "";
- /* Convert the text describing the flags in a numeric value. */
- flags_val = convert_flags (flags);
- if (flags_val == -1)
- /* Something went wrong. */
- continue;
- /* Now run the actual test. */
- ++ntests;
- #ifdef __UCLIBC_HAS_XLOCALE__
- if (setlocale (LC_COLLATE, locale) == NULL
- || setlocale (LC_CTYPE, locale) == NULL)
- {
- puts ("*** Cannot set locale");
- ++nfailed;
- continue;
- }
- #else
- /* skip non-ascii strings */
- if (!str_isalpha(pattern) || !str_isalpha(input))
- {
- ++nskipped;
- printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP multibyte test (requires locale support)\n", ++nr, pattern, input);
- continue;
- }
- /* skip collating symbols */
- if (str_has_funk(pattern, '.') || str_has_funk(input, '.'))
- {
- ++nskipped;
- printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP collating symbol test (requires locale support)\n", ++nr, pattern, input);
- continue;
- }
- /* skip equivalence class expressions */
- if (str_has_funk(pattern, '=') || str_has_funk(input, '='))
- {
- ++nskipped;
- printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP equivalence class test (requires locale support)\n", ++nr, pattern, input);
- continue;
- }
- #endif
- fnmres = fnmatch (pattern, input, flags_val);
- printf ("%3d: fnmatch (\"%s\", \"%s\", %s) = %s%c",
- ++nr,
- escape (pattern, &escpatternlen, &escpattern),
- escape (input, &escinputlen, &escinput),
- flag_output (flags_val),
- (fnmres == 0
- ? "0" : (fnmres == FNM_NOMATCH
- ? "FNM_NOMATCH"
- : (sprintf (numbuf, "%d", fnmres), numbuf))),
- (fnmres != 0) != (result != 0) ? ' ' : '\n');
- if ((fnmres != 0) != (result != 0))
- {
- printf ("(FAIL, expected %s) ***\n",
- result == 0
- ? "0" : (result == FNM_NOMATCH
- ? "FNM_NOMATCH"
- : (sprintf (numbuf, "%d", result), numbuf)));
- ++nfailed;
- }
- }
- printf ("=====================\n%3d tests, %3d failed, %3d skipped\n", ntests, nfailed, nskipped);
- free (escpattern);
- free (escinput);
- free (linebuf);
- return nfailed != 0;
- }
- static char *
- next_input (char **line, int first, int last)
- {
- char *cp = *line;
- char *result;
- while (*cp == ' ' || *cp == '\t')
- ++cp;
- /* We allow comment lines starting with '#'. */
- if (first && *cp == '#')
- return NULL;
- if (*cp == '"')
- {
- char *wp;
- result = ++cp;
- wp = cp;
- while (*cp != '"' && *cp != '\0' && *cp != '\n')
- if (*cp == '\\')
- {
- if (cp[1] == '\n' || cp[1] == '\0')
- return NULL;
- ++cp;
- if (*cp == 't')
- *wp++ = '\t';
- else if (*cp == 'n')
- *wp++ = '\n';
- else
- *wp++ = *cp;
- ++cp;
- }
- else
- *wp++ = *cp++;
- if (*cp != '"')
- return NULL;
- if (wp != cp)
- *wp = '\0';
- }
- else
- {
- result = cp;
- while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t')
- ++cp;
- if (cp == result && ! last)
- /* Premature end of line. */
- return NULL;
- }
- /* Terminate and skip over the next white spaces. */
- *cp++ = '\0';
- *line = cp;
- return result;
- }
- static int
- convert_flags (const char *str)
- {
- int result = 0;
- while (*str != '\0')
- {
- int len;
- if (strncasecmp (str, "PATHNAME", 8) == 0
- && (str[8] == '|' || str[8] == '\0'))
- {
- result |= FNM_PATHNAME;
- len = 8;
- }
- else if (strncasecmp (str, "NOESCAPE", 8) == 0
- && (str[8] == '|' || str[8] == '\0'))
- {
- result |= FNM_NOESCAPE;
- len = 8;
- }
- else if (strncasecmp (str, "PERIOD", 6) == 0
- && (str[6] == '|' || str[6] == '\0'))
- {
- result |= FNM_PERIOD;
- len = 6;
- }
- #ifdef FNM_LEADING_DIR
- else if (strncasecmp (str, "LEADING_DIR", 11) == 0
- && (str[11] == '|' || str[11] == '\0'))
- {
- result |= FNM_LEADING_DIR;
- len = 11;
- }
- #endif
- #ifdef FNM_CASEFOLD
- else if (strncasecmp (str, "CASEFOLD", 8) == 0
- && (str[8] == '|' || str[8] == '\0'))
- {
- result |= FNM_CASEFOLD;
- len = 8;
- }
- #endif
- #ifdef FNM_EXTMATCH
- else if (strncasecmp (str, "EXTMATCH", 8) == 0
- && (str[8] == '|' || str[8] == '\0'))
- {
- result |= FNM_EXTMATCH;
- len = 8;
- }
- #endif
- else
- return -1;
- str += len;
- if (*str != '\0')
- ++str;
- }
- return result;
- }
- static char *
- flag_output (int flags)
- {
- static char buf[100];
- int first = 1;
- char *cp = buf;
- if (flags & FNM_PATHNAME)
- {
- cp = stpcpy (cp, "FNM_PATHNAME");
- first = 0;
- }
- if (flags & FNM_NOESCAPE)
- {
- if (! first)
- *cp++ = '|';
- cp = stpcpy (cp, "FNM_NOESCAPE");
- first = 0;
- }
- if (flags & FNM_PERIOD)
- {
- if (! first)
- *cp++ = '|';
- cp = stpcpy (cp, "FNM_PERIOD");
- first = 0;
- }
- #ifdef FNM_LEADING_DIR
- if (flags & FNM_LEADING_DIR)
- {
- if (! first)
- *cp++ = '|';
- cp = stpcpy (cp, "FNM_LEADING_DIR");
- first = 0;
- }
- #endif
- #ifdef FNM_CASEFOLD
- if (flags & FNM_CASEFOLD)
- {
- if (! first)
- *cp++ = '|';
- cp = stpcpy (cp, "FNM_CASEFOLD");
- first = 0;
- }
- #endif
- #ifdef FNM_EXTMATCH
- if (flags & FNM_EXTMATCH)
- {
- if (! first)
- *cp++ = '|';
- cp = stpcpy (cp, "FNM_EXTMATCH");
- first = 0;
- }
- #endif
- if (cp == buf)
- *cp++ = '0';
- *cp = '\0';
- return buf;
- }
- static char *
- escape (const char *str, size_t *reslenp, char **resbufp)
- {
- size_t reslen = *reslenp;
- char *resbuf = *resbufp;
- size_t len = strlen (str);
- char *wp;
- if (2 * len + 1 > reslen)
- {
- resbuf = (char *) realloc (resbuf, 2 * len + 1);
- if (resbuf == NULL)
- error (EXIT_FAILURE, errno, "while allocating buffer for printing");
- *reslenp = 2 * len + 1;
- *resbufp = resbuf;
- }
- wp = resbuf;
- while (*str != '\0')
- if (*str == '\t')
- {
- *wp++ = '\\';
- *wp++ = 't';
- ++str;
- }
- else if (*str == '\n')
- {
- *wp++ = '\\';
- *wp++ = 'n';
- ++str;
- }
- else if (*str == '"')
- {
- *wp++ = '\\';
- *wp++ = '"';
- ++str;
- }
- else if (*str == '\\')
- {
- *wp++ = '\\';
- *wp++ = '\\';
- ++str;
- }
- else
- *wp++ = *str++;
- *wp = '\0';
- return resbuf;
- }
|