]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/glob.cc
Cygwin: add release message for latest pipe changes
[newlib-cygwin.git] / winsup / cygwin / glob.cc
CommitLineData
1fd5e000
CF
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Guido van Rossum.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
1fd5e000
CF
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
48f81ac6
CV
33#ifdef __CYGWIN__
34#include "winsup.h"
35#endif
36
733c9ed3
CV
37#if defined(LIBC_SCCS) && !defined(lint)
38static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
39#endif /* LIBC_SCCS and not lint */
d7bcd2a1
CV
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.28 2010/05/12 17:44:00 gordon Exp $");
1fd5e000
CF
42
43/*
44 * glob(3) -- a superset of the one defined in POSIX 1003.2.
45 *
46 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
47 *
48 * Optional extra services, controlled by flags not defined by POSIX:
49 *
50 * GLOB_QUOTE:
51 * Escaping convention: \ inhibits any special meaning the following
52 * character might have (except \ at end of string is retained).
53 * GLOB_MAGCHAR:
54 * Set in gl_flags if pattern contained a globbing character.
55 * GLOB_NOMAGIC:
56 * Same as GLOB_NOCHECK, but it will only append pattern if it did
57 * not contain any magic characters. [Used in csh style globbing]
58 * GLOB_ALTDIRFUNC:
59 * Use alternately specified directory access functions.
60 * GLOB_TILDE:
61 * expand ~user/foo to the /home/dir/of/user/foo
62 * GLOB_BRACE:
75a57bf0 63 * expand {1,2}{a,b} to 1a 1b 2a 2b
1fd5e000
CF
64 * gl_matchc:
65 * Number of matches in the current invocation of glob.
66 */
67
733c9ed3
CV
68/*
69 * Some notes on multibyte character support:
70 * 1. Patterns with illegal byte sequences match nothing - even if
71 * GLOB_NOCHECK is specified.
72 * 2. Illegal byte sequences in filenames are handled by treating them as
73 * single-byte characters with a value of the first byte of the sequence
0321fb57 74 * cast to wint_t.
733c9ed3
CV
75 * 3. State-dependent encodings are not currently supported.
76 */
77
d7bcd2a1
CV
78#include <sys/param.h>
79#include <sys/stat.h>
1fd5e000 80
6ccb6bcf 81#include <ctype.h>
1fd5e000 82#include <dirent.h>
d7bcd2a1 83#include <errno.h>
1fd5e000 84#include <glob.h>
d7bcd2a1 85#include <limits.h>
1fd5e000 86#include <pwd.h>
d7bcd2a1
CV
87#include <stdint.h>
88#include <stdio.h>
1fd5e000 89#include <stdlib.h>
d7bcd2a1 90#include <string.h>
1fd5e000 91#include <unistd.h>
733c9ed3 92#include <wchar.h>
4349a1e4 93#include <wctype.h>
733c9ed3 94
d7bcd2a1 95#include "collate.h"
733c9ed3 96
d7bcd2a1 97#ifdef __CYGWIN__
d7bcd2a1
CV
98#define Cchar(c) (ignore_case_with_glob ? towlower (c) : (c))
99#endif
733c9ed3 100
1d928241
CV
101#undef MAXPATHLEN
102#define MAXPATHLEN 8192
103
1fd5e000
CF
104#define DOLLAR '$'
105#define DOT '.'
d6d44361
CV
106#define COLON ':'
107#define EQUALS '='
1fd5e000
CF
108#define EOS '\0'
109#define LBRACKET '['
110#define NOT '!'
111#define QUESTION '?'
112#define QUOTE '\\'
113#define RANGE '-'
114#define RBRACKET ']'
115#define SEP '/'
116#define STAR '*'
117#define TILDE '~'
118#define UNDERSCORE '_'
119#define LBRACE '{'
120#define RBRACE '}'
121#define SLASH '/'
122#define COMMA ','
123
124#ifndef DEBUG
125
244faaea
CV
126#define M_QUOTE 0x40000000U
127#define M_PROTECT 0x20000000U
128#define M_MASK 0x70ffffffU
129#define M_COLL_MASK 0x700000ffU
6bc687e3 130#define M_CHAR 0x00ffffffU
1fd5e000 131
244faaea 132typedef wint_t Char;
1fd5e000
CF
133
134#else
135
136#define M_QUOTE 0x80
137#define M_PROTECT 0x40
138#define M_MASK 0xff
733c9ed3 139#define M_CHAR 0x7f
1fd5e000
CF
140
141typedef char Char;
142
143#endif
144
145
733c9ed3 146#define CHAR(c) ((Char)((c)&M_CHAR))
1fd5e000
CF
147#define META(c) ((Char)((c)|M_QUOTE))
148#define M_ALL META('*')
149#define M_END META(']')
150#define M_NOT META('!')
151#define M_ONE META('?')
152#define M_RNG META('-')
153#define M_SET META('[')
d6d44361 154#define M_NAMED META(':')
1df19b3c 155#define M_EQUIV META('=')
ce5aa098
CV
156#define M_COLL(_ccnt) META('.' | ((_ccnt) << 8))
157#define M_COLL_P(_c) (((_c) & M_COLL_MASK) == META('.'))
158#define M_COLL_CNT(_c) (((_c) & ~M_COLL_MASK) >> 8)
1fd5e000
CF
159#define ismeta(c) (((c)&M_QUOTE) != 0)
160
733c9ed3
CV
161static int compare(const void *, const void *);
162static int g_Ctoc(const Char *, char *, size_t);
d7bcd2a1 163static int g_lstat(Char *, struct stat *, glob_t *);
733c9ed3 164static DIR *g_opendir(Char *, glob_t *);
0321fb57 165static const Char *g_strchr(const Char *, wint_t);
1fd5e000 166#ifdef notdef
733c9ed3 167static Char *g_strcat(Char *, const Char *);
1fd5e000 168#endif
d7bcd2a1 169static int g_stat(Char *, struct stat *, glob_t *);
733c9ed3
CV
170static int glob0(const Char *, glob_t *, size_t *);
171static int glob1(Char *, glob_t *, size_t *);
172static int glob2(Char *, Char *, Char *, Char *, glob_t *, size_t *);
173static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, size_t *);
174static int globextend(const Char *, glob_t *, size_t *);
46f5dd59 175static const Char *
733c9ed3
CV
176 globtilde(const Char *, Char *, size_t, glob_t *);
177static int globexp1(const Char *, glob_t *, size_t *);
178static int globexp2(const Char *, const Char *, glob_t *, int *, size_t *);
179static int match(Char *, Char *, Char *);
1fd5e000 180#ifdef DEBUG
733c9ed3 181static void qprintf(const char *, Char *);
1fd5e000
CF
182#endif
183
d6d44361
CV
184/* Return value is either EOS, COLON, DOT, EQUALS, or LBRACKET if no class
185 expression found. */
186static inline Char
1df19b3c 187check_classes_expr(const Char *&cptr, wint_t *classbuf = NULL,
d6d44361
CV
188 size_t classbufsize = 0)
189{
190 const Char *ctype = NULL;
191
192 if (*cptr == LBRACKET &&
193 (cptr[1] == COLON || cptr[1] == DOT || cptr[1] == EQUALS)) {
194 ctype = ++cptr;
195 while (*++cptr != EOS &&
196 (*cptr != *ctype || cptr[1] != RBRACKET))
197 ;
198 if (*cptr == EOS)
199 return EOS;
200 if (classbuf) {
201 const Char *class_p = ctype + 1;
202 size_t clen = cptr - class_p;
d6d44361 203
b8196934
CV
204 if (clen < classbufsize)
205 *wcipncpy (classbuf, class_p, clen) = '\0';
206 else
d6d44361
CV
207 ctype = NULL;
208 }
209 cptr++; /* Advance cptr to closing RBRACKET of class expr */
210 }
211 return ctype ? *ctype : LBRACKET;
212}
213
1fd5e000 214int
3073f26d 215glob(const char *__restrict pattern, int flags, int (*errfunc)(const char *, int), glob_t *__restrict pglob)
1fd5e000 216{
733c9ed3
CV
217 const char *patnext;
218 size_t limit;
219 Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
220 mbstate_t mbs;
0321fb57 221 wint_t wc;
733c9ed3
CV
222 size_t clen;
223
224 patnext = pattern;
1fd5e000
CF
225 if (!(flags & GLOB_APPEND)) {
226 pglob->gl_pathc = 0;
227 pglob->gl_pathv = NULL;
228 if (!(flags & GLOB_DOOFFS))
229 pglob->gl_offs = 0;
230 }
733c9ed3
CV
231 if (flags & GLOB_LIMIT) {
232 limit = pglob->gl_matchc;
233 if (limit == 0)
234 limit = ARG_MAX;
235 } else
236 limit = 0;
1fd5e000
CF
237 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
238 pglob->gl_errfunc = errfunc;
239 pglob->gl_matchc = 0;
240
241 bufnext = patbuf;
733c9ed3
CV
242 bufend = bufnext + MAXPATHLEN - 1;
243 if (flags & GLOB_NOESCAPE) {
244 memset(&mbs, 0, sizeof(mbs));
245 while (bufend - bufnext >= MB_CUR_MAX) {
0321fb57 246 clen = mbrtowi(&wc, patnext, MB_LEN_MAX, &mbs);
733c9ed3
CV
247 if (clen == (size_t)-1 || clen == (size_t)-2)
248 return (GLOB_NOMATCH);
249 else if (clen == 0)
250 break;
89afbb8d 251 *bufnext++ = wc;
733c9ed3
CV
252 patnext += clen;
253 }
254 } else {
1fd5e000 255 /* Protect the quoted characters. */
733c9ed3
CV
256 memset(&mbs, 0, sizeof(mbs));
257 while (bufend - bufnext >= MB_CUR_MAX) {
258 if (*patnext == QUOTE) {
259 if (*++patnext == EOS) {
260 *bufnext++ = QUOTE | M_PROTECT;
261 continue;
1fd5e000 262 }
733c9ed3
CV
263 prot = M_PROTECT;
264 } else
265 prot = 0;
0321fb57 266 clen = mbrtowi(&wc, patnext, MB_LEN_MAX, &mbs);
733c9ed3
CV
267 if (clen == (size_t)-1 || clen == (size_t)-2)
268 return (GLOB_NOMATCH);
269 else if (clen == 0)
270 break;
89afbb8d 271 *bufnext++ = wc | prot;
733c9ed3
CV
272 patnext += clen;
273 }
1fd5e000 274 }
1fd5e000
CF
275 *bufnext = EOS;
276
277 if (flags & GLOB_BRACE)
733c9ed3 278 return globexp1(patbuf, pglob, &limit);
1fd5e000 279 else
733c9ed3 280 return glob0(patbuf, pglob, &limit);
1fd5e000
CF
281}
282
283/*
284 * Expand recursively a glob {} pattern. When there is no more expansion
285 * invoke the standard globbing routine to glob the rest of the magic
286 * characters
287 */
733c9ed3
CV
288static int
289globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
1fd5e000
CF
290{
291 const Char* ptr = pattern;
292 int rv;
293
294 /* Protect a single {}, for find(1), like csh */
295 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
733c9ed3 296 return glob0(pattern, pglob, limit);
1fd5e000 297
d7bcd2a1 298 while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
733c9ed3 299 if (!globexp2(ptr, pattern, pglob, &rv, limit))
1fd5e000
CF
300 return rv;
301
733c9ed3 302 return glob0(pattern, pglob, limit);
1fd5e000
CF
303}
304
305
306/*
307 * Recursive brace globbing helper. Tries to expand a single brace.
308 * If it succeeds then it invokes globexp1 with the new pattern.
309 * If it fails then it tries to glob the rest of the pattern and returns.
310 */
733c9ed3
CV
311static int
312globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, size_t *limit)
1fd5e000
CF
313{
314 int i;
315 Char *lm, *ls;
733c9ed3
CV
316 const Char *pe, *pm, *pm1, *pl;
317 Char patbuf[MAXPATHLEN];
1fd5e000
CF
318
319 /* copy part up to the brace */
320 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
321 continue;
733c9ed3 322 *lm = EOS;
1fd5e000
CF
323 ls = lm;
324
325 /* Find the balanced brace */
326 for (i = 0, pe = ++ptr; *pe; pe++)
327 if (*pe == LBRACKET) {
328 /* Ignore everything between [] */
d6d44361
CV
329 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) {
330 if (check_classes_expr (pe) == EOS)
331 break;
332 }
1fd5e000 333 if (*pe == EOS) {
75a57bf0 334 /*
1fd5e000
CF
335 * We could not find a matching RBRACKET.
336 * Ignore and just look for RBRACE
337 */
338 pe = pm;
339 }
340 }
341 else if (*pe == LBRACE)
342 i++;
343 else if (*pe == RBRACE) {
344 if (i == 0)
345 break;
346 i--;
347 }
348
349 /* Non matching braces; just glob the pattern */
350 if (i != 0 || *pe == EOS) {
733c9ed3 351 *rv = glob0(patbuf, pglob, limit);
1fd5e000
CF
352 return 0;
353 }
354
355 for (i = 0, pl = pm = ptr; pm <= pe; pm++)
356 switch (*pm) {
357 case LBRACKET:
358 /* Ignore everything between [] */
d6d44361
CV
359 for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) {
360 if (check_classes_expr (pm) == EOS)
361 break;
362 }
1fd5e000 363 if (*pm == EOS) {
75a57bf0 364 /*
1fd5e000
CF
365 * We could not find a matching RBRACKET.
366 * Ignore and just look for RBRACE
367 */
733c9ed3 368 pm = pm1;
1fd5e000
CF
369 }
370 break;
371
372 case LBRACE:
373 i++;
374 break;
375
376 case RBRACE:
377 if (i) {
378 i--;
379 break;
380 }
50ad1980 381 fallthrough;
1fd5e000
CF
382 case COMMA:
383 if (i && *pm == COMMA)
384 break;
385 else {
386 /* Append the current string */
387 for (lm = ls; (pl < pm); *lm++ = *pl++)
388 continue;
75a57bf0 389 /*
1fd5e000
CF
390 * Append the rest of the pattern after the
391 * closing brace
392 */
393 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
394 continue;
395
396 /* Expand the current pattern */
397#ifdef DEBUG
398 qprintf("globexp2:", patbuf);
399#endif
733c9ed3 400 *rv = globexp1(patbuf, pglob, limit);
1fd5e000
CF
401
402 /* move after the comma, to the next string */
403 pl = pm + 1;
404 }
405 break;
406
407 default:
408 break;
409 }
410 *rv = 0;
411 return 0;
412}
413
414
415
416/*
417 * expand tilde from the passwd file.
418 */
419static const Char *
733c9ed3 420globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
1fd5e000
CF
421{
422 struct passwd *pwd;
423 char *h;
424 const Char *p;
733c9ed3 425 Char *b, *eb;
1fd5e000
CF
426
427 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
428 return pattern;
429
46f5dd59
CF
430 /*
431 * Copy up to the end of the string or /
733c9ed3
CV
432 */
433 eb = &patbuf[patbuf_len - 1];
434 for (p = pattern + 1, h = (char *) patbuf;
435 h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
1fd5e000
CF
436 continue;
437
438 *h = EOS;
439
440 if (((char *) patbuf)[0] == EOS) {
75a57bf0 441 /*
733c9ed3
CV
442 * handle a plain ~ or ~/ by expanding $HOME first (iff
443 * we're not running setuid or setgid) and then trying
444 * the password file
1fd5e000 445 */
d7bcd2a1 446 if (issetugid() != 0 ||
733c9ed3
CV
447 (h = getenv("HOME")) == NULL) {
448 if (((h = getlogin()) != NULL &&
449 (pwd = getpwnam(h)) != NULL) ||
d7bcd2a1 450 (pwd = getpwuid(getuid())) != NULL)
1fd5e000 451 h = pwd->pw_dir;
733c9ed3
CV
452 else
453 return pattern;
1fd5e000
CF
454 }
455 }
456 else {
457 /*
458 * Expand a ~user
459 */
460 if ((pwd = getpwnam((char*) patbuf)) == NULL)
461 return pattern;
462 else
463 h = pwd->pw_dir;
464 }
465
466 /* Copy the home directory */
733c9ed3 467 for (b = patbuf; b < eb && *h; *b++ = *h++)
1fd5e000 468 continue;
75a57bf0 469
1fd5e000 470 /* Append the rest of the pattern */
733c9ed3 471 while (b < eb && (*b++ = *p++) != EOS)
1fd5e000 472 continue;
733c9ed3 473 *b = EOS;
1fd5e000
CF
474
475 return patbuf;
476}
75a57bf0 477
1fd5e000
CF
478/*
479 * The main glob() routine: compiles the pattern (optionally processing
480 * quotes), calls glob1() to do the real pattern matching, and finally
481 * sorts the list (unless unsorted operation is requested). Returns 0
733c9ed3 482 * if things went well, nonzero if errors occurred.
1fd5e000
CF
483 */
484static int
733c9ed3 485glob0(const Char *pattern, glob_t *pglob, size_t *limit)
1fd5e000 486{
d6d44361 487 const Char *qpatnext, *qpatrbsrch;
b3f40a5f 488 int err;
733c9ed3 489 size_t oldpathc;
d7bcd2a1 490 Char *bufnext, c, patbuf[MAXPATHLEN];
1fd5e000 491
733c9ed3 492 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
1fd5e000
CF
493 oldpathc = pglob->gl_pathc;
494 bufnext = patbuf;
495
496 /* We don't need to check for buffer overflow any more. */
497 while ((c = *qpatnext++) != EOS) {
498 switch (c) {
499 case LBRACKET:
500 c = *qpatnext;
501 if (c == NOT)
502 ++qpatnext;
d6d44361
CV
503 for (qpatrbsrch = qpatnext;
504 *qpatrbsrch != RBRACKET && *qpatrbsrch != EOS;
505 ++qpatrbsrch) {
506 if (check_classes_expr (qpatrbsrch) == EOS)
507 break;
508 }
509 if (*qpatrbsrch == EOS) {
1fd5e000
CF
510 *bufnext++ = LBRACKET;
511 if (c == NOT)
512 --qpatnext;
513 break;
514 }
515 *bufnext++ = M_SET;
516 if (c == NOT)
517 *bufnext++ = M_NOT;
ce5aa098 518 c = *qpatnext++;
1fd5e000 519 do {
1df19b3c 520 wint_t wclass[64];
d6d44361
CV
521 Char ctype;
522
ce5aa098 523 ctype = check_classes_expr(--qpatnext, wclass,
1df19b3c 524 64);
ce5aa098
CV
525 ++qpatnext;
526 if (ctype == COLON) {
1df19b3c 527 wctype_t type;
ce5aa098
CV
528 char cclass[64];
529
530 /* No worries, char classes are
531 ASCII-only anyway */
532 wcitoascii (cclass, wclass);
533 if ((type = wctype (cclass))) {
534 *bufnext++ = M_NAMED;
535 *bufnext++ = CHAR (type);
536 }
537 continue;
538 }
539 if (ctype == EQUALS) {
540 if (wclass[0] && !wclass[1]) {
1df19b3c
CV
541 *bufnext++ = M_EQUIV;
542 *bufnext++ = CHAR (wclass[0]);
d6d44361 543 }
d6d44361
CV
544 continue;
545 }
ce5aa098
CV
546 if (ctype == DOT &&
547 is_unicode_coll_elem (wclass)) {
548 *bufnext++ =
549 M_COLL (wcilen (wclass));
550 wint_t *wcp = wclass;
551 while ((*bufnext++ = *wcp++))
552 ;
553 --bufnext; /* drop NUL */
554 } else
555 *bufnext++ = CHAR(c);
1fd5e000
CF
556 if (*qpatnext == RANGE &&
557 (c = qpatnext[1]) != RBRACKET) {
558 *bufnext++ = M_RNG;
ce5aa098
CV
559
560 ctype = check_classes_expr(++qpatnext,
561 wclass, 64);
562 if (ctype == DOT &&
563 is_unicode_coll_elem (wclass)) {
564 *bufnext++ =
565 M_COLL (wcilen (wclass));
566 wint_t *wcp = wclass;
567 while ((*bufnext++ = *wcp++))
568 ;
569 --bufnext; /* drop NUL */
570 } else
571 *bufnext++ = CHAR(c);
572 ++qpatnext;
1fd5e000
CF
573 }
574 } while ((c = *qpatnext++) != RBRACKET);
575 pglob->gl_flags |= GLOB_MAGCHAR;
576 *bufnext++ = M_END;
577 break;
578 case QUESTION:
579 pglob->gl_flags |= GLOB_MAGCHAR;
580 *bufnext++ = M_ONE;
581 break;
582 case STAR:
583 pglob->gl_flags |= GLOB_MAGCHAR;
75a57bf0 584 /* collapse adjacent stars to one,
1fd5e000
CF
585 * to avoid exponential behavior
586 */
587 if (bufnext == patbuf || bufnext[-1] != M_ALL)
588 *bufnext++ = M_ALL;
589 break;
590 default:
591 *bufnext++ = CHAR(c);
592 break;
593 }
594 }
595 *bufnext = EOS;
596#ifdef DEBUG
597 qprintf("glob0:", patbuf);
598#endif
599
733c9ed3 600 if ((err = glob1(patbuf, pglob, limit)) != 0)
1fd5e000
CF
601 return(err);
602
603 /*
75a57bf0 604 * If there was no match we are going to append the pattern
1fd5e000
CF
605 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
606 * and the pattern did not contain any magic characters
607 * GLOB_NOMAGIC is there just for compatibility with csh.
608 */
733c9ed3
CV
609 if (pglob->gl_pathc == oldpathc) {
610 if (((pglob->gl_flags & GLOB_NOCHECK) ||
611 ((pglob->gl_flags & GLOB_NOMAGIC) &&
612 !(pglob->gl_flags & GLOB_MAGCHAR))))
613 return(globextend(pattern, pglob, limit));
614 else
615 return(GLOB_NOMATCH);
616 }
617 if (!(pglob->gl_flags & GLOB_NOSORT))
1fd5e000
CF
618 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
619 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
620 return(0);
621}
622
623static int
733c9ed3 624compare(const void *p, const void *q)
1fd5e000 625{
1cbe4b3d 626 return(strcoll(*(char **)p, *(char **)q));
1fd5e000
CF
627}
628
629static int
733c9ed3 630glob1(Char *pattern, glob_t *pglob, size_t *limit)
1fd5e000 631{
733c9ed3 632 Char pathbuf[MAXPATHLEN];
1fd5e000
CF
633
634 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
635 if (*pattern == EOS)
636 return(0);
733c9ed3
CV
637 return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
638 pattern, pglob, limit));
1fd5e000
CF
639}
640
641/*
642 * The functions glob2 and glob3 are mutually recursive; there is one level
643 * of recursion for each segment in the pattern that contains one or more
644 * meta characters.
645 */
646static int
733c9ed3
CV
647glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
648 glob_t *pglob, size_t *limit)
1fd5e000 649{
d7bcd2a1 650 struct stat sb;
1fd5e000
CF
651 Char *p, *q;
652 int anymeta;
653
654 /*
655 * Loop over pattern segments until end of pattern or until
656 * segment with meta character found.
657 */
658 for (anymeta = 0;;) {
659 if (*pattern == EOS) { /* End of pattern? */
660 *pathend = EOS;
661 if (g_lstat(pathbuf, &sb, pglob))
662 return(0);
75a57bf0 663
1fd5e000
CF
664 if (((pglob->gl_flags & GLOB_MARK) &&
665 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
666 || (S_ISLNK(sb.st_mode) &&
667 (g_stat(pathbuf, &sb, pglob) == 0) &&
668 S_ISDIR(sb.st_mode)))) {
733c9ed3
CV
669 if (pathend + 1 > pathend_last)
670 return (GLOB_ABORTED);
1fd5e000
CF
671 *pathend++ = SEP;
672 *pathend = EOS;
673 }
674 ++pglob->gl_matchc;
fa2d9fc5 675 return(globextend(pathbuf, pglob, limit));
1fd5e000
CF
676 }
677
678 /* Find end of next segment, copy tentatively to pathend. */
679 q = pathend;
680 p = pattern;
681 while (*p != EOS && *p != SEP) {
682 if (ismeta(*p))
683 anymeta = 1;
733c9ed3
CV
684 if (q + 1 > pathend_last)
685 return (GLOB_ABORTED);
1fd5e000
CF
686 *q++ = *p++;
687 }
688
689 if (!anymeta) { /* No expansion, do next segment. */
690 pathend = q;
691 pattern = p;
733c9ed3
CV
692 while (*pattern == SEP) {
693 if (pathend + 1 > pathend_last)
694 return (GLOB_ABORTED);
1fd5e000 695 *pathend++ = *pattern++;
733c9ed3 696 }
1fd5e000 697 } else /* Need expansion, recurse. */
733c9ed3
CV
698 return(glob3(pathbuf, pathend, pathend_last, pattern, p,
699 pglob, limit));
1fd5e000
CF
700 }
701 /* NOTREACHED */
702}
703
704static int
733c9ed3
CV
705glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
706 Char *pattern, Char *restpattern,
707 glob_t *pglob, size_t *limit)
1fd5e000 708{
733c9ed3 709 struct dirent *dp;
1fd5e000
CF
710 DIR *dirp;
711 int err;
712 char buf[MAXPATHLEN];
713
714 /*
715 * The readdirfunc declaration can't be prototyped, because it is
716 * assigned, below, to two functions which are prototyped in glob.h
717 * and dirent.h as taking pointers to differently typed opaque
718 * structures.
d7bcd2a1
CV
719 * CYGWIN: Needs prototype and subsequently wild casting to avoid
720 * compiler error.
1fd5e000 721 */
733c9ed3 722 struct dirent *(*readdirfunc)(void *);
1fd5e000 723
733c9ed3
CV
724 if (pathend > pathend_last)
725 return (GLOB_ABORTED);
1fd5e000
CF
726 *pathend = EOS;
727 errno = 0;
75a57bf0 728
1fd5e000
CF
729 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
730 /* TODO: don't call for ENOENT or ENOTDIR? */
731 if (pglob->gl_errfunc) {
733c9ed3
CV
732 if (g_Ctoc(pathbuf, buf, sizeof(buf)))
733 return (GLOB_ABORTED);
1fd5e000
CF
734 if (pglob->gl_errfunc(buf, errno) ||
735 pglob->gl_flags & GLOB_ERR)
733c9ed3 736 return (GLOB_ABORTED);
1fd5e000 737 }
d7bcd2a1 738 return(0);
1fd5e000
CF
739 }
740
741 err = 0;
742
743 /* Search directory for matching names. */
744 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
745 readdirfunc = pglob->gl_readdir;
746 else
733c9ed3 747 readdirfunc = (dirent*(*)(void*)) readdir;
1fd5e000 748 while ((dp = (*readdirfunc)(dirp))) {
733c9ed3
CV
749 char *sc;
750 Char *dc;
0321fb57 751 wint_t wc;
733c9ed3
CV
752 size_t clen;
753 mbstate_t mbs;
1fd5e000
CF
754
755 /* Initial DOT must be matched literally. */
756 if (dp->d_name[0] == DOT && *pattern != DOT)
757 continue;
733c9ed3
CV
758 memset(&mbs, 0, sizeof(mbs));
759 dc = pathend;
760 sc = dp->d_name;
761 while (dc < pathend_last) {
0321fb57 762 clen = mbrtowi(&wc, sc, MB_LEN_MAX, &mbs);
733c9ed3
CV
763 if (clen == (size_t)-1 || clen == (size_t)-2) {
764 wc = *sc;
765 clen = 1;
766 memset(&mbs, 0, sizeof(mbs));
767 }
768 if ((*dc++ = wc) == EOS)
769 break;
770 sc += clen;
771 }
1fd5e000
CF
772 if (!match(pathend, pattern, restpattern)) {
773 *pathend = EOS;
774 continue;
775 }
733c9ed3
CV
776 err = glob2(pathbuf, --dc, pathend_last, restpattern,
777 pglob, limit);
1fd5e000
CF
778 if (err)
779 break;
780 }
781
782 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
783 (*pglob->gl_closedir)(dirp);
784 else
785 closedir(dirp);
786 return(err);
787}
788
789
790/*
733c9ed3 791 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
1fd5e000
CF
792 * add the new item, and update gl_pathc.
793 *
794 * This assumes the BSD realloc, which only copies the block when its size
795 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
796 * behavior.
797 *
798 * Return 0 if new item added, error code if memory couldn't be allocated.
799 *
800 * Invariant of the glob_t structure:
801 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
802 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
803 */
804static int
733c9ed3 805globextend(const Char *path, glob_t *pglob, size_t *limit)
1fd5e000 806{
733c9ed3
CV
807 char **pathv;
808 size_t i, newsize, len;
1fd5e000
CF
809 char *copy;
810 const Char *p;
811
733c9ed3
CV
812 if (*limit && pglob->gl_pathc > *limit) {
813 errno = 0;
814 return (GLOB_NOSPACE);
815 }
816
1fd5e000 817 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
75a57bf0 818 pathv = pglob->gl_pathv ?
733c9ed3
CV
819 (char **) realloc((char *)pglob->gl_pathv, newsize) :
820 (char **) malloc(newsize);
821 if (pathv == NULL) {
822 if (pglob->gl_pathv) {
823 free(pglob->gl_pathv);
824 pglob->gl_pathv = NULL;
825 }
1fd5e000 826 return(GLOB_NOSPACE);
733c9ed3 827 }
1fd5e000
CF
828
829 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
830 /* first time around -- clear initial gl_offs items */
831 pathv += pglob->gl_offs;
733c9ed3 832 for (i = pglob->gl_offs + 1; --i > 0; )
1fd5e000
CF
833 *--pathv = NULL;
834 }
835 pglob->gl_pathv = pathv;
836
837 for (p = path; *p++;)
838 continue;
733c9ed3
CV
839 len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
840 if ((copy = (char *) malloc(len)) != NULL) {
841 if (g_Ctoc(path, copy, len)) {
842 free(copy);
843 return (GLOB_NOSPACE);
844 }
1fd5e000
CF
845 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
846 }
847 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
848 return(copy == NULL ? GLOB_NOSPACE : 0);
849}
850
1fd5e000
CF
851/*
852 * pattern matching function for filenames. Each occurrence of the *
853 * pattern causes a recursion level.
854 */
855static int
733c9ed3 856match(Char *name, Char *pat, Char *patend)
1fd5e000
CF
857{
858 int ok, negate_range;
ce5aa098
CV
859 Char *c, *k;
860 size_t k_len;
1fd5e000
CF
861
862 while (pat < patend) {
ce5aa098
CV
863 c = pat++;
864 switch (*c & M_MASK) {
1fd5e000
CF
865 case M_ALL:
866 if (pat == patend)
867 return(1);
75a57bf0 868 do
1fd5e000
CF
869 if (match(name, pat, patend))
870 return(1);
871 while (*name++ != EOS);
872 return(0);
873 case M_ONE:
874 if (*name++ == EOS)
875 return(0);
876 break;
877 case M_SET:
878 ok = 0;
ce5aa098 879 if (*(k = name) == EOS)
1fd5e000 880 return(0);
ce5aa098
CV
881 k_len = next_unicode_char (k);
882 name += k_len;
1fd5e000
CF
883 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
884 ++pat;
ce5aa098
CV
885 while ((*(c = pat++) & M_MASK) != M_END) {
886 size_t len1 = 1, len2 = 1;
887
888 if ((*c & M_MASK) == M_NAMED) {
889 if (iswctype (*k, *pat++))
d6d44361 890 ok = 1;
ce5aa098
CV
891 continue;
892 }
893 if ((*c & M_MASK) == M_EQUIV) {
894 if (is_unicode_equiv (*k, *pat++))
1df19b3c 895 ok = 1;
ce5aa098
CV
896 continue;
897 }
898 if (M_COLL_P(*c)) {
899 len1 = M_COLL_CNT(*c);
900 ++c;
901 pat += len1;
902 }
903 if ((*pat & M_MASK) == M_RNG) {
904 if (M_COLL_P(pat[1]))
905 len2 = M_COLL_CNT(*++pat);
064e4bb8 906#ifdef __CYGWIN__
e95a7a79 907 if ((!__get_current_collate_locale ()->win_locale[0]) ?
064e4bb8 908#else
d7bcd2a1 909 if (__collate_load_error ?
064e4bb8 910#endif
ce5aa098
CV
911 *c <= *k && *k <= pat[1] :
912 __wscollate_range_cmp(c, k, len1, k_len) <= 0
913 && __wscollate_range_cmp(k, pat + 1, k_len, len2) <= 0
d7bcd2a1
CV
914 )
915 ok = 1;
ce5aa098
CV
916 pat += len2 + 1;
917 } else if (len1 == k_len &&
918 wcincmp (c, k, len1) == 0)
d7bcd2a1 919 ok = 1;
ce5aa098 920 }
1fd5e000
CF
921 if (ok == negate_range)
922 return(0);
923 break;
924 default:
89afbb8d 925 if (Cchar(*name++) != Cchar(*c))
733c9ed3 926 return(0);
1fd5e000
CF
927 break;
928 }
929 }
930 return(*name == EOS);
931}
932
933/* Free allocated data belonging to a glob_t structure. */
934void
733c9ed3 935globfree(glob_t *pglob)
1fd5e000 936{
733c9ed3
CV
937 size_t i;
938 char **pp;
1fd5e000
CF
939
940 if (pglob->gl_pathv != NULL) {
941 pp = pglob->gl_pathv + pglob->gl_offs;
942 for (i = pglob->gl_pathc; i--; ++pp)
943 if (*pp)
944 free(*pp);
945 free(pglob->gl_pathv);
733c9ed3 946 pglob->gl_pathv = NULL;
1fd5e000
CF
947 }
948}
949
950static DIR *
733c9ed3 951g_opendir(Char *str, glob_t *pglob)
1fd5e000
CF
952{
953 char buf[MAXPATHLEN];
954
955 if (!*str)
956 strcpy(buf, ".");
733c9ed3
CV
957 else {
958 if (g_Ctoc(str, buf, sizeof(buf)))
959 return (NULL);
960 }
1fd5e000
CF
961
962 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
733c9ed3 963 return (DIR *) ((*pglob->gl_opendir)((const char *) buf));
1fd5e000
CF
964
965 return(opendir(buf));
966}
967
61522196 968#define CYGWIN_gl_stat(sfptr) ((*pglob->sfptr) (buf, sb))
d7bcd2a1 969
1fd5e000 970static int
d7bcd2a1 971g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
1fd5e000
CF
972{
973 char buf[MAXPATHLEN];
974
733c9ed3
CV
975 if (g_Ctoc(fn, buf, sizeof(buf))) {
976 errno = ENAMETOOLONG;
977 return (-1);
978 }
d7bcd2a1
CV
979 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
980 return CYGWIN_gl_stat (gl_lstat);
2d9b4876 981 return(lstat(buf, sb));
1fd5e000
CF
982}
983
984static int
d7bcd2a1 985g_stat(Char *fn, struct stat *sb, glob_t *pglob)
1fd5e000
CF
986{
987 char buf[MAXPATHLEN];
988
733c9ed3
CV
989 if (g_Ctoc(fn, buf, sizeof(buf))) {
990 errno = ENAMETOOLONG;
991 return (-1);
992 }
d7bcd2a1
CV
993 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
994 return CYGWIN_gl_stat (gl_stat);
2d9b4876 995 return(stat(buf, sb));
1fd5e000
CF
996}
997
d7bcd2a1 998static const Char *
0321fb57 999g_strchr(const Char *str, wint_t ch)
1fd5e000 1000{
733c9ed3 1001
1fd5e000
CF
1002 do {
1003 if (*str == ch)
1004 return (str);
1005 } while (*str++);
1006 return (NULL);
1007}
1008
733c9ed3
CV
1009static int
1010g_Ctoc(const Char *str, char *buf, size_t len)
1fd5e000 1011{
733c9ed3
CV
1012 mbstate_t mbs;
1013 size_t clen;
1014
1015 memset(&mbs, 0, sizeof(mbs));
1016 while (len >= (size_t) MB_CUR_MAX) {
6bc687e3 1017 clen = wirtomb(buf, CHAR (*str), &mbs);
733c9ed3
CV
1018 if (clen == (size_t)-1)
1019 return (1);
1020 if (*str == L'\0')
1021 return (0);
1022 str++;
1023 buf += clen;
1024 len -= clen;
1025 }
1026 return (1);
1fd5e000
CF
1027}
1028
1029#ifdef DEBUG
75a57bf0 1030static void
733c9ed3 1031qprintf(const char *str, Char *s)
1fd5e000 1032{
733c9ed3 1033 Char *p;
1fd5e000
CF
1034
1035 (void)printf("%s:\n", str);
1036 for (p = s; *p; p++)
1037 (void)printf("%c", CHAR(*p));
1038 (void)printf("\n");
1039 for (p = s; *p; p++)
1040 (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
1041 (void)printf("\n");
1042 for (p = s; *p; p++)
1043 (void)printf("%c", ismeta(*p) ? '_' : ' ');
1044 (void)printf("\n");
1045}
1046#endif
This page took 0.710277 seconds and 6 git commands to generate.