Bash-4.3 distribution sources and documentation
[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 int
204 extglob_pattern_p (pat)
205      char *pat;
206 {
207   switch (pat[0])
208     {
209     case '*':
210     case '+':
211     case '!':
212     case '@':
213       return (pat[1] == LPAREN);
214     default:
215       return 0;
216     }
217     
218   return 0;
219 }
220
221 /* Return 1 of the first character of STRING could match the first
222    character of pattern PAT.  Used to avoid n2 calls to strmatch(). */
223 int
224 match_pattern_char (pat, string)
225      char *pat, *string;
226 {
227   char c;
228
229   if (*string == 0)
230     return (0);
231
232   switch (c = *pat++)
233     {
234     default:
235       return (*string == c);
236     case '\\':
237       return (*string == *pat);
238     case '?':
239       return (*pat == LPAREN ? 1 : (*string != '\0'));
240     case '*':
241       return (1);
242     case '+':
243     case '!':
244     case '@':
245       return (*pat == LPAREN ? 1 : (*string == c));
246     case '[':
247       return (*string != '\0');
248     }
249 }
250
251 int
252 umatchlen (pat, max)
253      char *pat;
254      size_t max;
255 {
256   char c;
257   int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
258
259   if (*pat == 0)
260     return (0);
261
262   matlen = in_cclass = in_collsym = in_equiv = 0;
263   while (c = *pat++)
264     {
265       switch (c)
266         {
267         default:
268           matlen++;
269           break;
270         case '\\':
271           if (*pat == 0)
272             return ++matlen;
273           else
274             {
275               matlen++;
276               pat++;
277             }
278           break;
279         case '?':
280           if (*pat == LPAREN)
281             return (matlen = -1);               /* XXX for now */
282           else
283             matlen++;
284           break;
285         case '*':
286           return (matlen = -1);
287         case '+':
288         case '!':
289         case '@':
290           if (*pat == LPAREN)
291             return (matlen = -1);               /* XXX for now */
292           else
293             matlen++;
294           break;
295         case '[':
296           /* scan for ending `]', skipping over embedded [:...:] */
297           bracklen = 1;
298           c = *pat++;
299           do
300             {
301               if (c == 0)
302                 {
303                   pat--;                        /* back up to NUL */
304                   matlen += bracklen;
305                   goto bad_bracket;
306                 }
307               else if (c == '\\')
308                 {
309                   /* *pat == backslash-escaped character */
310                   bracklen++;
311                   /* If the backslash or backslash-escape ends the string,
312                      bail.  The ++pat skips over the backslash escape */
313                   if (*pat == 0 || *++pat == 0)
314                     {
315                       matlen += bracklen;
316                       goto bad_bracket;
317                     }
318                 }
319               else if (c == '[' && *pat == ':') /* character class */
320                 {
321                   pat++;
322                   bracklen++;
323                   in_cclass = 1;
324                 }
325               else if (in_cclass && c == ':' && *pat == ']')
326                 {
327                   pat++;
328                   bracklen++;
329                   in_cclass = 0;
330                 }
331               else if (c == '[' && *pat == '.') /* collating symbol */
332                 {
333                   pat++;
334                   bracklen++;
335                   if (*pat == ']')      /* right bracket can appear as collating symbol */
336                     {
337                       pat++;
338                       bracklen++;
339                     }
340                   in_collsym = 1;
341                 }
342               else if (in_collsym && c == '.' && *pat == ']')
343                 {
344                   pat++;
345                   bracklen++;
346                   in_collsym = 0;
347                 }
348               else if (c == '[' && *pat == '=') /* equivalence class */
349                 {
350                   pat++;
351                   bracklen++;
352                   if (*pat == ']')      /* right bracket can appear as equivalence class */
353                     {
354                       pat++;
355                       bracklen++;
356                     }
357                   in_equiv = 1;
358                 }
359               else if (in_equiv && c == '=' && *pat == ']')
360                 {
361                   pat++;
362                   bracklen++;
363                   in_equiv = 0;
364                 }
365               else
366                 bracklen++;
367             }
368           while ((c = *pat++) != ']');
369           matlen++;             /* bracket expression can only match one char */
370 bad_bracket:
371           break;
372         }
373     }
374
375   return matlen;
376 }