Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSvc / DtCodelibs / strwcmp.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 librararies 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 /*
24  * $TOG: strwcmp.C /main/7 1998/04/17 11:25:04 mgreess $
25  *
26  * (c) Copyright 1996 Digital Equipment Corporation.
27  * (c) Copyright 1993,1994,1996 Hewlett-Packard Company.
28  * (c) Copyright 1993,1994,1996 International Business Machines Corp.
29  * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
30  * (c) Copyright 1993,1994,1996 Novell, Inc. 
31  * (c) Copyright 1996 FUJITSU LIMITED.
32  * (c) Copyright 1996 Hitachi.
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <limits.h>
38 #include <codelibs/nl_hack.h>
39 #include <string.h>
40 #include <codelibs/stringx.h>
41
42 #define QUOTE 0x40000000
43
44 #ifdef DEBUG
45     static char tabs[] = "          ";
46 #   define TABS (&tabs[10 - depth])
47
48     static int
49     RETURN(int ret, int depth)
50     {
51         printf("%sreturning %s\n", TABS,
52                 (ret ? "SUCCEEDED" : "FAILED"));
53         return ret;
54     }
55 #else
56 #define RETURN(x,y) (x)
57 #endif
58
59 /* FORWARD */
60 static int match(const char *, const char *, int);
61 static const char *next_patt(const char *, int advance = 1);
62 static int match_class(const char *, char);
63
64 /* INLINE */
65 static int
66 next_char(register const char *pattern, const char **cpp = NULL)
67 {
68     register int ret;
69     wchar_t __nlh_char[1];
70
71     ret = pattern ? (int)CHARAT(pattern) : '\0';
72     if (ret != '\0')
73     {
74         ADVANCE(pattern);
75         /* AIX needs line broken to get around macro bug (Temporary Fix) */
76         if (ret == '\\' &&
77             CHARAT(pattern) != '\0')
78             ret = QUOTE | (int)CHARADV(pattern);
79     }
80
81     if (cpp != NULL)
82         *cpp = pattern;
83     return ret;
84 }
85
86 int
87 strwcmp(const char *pattern, const char *string)
88 /*
89  * String  'pattern'  is matched  against  string  'string'.  Zero is
90  * returned  if the match is  successful.  'pattern'  may  contain the
91  * shell metas * and ?  and the  semantics are the same.  ?  and * may
92  * be escaped with \
93  */
94 {
95     return !match(pattern, string, 0);
96 }
97
98 // stwpat returns a pointer to the first meta-character if the string
99 // is a pattern, else NULL
100 char *
101 strwpat(register const char *pattern)
102 {
103     register int ch;
104     register char *prev_pattern = (char *)pattern;
105     wchar_t __nlh_char[1];
106
107     while ((ch = next_char(pattern, &pattern)) != '\0')
108     {
109         switch (ch)
110         {
111         case '*': 
112             return prev_pattern;
113         case '?': 
114             return prev_pattern;
115         case '[': {
116             register const char *eop = next_patt(prev_pattern, 0);
117             if (CHARAT(eop) == ']')
118                 return prev_pattern;
119             break;
120         }
121         }
122
123         prev_pattern = (char *)pattern;
124     }
125
126     return NULL;
127 }
128
129 /*
130  * match will check to see if pattern can successfully be applied to
131  * the beginning of string.
132  */
133 static int 
134 match(register const char *pattern, register const char *string, int depth)
135 {
136 #ifdef DEBUG
137     printf("%smatch(\"%s\", \"%s\")\n", TABS, pattern, string);
138 #endif
139     int ch;
140     const char *cp;
141     wchar_t __nlh_char[1];
142
143     while ((ch = next_char(pattern, &cp)) != '\0')
144     {
145         const char *laststr = string;
146         register int testchar = (int)CHARADV(string);
147
148         switch (ch)
149         {
150         case '*': {
151             pattern = cp;       /* skip over '*' */
152             string = laststr;   /* reverse - testchar not used */
153
154             const char *s = string;
155             do
156                 if (match(pattern, s, depth + 1))
157                     return RETURN(1, depth);
158             while (CHARADV(s) != '\0');
159             return RETURN(0, depth);
160         }
161         case '?': 
162             break;
163         case '[': {
164             int mt = match_class(pattern, testchar);
165             if (mt == 0)
166                 return RETURN(0, depth);
167             else if (mt == 2 && ch != testchar)
168                 return RETURN(0, depth);
169             break;
170         }
171         default: 
172             if ((ch & ~QUOTE) != testchar)
173                 return RETURN(0, depth);
174             break;
175         }
176
177         if (testchar == '\0')
178             string = laststr;   // reverse string
179
180         pattern = next_patt(pattern);
181     }
182
183     return RETURN(CHARAT(string) == '\0', depth);
184 }
185
186 static int
187 match_class(register const char *clss, register char testchar)
188 /*
189  *      pattern is a pointer to the leading [ of
190  *      a shell-type class.  testchar is the character to match against
191  *      the class.
192  */
193 {
194     int match = 1;              /* false if first char is '!' */
195     wchar_t __nlh_char[1];
196
197     /* find end of class, ie an un-escaped ']' */
198     register const char *eop = next_patt(clss, 0);
199     ADVANCE(clss);
200
201     if (CHARAT(eop) != ']')
202         return 2;
203
204     if (CHARAT(clss) == '!')
205     {
206         match = 0;
207         ADVANCE(clss);
208     }
209
210     while (clss < eop)
211     {
212         register int ch = next_char(clss, &clss);
213         char const *clss_end = clss;
214         int sep = next_char(clss_end, &clss_end);
215         int ch2 = next_char(clss_end, &clss_end);
216
217         /* check if next three chars are a range */
218         if (sep == '-' && ch2 != ']')
219         {
220             /* check range - we have to use strcoll to do it right */
221             char c1[MB_LEN_MAX+1], c2[MB_LEN_MAX+1], tc[MB_LEN_MAX+1];
222             memset(c1, 0, sizeof(c1));
223             memset(c2, 0, sizeof(c2));
224             memset(tc, 0, sizeof(tc));
225             ch &= ~QUOTE;
226             WCHAR(ch, c1);
227             ch2 &= ~QUOTE;
228             WCHAR(ch2, c2);
229             WCHAR(testchar, tc);
230
231             /* if (ch <= testchar && testchar <= ch2) // Original code */
232
233             /* Second implementation:
234              * if (nl_strncmp(c1, tc, 1) <= 0 && nl_strncmp(tc, c2, 1) <= 0)
235              *     return match;
236              */
237
238             /* Third, portable implementation: */
239             if (strcoll(c1, tc) <= 0 && strcoll(tc, c2) <= 0)
240                 return match;
241             clss = clss_end;
242         }
243         else                    /* they are not a range, check simple
244                                    match */
245         {
246             if ((ch & ~QUOTE) == testchar)
247                 return match;
248         }
249     }
250
251     return !match;
252 }
253
254 static const char *
255 next_patt(register const char *pattern, int advance)
256 {
257     wchar_t __nlh_char[1];
258
259     if (CHARAT(pattern) == '[')
260     {
261         int ch;
262         const char *pp = pattern;
263         ADVANCE(pp);
264
265         if (CHARAT(pp) == '^')
266             ADVANCE(pp);
267
268         if (CHARAT(pp) == ']')
269             ADVANCE(pp);
270
271         char const *np;
272         for (; (ch = next_char(pp, &np)) != '\0'; pp = np)
273             if (ch == ']')
274                 return (advance ? np : pp);
275     }
276
277     next_char(pattern, &pattern);
278     return pattern;
279 }
280
281 #ifdef DEBUG
282 #define MAIN main
283 MAIN()
284 {
285     char pattern[50], string[50];
286
287     while (1)
288     {
289         putchar('\n');
290         printf("pattern:  ");
291         if (fgets(pattern, sizeof(pattern)-1, stdin) == NULL)
292             break;
293         printf("string:   ");
294         if (fgets(string, sizeof(pattern)-1, stdin) == NULL)
295             break;
296         printf("MATCH is %s\n",
297                 ((strwcmp(pattern, string) == 0) ? "SUCCEEDED" : "FAILED"));
298         putchar('\n');
299         printf("MATCHI is %s\n",
300                 ((strwcmpi(pattern, string) == 0) ? "SUCCEEDED" : "FAILED"));
301     }
302
303     return 0;
304 }
305 #endif