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