Remove Unixware and openserver support
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / string / strmatch.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: strmatch.c /main/3 1995/11/01 18:49:40 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
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        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46
47 /* : : generated by proto : : */
48
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__      "C"
53 #else
54 #define __MANGLE__
55 #endif
56 #define __STDARG__
57 #define __PROTO__(x)    x
58 #define __OTORP__(x)
59 #define __PARAM__(n,o)  n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
62 #define const
63 #endif
64 #define signed
65 #define void            int
66 #define volatile
67 #define __V_            char
68 #else
69 #define __V_            void
70 #endif
71 #else
72 #define __PROTO__(x)    ()
73 #define __OTORP__(x)    x
74 #define __PARAM__(n,o)  o
75 #define __MANGLE__
76 #define __V_            char
77 #define const
78 #define signed
79 #define void            int
80 #define volatile
81 #endif
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__      ...
84 #else
85 #define __VARARG__
86 #endif
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a)       va_start(p,a)
89 #else
90 #define __VA_START__(p,a)       va_start(p)
91 #endif
92 #endif
93 #include <ast.h>
94 #include <ctype.h>
95
96 #if _hdr_wchar && _lib_wctype && _lib_iswctype
97
98 /* on linux wchar.h can include FILE without stdio.h which clashes with sfio_t */
99 #if defined(linux)
100  #ifndef __FILE_defined
101   #define __FILE_defined 1
102  #endif
103 #endif
104 #include <wchar.h>
105
106 #undef  isalnum
107 #define isalnum(x)      iswalnum(x)
108 #undef  isalpha
109 #define isalpha(x)      iswalpha(x)
110 #undef  iscntrl
111 #define iscntrl(x)      iswcntrl(x)
112 #undef  isblank
113 #define isblank(x)      iswblank(x)
114 #undef  isdigit
115 #define isdigit(x)      iswdigit(x)
116 #undef  isgraph
117 #define isgraph(x)      iswgraph(x)
118 #undef  islower
119 #define islower(x)      iswlower(x)
120 #undef  isprint
121 #define isprint(x)      iswprint(x)
122 #undef  ispunct
123 #define ispunct(x)      iswpunct(x)
124 #undef  isspace
125 #define isspace(x)      iswspace(x)
126 #undef  isupper
127 #define isupper(x)      iswupper(x)
128 #undef  isxdigit
129 #define isxdigit(x)     iswxdigit(x)
130
131 #if !_lib_iswblank
132
133 static int
134 iswblank __PARAM__((wint_t wc), (wc)) __OTORP__(wint_t wc;){
135         static int      initialized;
136         static wctype_t wt;
137
138         if (!initialized)
139         {
140                 initialized = 1;
141                 wt = wctype("blank");
142         }
143         return(iswctype(wc, wt));
144 }
145
146 #endif
147
148 #else
149
150 #undef  _lib_wctype
151
152 #ifndef isblank
153 #define isblank(x)      ((x)==' '||(x)=='\t')
154 #endif
155
156 #ifndef isgraph
157 #define isgraph(x)      (isprint(x)&&!isblank(x))
158 #endif
159
160 #endif
161
162 #if _DEBUG_MATCH
163 #include <error.h>
164 #endif
165
166 #define MAXGROUP        10
167
168 typedef struct
169 {
170         char*           beg[MAXGROUP];
171         char*           end[MAXGROUP];
172         char*           next_s;
173         short           groups;
174 } Group_t;
175
176 typedef struct
177 {
178         Group_t         current;
179         Group_t         best;
180         char*           last_s;
181         char*           next_p;
182 } Match_t;
183
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++))
186 #else
187 #define mbgetchar(p)    (*p++)
188 #endif
189
190 #ifndef isxdigit
191 #define isxdigit(c)     ((c)>='0'&&(c)<='9'||(c)>='a'&&(c)<='f'||(c)>='A'&&(c)<='F')
192 #endif
193
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'))
195
196 #define getsource(s,e)  (((s)>=(e))?0:mbgetchar(s))
197
198 #define COLL_MAX        3
199
200 #if !_lib_strcoll
201 #undef  _lib_fnmatch
202 #endif
203
204 #if _lib_fnmatch
205 extern __MANGLE__ int           fnmatch __PROTO__((const char*, const char*, int));
206 #endif
207
208 /*
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
212  */
213
214 static char*
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;){
216         register int    p = 0;
217         register char*  b = 0;
218         int             c = 0;
219         int             n;
220
221         for (;;) switch (mbgetchar(s))
222         {
223         case '\\':
224                 if (mbgetchar(s)) break;
225                 /*FALLTHROUGH*/
226         case 0:
227                 return(0);
228         case '[':
229                 if (!b)
230                 {
231                         if (*s == '!') mbgetchar(s);
232                         b = s;
233                 }
234                 else if (*s == '.' || *s == '=' || *s == ':') c = *s;
235                 break;
236         case ']':
237                 if (b)
238                 {
239                         if (*(s - 2) == c) c = 0;
240                         else if (b != (s - 1)) b = 0;
241                 }
242                 break;
243         case '(':
244                 if (!b)
245                 {
246                         p++;
247                         n = (*g)++;
248                         if (clear)
249                         {
250                                 if (!sub) n++;
251                                 if (n < MAXGROUP)
252                                         mp->current.beg[n] = mp->current.end[n] = 0;
253                         }
254                 }
255                 break;
256         case ')':
257                 if (!b && p-- <= 0) return(sub ? 0 : s);
258                 break;
259         case '|':
260                 if (!b && !p && sub == '|') return(s);
261                 break;
262         }
263 }
264
265 static int      grpmatch __PROTO__((Match_t*, int, char*, register char*, char*, int));
266
267 #if _DEBUG_MATCH
268 static long             test;
269
270 #define return(x)       do{error_info.indent--;return(x);}while(0)
271 #endif
272
273 /*
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
277  */
278
279 static int
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;){
281         register int    pc;
282         register int    sc;
283         register int    n;
284         char*           olds;
285         char*           oldp;
286
287 #if _DEBUG_MATCH
288         error_info.indent++;
289         error(-1, "onematch g=%d s=%-.*s p=%s r=%p flags=%o", g, e - s, s, p, r, flags);
290 #endif
291         do
292         {
293                 olds = s;
294                 sc = getsource(s, e);
295                 oldp = p;
296                 switch (pc = mbgetchar(p))
297                 {
298                 case '(':
299                 case '*':
300                 case '?':
301                 case '+':
302                 case '@':
303                 case '!':
304                         if (pc == '(' || *p == '(')
305                         {
306                                 char*   subp;
307                                 int     oldg;
308
309                                 s = olds;
310                                 subp = p + (pc != '(');
311                                 oldg = g;
312                                 n = ++g;
313                                 if (g < MAXGROUP && !r)
314                                         mp->current.beg[g] = mp->current.end[g] = 0;
315                                 if (!(p = gobble(mp, subp, 0, &g, !r)))
316                                         return(0);
317                                 if (pc == '*' || pc == '?' || pc == '+' && oldp == r)
318                                 {
319                                         if (onematch(mp, g, s, p, e, NiL, flags))
320                                                 return(1);
321                                         if (!sc || !getsource(s, e))
322                                         {
323                                                 mp->current.groups = oldg;
324                                                 return(0);
325                                         }
326                                 }
327                                 if (pc == '*' || pc == '+')
328                                 {
329                                         p = oldp;
330                                         sc = n - 1;
331                                 }
332                                 else sc = g;
333                                 pc = (pc != '!');
334                                 do
335                                 {
336                                         if (grpmatch(mp, n, olds, subp, s, flags) == pc)
337                                         {
338                                                 if (n < MAXGROUP)
339                                                 {
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;
344 #if _DEBUG_MATCH
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]);
346 #endif
347                                                 }
348                                                 if (onematch(mp, sc, s, p, e, oldp, flags))
349                                                 {
350                                                         if (p == oldp && n < MAXGROUP)
351                                                         {
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;
356 #if _DEBUG_MATCH
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]);
358 #endif
359                                                         }
360                                                         return(1);
361                                                 }
362                                         }
363                                 } while (s < e && mbgetchar(s));
364                                 mp->current.groups = oldg;
365                                 return(0);
366                         }
367                         else if (pc == '*')
368                         {
369                                 /*
370                                  * several stars are the same as one
371                                  */
372
373                                 while (*p == '*')
374                                         if (*(p + 1) == '(') break;
375                                         else p++;
376                                 oldp = p;
377                                 switch (pc = mbgetchar(p))
378                                 {
379                                 case '@':
380                                 case '!':
381                                 case '+':
382                                         n = *p == '(';
383                                         break;
384                                 case '(':
385                                 case '[':
386                                 case '?':
387                                 case '*':
388                                         n = 1;
389                                         break;
390                                 case 0:
391                                 case '|':
392                                 case '&':
393                                 case ')':
394                                         mp->current.next_s = (flags & STR_MAXIMAL) ? e : olds;
395                                         mp->next_p = oldp;
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))
398                                         {
399                                                 mp->best = mp->current;
400 #if _DEBUG_MATCH
401                                                 error(-3, "best#%d groups=%d next=\"%s\"", __LINE__, mp->best.groups, mp->best.next_s);
402 #endif
403                                         }
404                                         return(1);
405                                 case '\\':
406                                         if (!(pc = mbgetchar(p))) return(0);
407                                         if (pc >= '0' && pc <= '9')
408                                         {
409                                                 n = pc - '0';
410 #if _DEBUG_MATCH
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]);
412 #endif
413                                                 if (n <= g && mp->current.beg[n])
414                                                         pc = *mp->current.beg[n];
415                                         }
416                                         /*FALLTHROUGH*/
417                                 default:
418                                         n = 0;
419                                         break;
420                                 }
421                                 p = oldp;
422                                 for (;;)
423                                 {
424                                         if ((n || pc == sc) && onematch(mp, g, olds, p, e, NiL, flags)) return(1);
425                                         if (!sc) return(0);
426                                         olds = s;
427                                         sc = getsource(s, e);
428                                 }
429                         }
430                         else if (pc != '?' && pc != sc) return(0);
431                         break;
432                 case 0:
433                         if (!(flags & STR_MAXIMAL)) sc = 0;
434                         /*FALLTHROUGH*/
435                 case '|':
436                 case '&':
437                 case ')':
438                         if (!sc)
439                         {
440                                 mp->current.next_s = olds;
441                                 mp->next_p = oldp;
442                                 mp->current.groups = g;
443                         }
444                         if (!pc && (!mp->best.next_s || (flags & STR_MAXIMAL) && olds > mp->best.next_s || !(flags & STR_MAXIMAL) && olds < mp->best.next_s))
445                         {
446                                 mp->best = mp->current;
447                                 mp->best.next_s = olds;
448                                 mp->best.groups = g;
449 #if _DEBUG_MATCH
450                                 error(-3, "best#%d groups=%d next=\"%s\"", __LINE__, mp->best.groups, mp->best.next_s);
451 #endif
452                         }
453                         return(!sc);
454                 case '[':
455                         {
456                                 /*UNDENT...*/
457
458         int     invert;
459         int     x;
460         int     ok = 0;
461         char*   range;
462
463         if (!sc)
464                 return(0);
465 #if _lib_fnmatch
466         if (ast.locale.set & LC_SET_COLLATE) range = p - 1;
467         else
468 #endif
469         range = 0;
470         n = 0;
471         if (invert = *p == '!') p++;
472         for (;;)
473         {
474                 oldp = p;
475                 if (!(pc = mbgetchar(p))) return(0);
476                 else if (pc == '[' && (*p == ':' || *p == '=' || *p == '.'))
477                 {
478                         x = 0;
479                         n = mbgetchar(p);
480                         oldp = p;
481                         for (;;)
482                         {
483                                 if (!(pc = mbgetchar(p))) return(0);
484                                 if (pc == n && *p == ']') break;
485                                 x++;
486                         }
487                         mbgetchar(p);
488                         if (ok) /*NOP*/;
489                         else if (n == ':')
490                         {
491                                 switch (CODE(x, oldp[0], oldp[1], oldp[2], oldp[3], oldp[4]))
492                                 {
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 )
500                                 */
501                                 case CODE(5,'a','l','n','u','m'):
502                                         if (isalnum(sc)) ok = 1;
503                                         break;
504                                 case CODE(5,'a','l','p','h','a'):
505                                         if (isalpha(sc)) ok = 1;
506                                         break;
507                                 case CODE(5,'b','l','a','n','k'):
508                                         if (isblank(sc)) ok = 1;
509                                         break;
510                                 case CODE(5,'c','n','t','r','l'):
511                                         if (iscntrl(sc)) ok = 1;
512                                         break;
513                                 case CODE(5,'d','i','g','i','t'):
514                                         if (isdigit(sc)) ok = 1;
515                                         break;
516                                 case CODE(5,'g','r','a','p','h'):
517                                         if (isgraph(sc)) ok = 1;
518                                         break;
519                                 case CODE(5,'l','o','w','e','r'):
520                                         if (islower(sc)) ok = 1;
521                                         break;
522                                 case CODE(5,'p','r','i','n','t'):
523                                         if (isprint(sc)) ok = 1;
524                                         break;
525                                 case CODE(5,'p','u','n','c','t'):
526                                         if (ispunct(sc)) ok = 1;
527                                         break;
528                                 case CODE(5,'s','p','a','c','e'):
529                                         if (isspace(sc)) ok = 1;
530                                         break;
531                                 case CODE(5,'u','p','p','e','r'):
532                                         if (isupper(sc)) ok = 1;
533                                         break;
534                                 case CODE(6,'x','d','i','g','i'):
535                                         if (oldp[5] == 't' && isxdigit(sc)) ok = 1;
536                                         break;
537 #if _lib_wctype
538                                 default:
539                                         {
540                                                 char    cc[32];
541
542                                                 if (x >= sizeof(cc))
543                                                         x = sizeof(cc) - 1;
544                                                 strncpy(cc, oldp, x);
545                                                 cc[x] = 0;
546                                                 if (iswctype(sc, wctype(cc))) ok = 1;
547                                         }
548                                         break;
549 #endif
550                                 }
551                         }
552 #if _lib_fnmatch
553                         else if (ast.locale.set & LC_SET_COLLATE)
554                                 ok = -1;
555 #endif
556                         else if (range)
557                                 goto getrange;
558                         else if (*p == '-' && *(p + 1) != ']')
559                         {
560                                 mbgetchar(p);
561                                 range = oldp;
562                         }
563                         else if (isalpha(*oldp) && isalpha(*olds) && tolower(*oldp) == tolower(*olds) || sc == mbgetchar(oldp))
564                                 ok = 1;
565                         n = 1;
566                 }
567                 else if (pc == ']' && n)
568                 {
569 #if _lib_fnmatch
570                         if (ok < 0)
571                         {
572                                 char    pat[2 * UCHAR_MAX];
573                                 char    str[COLL_MAX + 1];
574
575                                 if (p - range > sizeof(pat) - 2)
576                                         return(0);
577                                 memcpy(pat, range, p - range);
578                                 pat[p - range] = '*';
579                                 pat[p - range + 1] = 0;
580                                 if (fnmatch(pat, olds, 0))
581                                         return(0);
582                                 pat[p - range] = 0;
583                                 ok = 0;
584                                 for (x = 0; x < sizeof(str) - 1 && olds[x]; x++)
585                                 {
586                                         str[x] = olds[x];
587                                         str[x + 1] = 0;
588                                         if (!fnmatch(pat, str, 0))
589                                                 ok = 1;
590                                         else if (ok)
591                                                 break;
592                                 }
593                                 s = olds + x;
594                                 break;
595                         }
596 #endif
597                         if (ok != invert) break;
598                         return(0);
599                 }
600                 else if (pc == '\\' && (oldp = p, !(pc = mbgetchar(p)))) return(0);
601                 else if (ok) /*NOP*/;
602 #if _lib_fnmatch
603                 else if (range && !(ast.locale.set & LC_SET_COLLATE))
604 #else
605                 else if (range)
606 #endif
607                 {
608                 getrange:
609 #if _lib_mbtowc
610                         if (ast.locale.set & LC_SET_CTYPE)
611                         {
612                                 wchar_t sw;
613                                 wchar_t bw;
614                                 wchar_t ew;
615                                 int     sz;
616                                 int     bz;
617                                 int     ez;
618
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)
623                                         ok = 1;
624                                 else if (sz > 1 || bz > 1 || ez > 1)
625                                 {
626                                         if (sz == bz && sz == ez && sw > bw && sw < ew)
627                                                 ok = 1;
628                                         else return(0);
629                                 }
630                         }
631                         if (!ok)
632 #endif
633                         if (sc == (x = mbgetchar(range)) || sc == (pc = mbgetchar(oldp)) || sc > x && sc < pc)
634                                 ok = 1;
635                         range = 0;
636                         n = 1;
637                 }
638                 else if (*p == '-' && *(p + 1) != ']')
639                 {
640                         mbgetchar(p);
641 #if _lib_fnmatch
642                         if (ast.locale.set & LC_SET_COLLATE) ok = -1;
643                         else
644 #endif
645                         range = oldp;
646                         n = 1;
647                 }
648                 else
649                 {
650                         if (sc == pc) ok = 1;
651                         n = pc;
652                 }
653         }
654
655                                 /*...INDENT*/
656                         }
657                         break;
658                 case '\\':
659                         if (!(pc = mbgetchar(p))) return(0);
660                         if (pc >= '0' && pc <= '9')
661                         {
662                                 n = pc - '0';
663 #if _DEBUG_MATCH
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]);
665 #endif
666                                 if (n <= g && (oldp = mp->current.beg[n]))
667                                 {
668                                         while (oldp < mp->current.end[n])
669                                                 if (!*olds || *olds++ != *oldp++)
670                                                         return(0);
671                                         s = olds;
672                                         break;
673                                 }
674                         }
675                         /*FALLTHROUGH*/
676                 default:
677                         if (pc != sc) return(0);
678                         break;
679                 }
680         } while (sc);
681         return(0);
682 }
683
684 /*
685  * match any pattern in a group
686  * | and & subgroups are parsed here
687  */
688
689 static int
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;){
691         register char*  a;
692
693 #if _DEBUG_MATCH
694         error_info.indent++;
695         error(-1, "grpmatch g=%d s=%-.*s p=%s flags=%o", g, e - s, s, p, flags);
696 #endif
697         do
698         {
699                 for (a = p; onematch(mp, g, s, a, e, NiL, flags); a++)
700                         if (*(a = mp->next_p) != '&')
701                                 return(1);
702         } while (p = gobble(mp, p, '|', &g, 1));
703         return(0);
704 }
705
706 #if _DEBUG_MATCH
707 #undef  return
708 #endif
709
710 /*
711  * subgroup match
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
717  * including s+sub[1]
718  */
719
720 int
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;){
722         register int    i;
723         register char*  s;
724         char*           e;
725         Match_t         match;
726
727         s = (char*)b;
728         match.last_s = e = s + strlen(s);
729         for (;;)
730         {
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)
734                 {
735                         if (!i) match.current = match.best;
736                         match.current.groups++;
737                         match.current.end[0] = match.current.next_s;
738 #if _DEBUG_MATCH
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);
740 #endif
741                         break;
742                 }
743                 if ((flags & STR_LEFT) || s >= e)
744                         return(0);
745                 s++;
746         }
747         if ((flags & STR_RIGHT) && match.current.next_s != e)
748                 return(0);
749         if (!sub)
750                 return(1);
751         match.current.beg[0] = s;
752         s = (char*)b;
753         if (n > match.current.groups)
754                 n = match.current.groups;
755         for (i = 0; i < n; i++)
756         {
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;
759         }
760         return(n);
761 }
762
763 /*
764  * compare the string s with the shell pattern p
765  * returns 1 for match 0 otherwise
766  */
767
768 int
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));
771 }
772
773 /*
774  * leading substring match
775  * first char after end of substring returned
776  * 0 returned if no match
777  *
778  * OBSOLETE: use strgrpmatch()
779  */
780
781 char*
782 strsubmatch __PARAM__((const char* s, const char* p, int flags), (s, p, flags)) __OTORP__(const char* s; const char* p; int flags;){
783         int     match[2];
784
785         return(strgrpmatch(s, p, match, 1, (flags ? STR_MAXIMAL : 0)|STR_LEFT) ? (char*)s + match[1] : (char*)0);
786 }