Bash-4.2 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, *wbrack;
81   int matlen, 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           wbrack = wpat;
122           wc = *wpat++;
123           do
124             {
125               if (wc == 0)
126                 {
127                   matlen += wpat - wbrack - 1;  /* incremented below */
128                   break;
129                 }
130               else if (wc == L'\\')
131                 {
132                   wc = *wpat++;
133                   if (*wpat == 0)
134                     break;
135                 }
136               else if (wc == L'[' && *wpat == L':')     /* character class */
137                 {
138                   wpat++;
139                   in_cclass = 1;
140                 }
141               else if (in_cclass && wc == L':' && *wpat == L']')
142                 {
143                   wpat++;
144                   in_cclass = 0;
145                 }
146               else if (wc == L'[' && *wpat == L'.')     /* collating symbol */
147                 {
148                   wpat++;
149                   if (*wpat == L']')    /* right bracket can appear as collating symbol */
150                     wpat++;
151                   in_collsym = 1;
152                 }
153               else if (in_collsym && wc == L'.' && *wpat == L']')
154                 {
155                   wpat++;
156                   in_collsym = 0;
157                 }
158               else if (wc == L'[' && *wpat == L'=')     /* equivalence class */
159                 {
160                   wpat++;
161                   if (*wpat == L']')    /* right bracket can appear as equivalence class */
162                     wpat++;
163                   in_equiv = 1;
164                 }
165               else if (in_equiv && wc == L'=' && *wpat == L']')
166                 {
167                   wpat++;
168                   in_equiv = 0;
169                 }
170             }
171           while ((wc = *wpat++) != L']');
172           matlen++;             /* bracket expression can only match one char */
173           break;
174         }
175     }
176
177   return matlen;
178 }
179 #endif
180
181 /* Return 1 of the first character of STRING could match the first
182    character of pattern PAT.  Used to avoid n2 calls to strmatch(). */
183 int
184 match_pattern_char (pat, string)
185      char *pat, *string;
186 {
187   char c;
188
189   if (*string == 0)
190     return (0);
191
192   switch (c = *pat++)
193     {
194     default:
195       return (*string == c);
196     case '\\':
197       return (*string == *pat);
198     case '?':
199       return (*pat == LPAREN ? 1 : (*string != '\0'));
200     case '*':
201       return (1);
202     case '+':
203     case '!':
204     case '@':
205       return (*pat == LPAREN ? 1 : (*string == c));
206     case '[':
207       return (*string != '\0');
208     }
209 }
210
211 int
212 umatchlen (pat, max)
213      char *pat;
214      size_t max;
215 {
216   char c, *brack;
217   int matlen, t, in_cclass, in_collsym, in_equiv;
218
219   if (*pat == 0)
220     return (0);
221
222   matlen = in_cclass = in_collsym = in_equiv = 0;
223   while (c = *pat++)
224     {
225       switch (c)
226         {
227         default:
228           matlen++;
229           break;
230         case '\\':
231           if (*pat == 0)
232             return ++matlen;
233           else
234             {
235               matlen++;
236               pat++;
237             }
238           break;
239         case '?':
240           if (*pat == LPAREN)
241             return (matlen = -1);               /* XXX for now */
242           else
243             matlen++;
244           break;
245         case '*':
246           return (matlen = -1);
247         case '+':
248         case '!':
249         case '@':
250           if (*pat == LPAREN)
251             return (matlen = -1);               /* XXX for now */
252           else
253             matlen++;
254           break;
255         case '[':
256           /* scan for ending `]', skipping over embedded [:...:] */
257           brack = pat;
258           c = *pat++;
259           do
260             {
261               if (c == 0)
262                 {
263                   matlen += pat - brack - 1;    /* incremented below */
264                   break;
265                 }
266               else if (c == '\\')
267                 {
268                   c = *pat++;
269                   if (*pat == 0)
270                     break;
271                 }
272               else if (c == '[' && *pat == ':') /* character class */
273                 {
274                   pat++;
275                   in_cclass = 1;
276                 }
277               else if (in_cclass && c == ':' && *pat == ']')
278                 {
279                   pat++;
280                   in_cclass = 0;
281                 }
282               else if (c == '[' && *pat == '.') /* collating symbol */
283                 {
284                   pat++;
285                   if (*pat == ']')      /* right bracket can appear as collating symbol */
286                     pat++;
287                   in_collsym = 1;
288                 }
289               else if (in_collsym && c == '.' && *pat == ']')
290                 {
291                   pat++;
292                   in_collsym = 0;
293                 }
294               else if (c == '[' && *pat == '=') /* equivalence class */
295                 {
296                   pat++;
297                   if (*pat == ']')      /* right bracket can appear as equivalence class */
298                     pat++;
299                   in_equiv = 1;
300                 }
301               else if (in_equiv && c == '=' && *pat == ']')
302                 {
303                   pat++;
304                   in_equiv = 0;
305                 }
306             }
307           while ((c = *pat++) != ']');
308           matlen++;             /* bracket expression can only match one char */
309           break;
310         }
311     }
312
313   return matlen;
314 }