683035a2510df47c00e8f79364e7ba71c125e218
[platform/upstream/bash.git] / lib / glob / gmisc.c
1 /* gmisc.c -- miscellaneous pattern matching utility functions for Bash.
2
3    Copyright (C) 2010 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne-Again SHell.
6    
7    Bash is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Bash is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include "bashtypes.h"
24
25 #if defined (HAVE_UNISTD_H)
26 #  include <unistd.h>
27 #endif
28
29 #include "bashansi.h"
30 #include "shmbutil.h"
31
32 #include "stdc.h"
33
34 #ifndef LPAREN
35 #  define LPAREN '('
36 #endif
37 #ifndef RPAREN
38 #  define RPAREN ')'
39 #endif
40
41 #if defined (HANDLE_MULTIBYTE)
42 #define WLPAREN         L'('
43 #define WRPAREN         L')'
44
45 /* Return 1 of the first character of WSTRING could match the first
46    character of pattern WPAT.  Wide character version. */
47 int
48 match_pattern_wchar (wpat, wstring)
49      wchar_t *wpat, *wstring;
50 {
51   wchar_t wc;
52
53   if (*wstring == 0)
54     return (0);
55
56   switch (wc = *wpat++)
57     {
58     default:
59       return (*wstring == wc);
60     case L'\\':
61       return (*wstring == *wpat);
62     case L'?':
63       return (*wpat == WLPAREN ? 1 : (*wstring != L'\0'));
64     case L'*':
65       return (1);
66     case L'+':
67     case L'!':
68     case L'@':
69       return (*wpat == WLPAREN ? 1 : (*wstring == wc));
70     case L'[':
71       return (*wstring != L'\0');
72     }
73 }
74
75 int
76 wmatchlen (wpat, wmax)
77      wchar_t *wpat;
78      size_t wmax;
79 {
80   wchar_t wc;
81   int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
82
83   if (*wpat == 0)
84     return (0);
85
86   matlen = in_cclass = in_collsym = in_equiv = 0;
87   while (wc = *wpat++)
88     {
89       switch (wc)
90         {
91         default:
92           matlen++;
93           break;
94         case L'\\':
95           if (*wpat == 0)
96             return ++matlen;
97           else
98             {
99               matlen++;
100               wpat++;
101             }
102           break;
103         case L'?':
104           if (*wpat == WLPAREN)
105             return (matlen = -1);               /* XXX for now */
106           else
107             matlen++;
108           break;
109         case L'*':
110           return (matlen = -1);
111         case L'+':
112         case L'!':
113         case L'@':
114           if (*wpat == WLPAREN)
115             return (matlen = -1);               /* XXX for now */
116           else
117             matlen++;
118           break;
119         case L'[':
120           /* scan for ending `]', skipping over embedded [:...:] */
121           bracklen = 1;
122           wc = *wpat++;
123           do
124             {
125               if (wc == 0)
126                 {
127                   wpat--;                       /* back up to NUL */
128                   matlen += bracklen;
129                   goto bad_bracket;
130                 }
131               else if (wc == L'\\')
132                 {
133                   /* *wpat == backslash-escaped character */
134                   bracklen++;
135                   /* If the backslash or backslash-escape ends the string,
136                      bail.  The ++wpat skips over the backslash escape */
137                   if (*wpat == 0 || *++wpat == 0)
138                     {
139                       matlen += bracklen;
140                       goto bad_bracket;
141                     }
142                 }
143               else if (wc == L'[' && *wpat == L':')     /* character class */
144                 {
145                   wpat++;
146                   bracklen++;
147                   in_cclass = 1;
148                 }
149               else if (in_cclass && wc == L':' && *wpat == L']')
150                 {
151                   wpat++;
152                   bracklen++;
153                   in_cclass = 0;
154                 }
155               else if (wc == L'[' && *wpat == L'.')     /* collating symbol */
156                 {
157                   wpat++;
158                   bracklen++;
159                   if (*wpat == L']')    /* right bracket can appear as collating symbol */
160                     {
161                       wpat++;
162                       bracklen++;
163                     }
164                   in_collsym = 1;
165                 }
166               else if (in_collsym && wc == L'.' && *wpat == L']')
167                 {
168                   wpat++;
169                   bracklen++;
170                   in_collsym = 0;
171                 }
172               else if (wc == L'[' && *wpat == L'=')     /* equivalence class */
173                 {
174                   wpat++;
175                   bracklen++;
176                   if (*wpat == L']')    /* right bracket can appear as equivalence class */
177                     {
178                       wpat++;
179                       bracklen++;
180                     }
181                   in_equiv = 1;
182                 }
183               else if (in_equiv && wc == L'=' && *wpat == L']')
184                 {
185                   wpat++;
186                   bracklen++;
187                   in_equiv = 0;
188                 }
189               else
190                 bracklen++;
191             }
192           while ((wc = *wpat++) != L']');
193           matlen++;             /* bracket expression can only match one char */
194 bad_bracket:
195           break;
196         }
197     }
198
199   return matlen;
200 }
201 #endif
202
203 /* Return 1 of the first character of STRING could match the first
204    character of pattern PAT.  Used to avoid n2 calls to strmatch(). */
205 int
206 match_pattern_char (pat, string)
207      char *pat, *string;
208 {
209   char c;
210
211   if (*string == 0)
212     return (0);
213
214   switch (c = *pat++)
215     {
216     default:
217       return (*string == c);
218     case '\\':
219       return (*string == *pat);
220     case '?':
221       return (*pat == LPAREN ? 1 : (*string != '\0'));
222     case '*':
223       return (1);
224     case '+':
225     case '!':
226     case '@':
227       return (*pat == LPAREN ? 1 : (*string == c));
228     case '[':
229       return (*string != '\0');
230     }
231 }
232
233 int
234 umatchlen (pat, max)
235      char *pat;
236      size_t max;
237 {
238   char c;
239   int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
240
241   if (*pat == 0)
242     return (0);
243
244   matlen = in_cclass = in_collsym = in_equiv = 0;
245   while (c = *pat++)
246     {
247       switch (c)
248         {
249         default:
250           matlen++;
251           break;
252         case '\\':
253           if (*pat == 0)
254             return ++matlen;
255           else
256             {
257               matlen++;
258               pat++;
259             }
260           break;
261         case '?':
262           if (*pat == LPAREN)
263             return (matlen = -1);               /* XXX for now */
264           else
265             matlen++;
266           break;
267         case '*':
268           return (matlen = -1);
269         case '+':
270         case '!':
271         case '@':
272           if (*pat == LPAREN)
273             return (matlen = -1);               /* XXX for now */
274           else
275             matlen++;
276           break;
277         case '[':
278           /* scan for ending `]', skipping over embedded [:...:] */
279           bracklen = 1;
280           c = *pat++;
281           do
282             {
283               if (c == 0)
284                 {
285                   pat--;                        /* back up to NUL */
286                   matlen += bracklen;
287                   goto bad_bracket;
288                 }
289               else if (c == '\\')
290                 {
291                   /* *pat == backslash-escaped character */
292                   bracklen++;
293                   /* If the backslash or backslash-escape ends the string,
294                      bail.  The ++pat skips over the backslash escape */
295                   if (*pat == 0 || *++pat == 0)
296                     {
297                       matlen += bracklen;
298                       goto bad_bracket;
299                     }
300                 }
301               else if (c == '[' && *pat == ':') /* character class */
302                 {
303                   pat++;
304                   bracklen++;
305                   in_cclass = 1;
306                 }
307               else if (in_cclass && c == ':' && *pat == ']')
308                 {
309                   pat++;
310                   bracklen++;
311                   in_cclass = 0;
312                 }
313               else if (c == '[' && *pat == '.') /* collating symbol */
314                 {
315                   pat++;
316                   bracklen++;
317                   if (*pat == ']')      /* right bracket can appear as collating symbol */
318                     {
319                       pat++;
320                       bracklen++;
321                     }
322                   in_collsym = 1;
323                 }
324               else if (in_collsym && c == '.' && *pat == ']')
325                 {
326                   pat++;
327                   bracklen++;
328                   in_collsym = 0;
329                 }
330               else if (c == '[' && *pat == '=') /* equivalence class */
331                 {
332                   pat++;
333                   bracklen++;
334                   if (*pat == ']')      /* right bracket can appear as equivalence class */
335                     {
336                       pat++;
337                       bracklen++;
338                     }
339                   in_equiv = 1;
340                 }
341               else if (in_equiv && c == '=' && *pat == ']')
342                 {
343                   pat++;
344                   bracklen++;
345                   in_equiv = 0;
346                 }
347               else
348                 bracklen++;
349             }
350           while ((c = *pat++) != ']');
351           matlen++;             /* bracket expression can only match one char */
352 bad_bracket:
353           break;
354         }
355     }
356
357   return matlen;
358 }