2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: strmatch.c /main/3 1995/11/01 18:49:40 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
31 * Copyright (c) 1995 AT&T Corp. *
32 * All Rights Reserved *
34 * This software is licensed by AT&T Corp. *
35 * under the terms and conditions of the license in *
36 * http://www.research.att.com/orgs/ssr/book/reuse *
38 * This software was created by the *
39 * Software Engineering Research Department *
40 * AT&T Bell Laboratories *
42 * For further information contact *
43 * gsf@research.att.com *
45 ***************************************************************/
47 /* : : generated by proto : : */
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__ "C"
57 #define __PROTO__(x) x
59 #define __PARAM__(n,o) n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
72 #define __PROTO__(x) ()
73 #define __OTORP__(x) x
74 #define __PARAM__(n,o) o
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__ ...
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a) va_start(p,a)
90 #define __VA_START__(p,a) va_start(p)
96 #if _hdr_wchar && _lib_wctype && _lib_iswctype
98 /* on linux wchar.h can include FILE without stdio.h which clashes with sfio_t */
100 #ifndef __FILE_defined
101 #define __FILE_defined 1
107 #define isalnum(x) iswalnum(x)
109 #define isalpha(x) iswalpha(x)
111 #define iscntrl(x) iswcntrl(x)
113 #define isblank(x) iswblank(x)
115 #define isdigit(x) iswdigit(x)
117 #define isgraph(x) iswgraph(x)
119 #define islower(x) iswlower(x)
121 #define isprint(x) iswprint(x)
123 #define ispunct(x) iswpunct(x)
125 #define isspace(x) iswspace(x)
127 #define isupper(x) iswupper(x)
129 #define isxdigit(x) iswxdigit(x)
134 iswblank __PARAM__((wint_t wc), (wc)) __OTORP__(wint_t wc;){
135 static int initialized;
141 wt = wctype("blank");
143 return(iswctype(wc, wt));
153 #define isblank(x) ((x)==' '||(x)=='\t')
157 #define isgraph(x) (isprint(x)&&!isblank(x))
184 #if _lib_mbtowc && MB_LEN_MAX > 1
185 #define mbgetchar(p) ((ast.locale.set&LC_SET_CTYPE)?((ast.tmp_int=mbtowc(&ast.tmp_wchar,p,MB_CUR_MAX))>=0?((p+=ast.tmp_int),ast.tmp_wchar):0):(*p++))
187 #define mbgetchar(p) (*p++)
191 #define isxdigit(c) ((c)>='0'&&(c)<='9'||(c)>='a'&&(c)<='f'||(c)>='A'&&(c)<='F')
194 #define CODE(n,c1,c2,c3,c4,c5) (((n)<<25)|(((c1)-'a')<<20)|(((c2)-'a')<<15)|(((c3)-'a')<<10)|(((c4)-'a')<<5)|((c5)-'a'))
196 #define getsource(s,e) (((s)>=(e))?0:mbgetchar(s))
205 extern __MANGLE__ int fnmatch __PROTO__((const char*, const char*, int));
209 * gobble chars up to <sub> or ) keeping track of (...) and [...]
210 * sub must be one of { '|', '&', 0 }
211 * 0 returned if s runs out
215 gobble __PARAM__((Match_t* mp, register char* s, register int sub, int* g, int clear), (mp, s, sub, g, clear)) __OTORP__(Match_t* mp; register char* s; register int sub; int* g; int clear;){
217 register char* b = 0;
221 for (;;) switch (mbgetchar(s))
224 if (mbgetchar(s)) break;
231 if (*s == '!') mbgetchar(s);
234 else if (*s == '.' || *s == '=' || *s == ':') c = *s;
239 if (*(s - 2) == c) c = 0;
240 else if (b != (s - 1)) b = 0;
252 mp->current.beg[n] = mp->current.end[n] = 0;
257 if (!b && p-- <= 0) return(sub ? 0 : s);
260 if (!b && !p && sub == '|') return(s);
265 static int grpmatch __PROTO__((Match_t*, int, char*, register char*, char*, int));
270 #define return(x) do{error_info.indent--;return(x);}while(0)
274 * match a single pattern
275 * e is the end (0) of the substring in s
276 * r marks the start of a repeated subgroup pattern
280 onematch __PARAM__((Match_t* mp, int g, char* s, char* p, char* e, char* r, int flags), (mp, g, s, p, e, r, flags)) __OTORP__(Match_t* mp; int g; char* s; char* p; char* e; char* r; int flags;){
289 error(-1, "onematch g=%d s=%-.*s p=%s r=%p flags=%o", g, e - s, s, p, r, flags);
294 sc = getsource(s, e);
296 switch (pc = mbgetchar(p))
304 if (pc == '(' || *p == '(')
310 subp = p + (pc != '(');
313 if (g < MAXGROUP && !r)
314 mp->current.beg[g] = mp->current.end[g] = 0;
315 if (!(p = gobble(mp, subp, 0, &g, !r)))
317 if (pc == '*' || pc == '?' || pc == '+' && oldp == r)
319 if (onematch(mp, g, s, p, e, NiL, flags))
321 if (!sc || !getsource(s, e))
323 mp->current.groups = oldg;
327 if (pc == '*' || pc == '+')
336 if (grpmatch(mp, n, olds, subp, s, flags) == pc)
340 if (!mp->current.beg[n] || mp->current.beg[n] > olds)
341 mp->current.beg[n] = olds;
342 if (s > mp->current.end[n])
343 mp->current.end[n] = s;
345 error(-4, "subgroup#%d n=%d beg=%p end=%p len=%d", __LINE__, n, mp->current.beg[n], mp->current.end[n], mp->current.end[n] - mp->current.beg[n]);
348 if (onematch(mp, sc, s, p, e, oldp, flags))
350 if (p == oldp && n < MAXGROUP)
352 if (!mp->current.beg[n] || mp->current.beg[n] > olds)
353 mp->current.beg[n] = olds;
354 if (s > mp->current.end[n])
355 mp->current.end[n] = s;
357 error(-4, "subgroup#%d n=%d beg=%p end=%p len=%d", __LINE__, n, mp->current.beg[n], mp->current.end[n], mp->current.end[n] - mp->current.beg[n]);
363 } while (s < e && mbgetchar(s));
364 mp->current.groups = oldg;
370 * several stars are the same as one
374 if (*(p + 1) == '(') break;
377 switch (pc = mbgetchar(p))
394 mp->current.next_s = (flags & STR_MAXIMAL) ? e : olds;
396 mp->current.groups = g;
397 if (!pc && (!mp->best.next_s || (flags & STR_MAXIMAL) && mp->current.next_s > mp->best.next_s || !(flags & STR_MAXIMAL) && mp->current.next_s < mp->best.next_s))
399 mp->best = mp->current;
401 error(-3, "best#%d groups=%d next=\"%s\"", __LINE__, mp->best.groups, mp->best.next_s);
406 if (!(pc = mbgetchar(p))) return(0);
407 if (pc >= '0' && pc <= '9')
411 error(-2, "backref#%d n=%d g=%d beg=%p end=%p len=%d", __LINE__, n, g, mp->current.beg[n], mp->current.end[n], mp->current.end[n] - mp->current.beg[n]);
413 if (n <= g && mp->current.beg[n])
414 pc = *mp->current.beg[n];
424 if ((n || pc == sc) && onematch(mp, g, olds, p, e, NiL, flags)) return(1);
427 sc = getsource(s, e);
430 else if (pc != '?' && pc != sc) return(0);
433 if (!(flags & STR_MAXIMAL)) sc = 0;
440 mp->current.next_s = olds;
442 mp->current.groups = g;
444 if (!pc && (!mp->best.next_s || (flags & STR_MAXIMAL) && olds > mp->best.next_s || !(flags & STR_MAXIMAL) && olds < mp->best.next_s))
446 mp->best = mp->current;
447 mp->best.next_s = olds;
450 error(-3, "best#%d groups=%d next=\"%s\"", __LINE__, mp->best.groups, mp->best.next_s);
466 if (ast.locale.set & LC_SET_COLLATE) range = p - 1;
471 if (invert = *p == '!') p++;
475 if (!(pc = mbgetchar(p))) return(0);
476 else if (pc == '[' && (*p == ':' || *p == '=' || *p == '.'))
483 if (!(pc = mbgetchar(p))) return(0);
484 if (pc == n && *p == ']') break;
491 switch (CODE(x, oldp[0], oldp[1], oldp[2], oldp[3], oldp[4]))
493 /* all these should really be controlled by
494 * #if _lib_mbtowc to use the narrow
495 * character versions (isalnum, etc)
496 * if there are no wide characters.
497 * For CDE, we require wide chars so
498 * I am not bothering.
499 * ( COSE Defect 8262 )
501 case CODE(5,'a','l','n','u','m'):
502 if (isalnum(sc)) ok = 1;
504 case CODE(5,'a','l','p','h','a'):
505 if (isalpha(sc)) ok = 1;
507 case CODE(5,'b','l','a','n','k'):
508 if (isblank(sc)) ok = 1;
510 case CODE(5,'c','n','t','r','l'):
511 if (iscntrl(sc)) ok = 1;
513 case CODE(5,'d','i','g','i','t'):
514 if (isdigit(sc)) ok = 1;
516 case CODE(5,'g','r','a','p','h'):
517 if (isgraph(sc)) ok = 1;
519 case CODE(5,'l','o','w','e','r'):
520 if (islower(sc)) ok = 1;
522 case CODE(5,'p','r','i','n','t'):
523 if (isprint(sc)) ok = 1;
525 case CODE(5,'p','u','n','c','t'):
526 if (ispunct(sc)) ok = 1;
528 case CODE(5,'s','p','a','c','e'):
529 if (isspace(sc)) ok = 1;
531 case CODE(5,'u','p','p','e','r'):
532 if (isupper(sc)) ok = 1;
534 case CODE(6,'x','d','i','g','i'):
535 if (oldp[5] == 't' && isxdigit(sc)) ok = 1;
544 strncpy(cc, oldp, x);
546 if (iswctype(sc, wctype(cc))) ok = 1;
553 else if (ast.locale.set & LC_SET_COLLATE)
558 else if (*p == '-' && *(p + 1) != ']')
563 else if (isalpha(*oldp) && isalpha(*olds) && tolower(*oldp) == tolower(*olds) || sc == mbgetchar(oldp))
567 else if (pc == ']' && n)
572 char pat[2 * UCHAR_MAX];
573 char str[COLL_MAX + 1];
575 if (p - range > sizeof(pat) - 2)
577 memcpy(pat, range, p - range);
578 pat[p - range] = '*';
579 pat[p - range + 1] = 0;
580 if (fnmatch(pat, olds, 0))
584 for (x = 0; x < sizeof(str) - 1 && olds[x]; x++)
588 if (!fnmatch(pat, str, 0))
597 if (ok != invert) break;
600 else if (pc == '\\' && (oldp = p, !(pc = mbgetchar(p)))) return(0);
601 else if (ok) /*NOP*/;
603 else if (range && !(ast.locale.set & LC_SET_COLLATE))
610 if (ast.locale.set & LC_SET_CTYPE)
619 sz = mbtowc(&sw, olds, MB_CUR_MAX);
620 bz = mbtowc(&bw, range, MB_CUR_MAX);
621 ez = mbtowc(&ew, oldp, MB_CUR_MAX);
622 if (sw == bw || sw == ew)
624 else if (sz > 1 || bz > 1 || ez > 1)
626 if (sz == bz && sz == ez && sw > bw && sw < ew)
633 if (sc == (x = mbgetchar(range)) || sc == (pc = mbgetchar(oldp)) || sc > x && sc < pc)
638 else if (*p == '-' && *(p + 1) != ']')
642 if (ast.locale.set & LC_SET_COLLATE) ok = -1;
650 if (sc == pc) ok = 1;
659 if (!(pc = mbgetchar(p))) return(0);
660 if (pc >= '0' && pc <= '9')
664 error(-2, "backref#%d n=%d g=%d beg=%p end=%p len=%d", __LINE__, n, g, mp->current.beg[n], mp->current.end[n], mp->current.end[n] - mp->current.beg[n]);
666 if (n <= g && (oldp = mp->current.beg[n]))
668 while (oldp < mp->current.end[n])
669 if (!*olds || *olds++ != *oldp++)
677 if (pc != sc) return(0);
685 * match any pattern in a group
686 * | and & subgroups are parsed here
690 grpmatch __PARAM__((Match_t* mp, int g, char* s, register char* p, char* e, int flags), (mp, g, s, p, e, flags)) __OTORP__(Match_t* mp; int g; char* s; register char* p; char* e; int flags;){
695 error(-1, "grpmatch g=%d s=%-.*s p=%s flags=%o", g, e - s, s, p, flags);
699 for (a = p; onematch(mp, g, s, a, e, NiL, flags); a++)
700 if (*(a = mp->next_p) != '&')
702 } while (p = gobble(mp, p, '|', &g, 1));
712 * 0 returned if no match
713 * otherwise number of subgroups matched returned
714 * match group begin offsets are even elements of sub
715 * match group end offsets are odd elements of sub
716 * the matched string is from s+sub[0] up to but not
721 strgrpmatch __PARAM__((const char* b, const char* p, int* sub, int n, int flags), (b, p, sub, n, flags)) __OTORP__(const char* b; const char* p; int* sub; int n; int flags;){
728 match.last_s = e = s + strlen(s);
731 match.best.next_s = 0;
732 match.current.groups = 0;
733 if ((i = grpmatch(&match, 0, s, (char*)p, e, flags)) || match.best.next_s)
735 if (!i) match.current = match.best;
736 match.current.groups++;
737 match.current.end[0] = match.current.next_s;
739 error(-1, "match i=%d s=\"%s\" p=\"%s\" flags=%o groups=%d next=\"%s\"", i, s, p, flags, match.current.groups, match.current.next_s);
743 if ((flags & STR_LEFT) || s >= e)
747 if ((flags & STR_RIGHT) && match.current.next_s != e)
751 match.current.beg[0] = s;
753 if (n > match.current.groups)
754 n = match.current.groups;
755 for (i = 0; i < n; i++)
757 sub[i * 2] = match.current.end[i] ? match.current.beg[i] - s : 0;
758 sub[i * 2 + 1] = match.current.end[i] ? match.current.end[i] - s : 0;
764 * compare the string s with the shell pattern p
765 * returns 1 for match 0 otherwise
769 strmatch __PARAM__((const char* s, const char* p), (s, p)) __OTORP__(const char* s; const char* p;){
770 return(strgrpmatch(s, p, NiL, 0, STR_MAXIMAL|STR_LEFT|STR_RIGHT));
774 * leading substring match
775 * first char after end of substring returned
776 * 0 returned if no match
778 * OBSOLETE: use strgrpmatch()
782 strsubmatch __PARAM__((const char* s, const char* p, int flags), (s, p, flags)) __OTORP__(const char* s; const char* p; int flags;){
785 return(strgrpmatch(s, p, match, 1, (flags ? STR_MAXIMAL : 0)|STR_LEFT) ? (char*)s + match[1] : (char*)0);