/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they 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 these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * $TOG: strwcmp.C /main/7 1998/04/17 11:25:04 mgreess $ * * (c) Copyright 1996 Digital Equipment Corporation. * (c) Copyright 1993,1994,1996 Hewlett-Packard Company. * (c) Copyright 1993,1994,1996 International Business Machines Corp. * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc. * (c) Copyright 1993,1994,1996 Novell, Inc. * (c) Copyright 1996 FUJITSU LIMITED. * (c) Copyright 1996 Hitachi. */ #include #include #include #include #include #include #define QUOTE 0x40000000 #ifdef DEBUG static char tabs[] = " "; # define TABS (&tabs[10 - depth]) static int RETURN(int ret, int depth) { printf("%sreturning %s\n", TABS, (ret ? "SUCCEEDED" : "FAILED")); return ret; } #else #define RETURN(x,y) (x) #endif /* FORWARD */ static int match(const char *, const char *, int); static const char *next_patt(const char *, int advance = 1); static int match_class(const char *, char); /* INLINE */ static int next_char(register const char *pattern, const char **cpp = NULL) { register int ret; wchar_t __nlh_char[1]; ret = pattern ? (int)CHARAT(pattern) : '\0'; if (ret != '\0') { ADVANCE(pattern); /* AIX needs line broken to get around macro bug (Temporary Fix) */ if (ret == '\\' && CHARAT(pattern) != '\0') ret = QUOTE | (int)CHARADV(pattern); } if (cpp != NULL) *cpp = pattern; return ret; } int strwcmp(const char *pattern, const char *string) /* * String 'pattern' is matched against string 'string'. Zero is * returned if the match is successful. 'pattern' may contain the * shell metas * and ? and the semantics are the same. ? and * may * be escaped with \ */ { return !match(pattern, string, 0); } // stwpat returns a pointer to the first meta-character if the string // is a pattern, else NULL char * strwpat(register const char *pattern) { register int ch; register char *prev_pattern = (char *)pattern; wchar_t __nlh_char[1]; while ((ch = next_char(pattern, &pattern)) != '\0') { switch (ch) { case '*': return prev_pattern; case '?': return prev_pattern; case '[': { register const char *eop = next_patt(prev_pattern, 0); if (CHARAT(eop) == ']') return prev_pattern; break; } } prev_pattern = (char *)pattern; } return NULL; } /* * match will check to see if pattern can successfully be applied to * the beginning of string. */ static int match(register const char *pattern, register const char *string, int depth) { #ifdef DEBUG printf("%smatch(\"%s\", \"%s\")\n", TABS, pattern, string); #endif int ch; const char *cp; wchar_t __nlh_char[1]; while ((ch = next_char(pattern, &cp)) != '\0') { const char *laststr = string; register int testchar = (int)CHARADV(string); switch (ch) { case '*': { pattern = cp; /* skip over '*' */ string = laststr; /* reverse - testchar not used */ const char *s = string; do if (match(pattern, s, depth + 1)) return RETURN(1, depth); while (CHARADV(s) != '\0'); return RETURN(0, depth); } case '?': break; case '[': { int mt = match_class(pattern, testchar); if (mt == 0) return RETURN(0, depth); else if (mt == 2 && ch != testchar) return RETURN(0, depth); break; } default: if ((ch & ~QUOTE) != testchar) return RETURN(0, depth); break; } if (testchar == '\0') string = laststr; // reverse string pattern = next_patt(pattern); } return RETURN(CHARAT(string) == '\0', depth); } static int match_class(register const char *clss, register char testchar) /* * pattern is a pointer to the leading [ of * a shell-type class. testchar is the character to match against * the class. */ { int match = 1; /* false if first char is '!' */ wchar_t __nlh_char[1]; /* find end of class, ie an un-escaped ']' */ register const char *eop = next_patt(clss, 0); ADVANCE(clss); if (CHARAT(eop) != ']') return 2; if (CHARAT(clss) == '!') { match = 0; ADVANCE(clss); } while (clss < eop) { register int ch = next_char(clss, &clss); char const *clss_end = clss; int sep = next_char(clss_end, &clss_end); int ch2 = next_char(clss_end, &clss_end); /* check if next three chars are a range */ if (sep == '-' && ch2 != ']') { /* check range - we have to use strcoll to do it right */ char c1[MB_LEN_MAX+1], c2[MB_LEN_MAX+1], tc[MB_LEN_MAX+1]; memset(c1, 0, sizeof(c1)); memset(c2, 0, sizeof(c2)); memset(tc, 0, sizeof(tc)); ch &= ~QUOTE; WCHAR(ch, c1); ch2 &= ~QUOTE; WCHAR(ch2, c2); WCHAR(testchar, tc); /* if (ch <= testchar && testchar <= ch2) // Original code */ /* Second implementation: * if (nl_strncmp(c1, tc, 1) <= 0 && nl_strncmp(tc, c2, 1) <= 0) * return match; */ /* Third, portable implementation: */ if (strcoll(c1, tc) <= 0 && strcoll(tc, c2) <= 0) return match; clss = clss_end; } else /* they are not a range, check simple match */ { if ((ch & ~QUOTE) == testchar) return match; } } return !match; } static const char * next_patt(register const char *pattern, int advance) { wchar_t __nlh_char[1]; if (CHARAT(pattern) == '[') { int ch; const char *pp = pattern; ADVANCE(pp); if (CHARAT(pp) == '^') ADVANCE(pp); if (CHARAT(pp) == ']') ADVANCE(pp); char const *np; for (; (ch = next_char(pp, &np)) != '\0'; pp = np) if (ch == ']') return (advance ? np : pp); } next_char(pattern, &pattern); return pattern; } #ifdef DEBUG #define MAIN main MAIN() { char pattern[50], string[50]; while (1) { putchar('\n'); printf("pattern: "); if (fgets(pattern, sizeof(pattern)-1, stdin) == NULL) break; printf("string: "); if (fgets(string, sizeof(pattern)-1, stdin) == NULL) break; printf("MATCH is %s\n", ((strwcmp(pattern, string) == 0) ? "SUCCEEDED" : "FAILED")); putchar('\n'); printf("MATCHI is %s\n", ((strwcmpi(pattern, string) == 0) ? "SUCCEEDED" : "FAILED")); } return 0; } #endif