]> sourceware.org Git - newlib-cygwin.git/blame_incremental - winsup/cygwin/glob.cc
Cygwin: add release message for latest pipe changes
[newlib-cygwin.git] / winsup / cygwin / glob.cc
... / ...
CommitLineData
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.
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
33#ifdef __CYGWIN__
34#include "winsup.h"
35#endif
36
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 */
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 $");
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:
63 * expand {1,2}{a,b} to 1a 1b 2a 2b
64 * gl_matchc:
65 * Number of matches in the current invocation of glob.
66 */
67
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
74 * cast to wint_t.
75 * 3. State-dependent encodings are not currently supported.
76 */
77
78#include <sys/param.h>
79#include <sys/stat.h>
80
81#include <ctype.h>
82#include <dirent.h>
83#include <errno.h>
84#include <glob.h>
85#include <limits.h>
86#include <pwd.h>
87#include <stdint.h>
88#include <stdio.h>
89#include <stdlib.h>
90#include <string.h>
91#include <unistd.h>
92#include <wchar.h>
93#include <wctype.h>
94
95#include "collate.h"
96
97#ifdef __CYGWIN__
98#define Cchar(c) (ignore_case_with_glob ? towlower (c) : (c))
99#endif
100
101#undef MAXPATHLEN
102#define MAXPATHLEN 8192
103
104#define DOLLAR '$'
105#define DOT '.'
106#define COLON ':'
107#define EQUALS '='
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
126#define M_QUOTE 0x40000000U
127#define M_PROTECT 0x20000000U
128#define M_MASK 0x70ffffffU
129#define M_COLL_MASK 0x700000ffU
130#define M_CHAR 0x00ffffffU
131
132typedef wint_t Char;
133
134#else
135
136#define M_QUOTE 0x80
137#define M_PROTECT 0x40
138#define M_MASK 0xff
139#define M_CHAR 0x7f
140
141typedef char Char;
142
143#endif
144
145
146#define CHAR(c) ((Char)((c)&M_CHAR))
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('[')
154#define M_NAMED META(':')
155#define M_EQUIV META('=')
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)
159#define ismeta(c) (((c)&M_QUOTE) != 0)
160
161static int compare(const void *, const void *);
162static int g_Ctoc(const Char *, char *, size_t);
163static int g_lstat(Char *, struct stat *, glob_t *);
164static DIR *g_opendir(Char *, glob_t *);
165static const Char *g_strchr(const Char *, wint_t);
166#ifdef notdef
167static Char *g_strcat(Char *, const Char *);
168#endif
169static int g_stat(Char *, struct stat *, glob_t *);
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 *);
175static const Char *
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 *);
180#ifdef DEBUG
181static void qprintf(const char *, Char *);
182#endif
183
184/* Return value is either EOS, COLON, DOT, EQUALS, or LBRACKET if no class
185 expression found. */
186static inline Char
187check_classes_expr(const Char *&cptr, wint_t *classbuf = NULL,
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;
203
204 if (clen < classbufsize)
205 *wcipncpy (classbuf, class_p, clen) = '\0';
206 else
207 ctype = NULL;
208 }
209 cptr++; /* Advance cptr to closing RBRACKET of class expr */
210 }
211 return ctype ? *ctype : LBRACKET;
212}
213
214int
215glob(const char *__restrict pattern, int flags, int (*errfunc)(const char *, int), glob_t *__restrict pglob)
216{
217 const char *patnext;
218 size_t limit;
219 Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
220 mbstate_t mbs;
221 wint_t wc;
222 size_t clen;
223
224 patnext = pattern;
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 }
231 if (flags & GLOB_LIMIT) {
232 limit = pglob->gl_matchc;
233 if (limit == 0)
234 limit = ARG_MAX;
235 } else
236 limit = 0;
237 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
238 pglob->gl_errfunc = errfunc;
239 pglob->gl_matchc = 0;
240
241 bufnext = patbuf;
242 bufend = bufnext + MAXPATHLEN - 1;
243 if (flags & GLOB_NOESCAPE) {
244 memset(&mbs, 0, sizeof(mbs));
245 while (bufend - bufnext >= MB_CUR_MAX) {
246 clen = mbrtowi(&wc, patnext, MB_LEN_MAX, &mbs);
247 if (clen == (size_t)-1 || clen == (size_t)-2)
248 return (GLOB_NOMATCH);
249 else if (clen == 0)
250 break;
251 *bufnext++ = wc;
252 patnext += clen;
253 }
254 } else {
255 /* Protect the quoted characters. */
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;
262 }
263 prot = M_PROTECT;
264 } else
265 prot = 0;
266 clen = mbrtowi(&wc, patnext, MB_LEN_MAX, &mbs);
267 if (clen == (size_t)-1 || clen == (size_t)-2)
268 return (GLOB_NOMATCH);
269 else if (clen == 0)
270 break;
271 *bufnext++ = wc | prot;
272 patnext += clen;
273 }
274 }
275 *bufnext = EOS;
276
277 if (flags & GLOB_BRACE)
278 return globexp1(patbuf, pglob, &limit);
279 else
280 return glob0(patbuf, pglob, &limit);
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 */
288static int
289globexp1(const Char *pattern, glob_t *pglob, size_t *limit)
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)
296 return glob0(pattern, pglob, limit);
297
298 while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
299 if (!globexp2(ptr, pattern, pglob, &rv, limit))
300 return rv;
301
302 return glob0(pattern, pglob, limit);
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 */
311static int
312globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, size_t *limit)
313{
314 int i;
315 Char *lm, *ls;
316 const Char *pe, *pm, *pm1, *pl;
317 Char patbuf[MAXPATHLEN];
318
319 /* copy part up to the brace */
320 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
321 continue;
322 *lm = EOS;
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 [] */
329 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) {
330 if (check_classes_expr (pe) == EOS)
331 break;
332 }
333 if (*pe == EOS) {
334 /*
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) {
351 *rv = glob0(patbuf, pglob, limit);
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 [] */
359 for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) {
360 if (check_classes_expr (pm) == EOS)
361 break;
362 }
363 if (*pm == EOS) {
364 /*
365 * We could not find a matching RBRACKET.
366 * Ignore and just look for RBRACE
367 */
368 pm = pm1;
369 }
370 break;
371
372 case LBRACE:
373 i++;
374 break;
375
376 case RBRACE:
377 if (i) {
378 i--;
379 break;
380 }
381 fallthrough;
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;
389 /*
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
400 *rv = globexp1(patbuf, pglob, limit);
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 *
420globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
421{
422 struct passwd *pwd;
423 char *h;
424 const Char *p;
425 Char *b, *eb;
426
427 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
428 return pattern;
429
430 /*
431 * Copy up to the end of the string or /
432 */
433 eb = &patbuf[patbuf_len - 1];
434 for (p = pattern + 1, h = (char *) patbuf;
435 h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
436 continue;
437
438 *h = EOS;
439
440 if (((char *) patbuf)[0] == EOS) {
441 /*
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
445 */
446 if (issetugid() != 0 ||
447 (h = getenv("HOME")) == NULL) {
448 if (((h = getlogin()) != NULL &&
449 (pwd = getpwnam(h)) != NULL) ||
450 (pwd = getpwuid(getuid())) != NULL)
451 h = pwd->pw_dir;
452 else
453 return pattern;
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 */
467 for (b = patbuf; b < eb && *h; *b++ = *h++)
468 continue;
469
470 /* Append the rest of the pattern */
471 while (b < eb && (*b++ = *p++) != EOS)
472 continue;
473 *b = EOS;
474
475 return patbuf;
476}
477
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
482 * if things went well, nonzero if errors occurred.
483 */
484static int
485glob0(const Char *pattern, glob_t *pglob, size_t *limit)
486{
487 const Char *qpatnext, *qpatrbsrch;
488 int err;
489 size_t oldpathc;
490 Char *bufnext, c, patbuf[MAXPATHLEN];
491
492 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
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;
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) {
510 *bufnext++ = LBRACKET;
511 if (c == NOT)
512 --qpatnext;
513 break;
514 }
515 *bufnext++ = M_SET;
516 if (c == NOT)
517 *bufnext++ = M_NOT;
518 c = *qpatnext++;
519 do {
520 wint_t wclass[64];
521 Char ctype;
522
523 ctype = check_classes_expr(--qpatnext, wclass,
524 64);
525 ++qpatnext;
526 if (ctype == COLON) {
527 wctype_t type;
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]) {
541 *bufnext++ = M_EQUIV;
542 *bufnext++ = CHAR (wclass[0]);
543 }
544 continue;
545 }
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);
556 if (*qpatnext == RANGE &&
557 (c = qpatnext[1]) != RBRACKET) {
558 *bufnext++ = M_RNG;
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;
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;
584 /* collapse adjacent stars to one,
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
600 if ((err = glob1(patbuf, pglob, limit)) != 0)
601 return(err);
602
603 /*
604 * If there was no match we are going to append the pattern
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 */
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))
618 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
619 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
620 return(0);
621}
622
623static int
624compare(const void *p, const void *q)
625{
626 return(strcoll(*(char **)p, *(char **)q));
627}
628
629static int
630glob1(Char *pattern, glob_t *pglob, size_t *limit)
631{
632 Char pathbuf[MAXPATHLEN];
633
634 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
635 if (*pattern == EOS)
636 return(0);
637 return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
638 pattern, pglob, limit));
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
647glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
648 glob_t *pglob, size_t *limit)
649{
650 struct stat sb;
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);
663
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)))) {
669 if (pathend + 1 > pathend_last)
670 return (GLOB_ABORTED);
671 *pathend++ = SEP;
672 *pathend = EOS;
673 }
674 ++pglob->gl_matchc;
675 return(globextend(pathbuf, pglob, limit));
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;
684 if (q + 1 > pathend_last)
685 return (GLOB_ABORTED);
686 *q++ = *p++;
687 }
688
689 if (!anymeta) { /* No expansion, do next segment. */
690 pathend = q;
691 pattern = p;
692 while (*pattern == SEP) {
693 if (pathend + 1 > pathend_last)
694 return (GLOB_ABORTED);
695 *pathend++ = *pattern++;
696 }
697 } else /* Need expansion, recurse. */
698 return(glob3(pathbuf, pathend, pathend_last, pattern, p,
699 pglob, limit));
700 }
701 /* NOTREACHED */
702}
703
704static int
705glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
706 Char *pattern, Char *restpattern,
707 glob_t *pglob, size_t *limit)
708{
709 struct dirent *dp;
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.
719 * CYGWIN: Needs prototype and subsequently wild casting to avoid
720 * compiler error.
721 */
722 struct dirent *(*readdirfunc)(void *);
723
724 if (pathend > pathend_last)
725 return (GLOB_ABORTED);
726 *pathend = EOS;
727 errno = 0;
728
729 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
730 /* TODO: don't call for ENOENT or ENOTDIR? */
731 if (pglob->gl_errfunc) {
732 if (g_Ctoc(pathbuf, buf, sizeof(buf)))
733 return (GLOB_ABORTED);
734 if (pglob->gl_errfunc(buf, errno) ||
735 pglob->gl_flags & GLOB_ERR)
736 return (GLOB_ABORTED);
737 }
738 return(0);
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
747 readdirfunc = (dirent*(*)(void*)) readdir;
748 while ((dp = (*readdirfunc)(dirp))) {
749 char *sc;
750 Char *dc;
751 wint_t wc;
752 size_t clen;
753 mbstate_t mbs;
754
755 /* Initial DOT must be matched literally. */
756 if (dp->d_name[0] == DOT && *pattern != DOT)
757 continue;
758 memset(&mbs, 0, sizeof(mbs));
759 dc = pathend;
760 sc = dp->d_name;
761 while (dc < pathend_last) {
762 clen = mbrtowi(&wc, sc, MB_LEN_MAX, &mbs);
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 }
772 if (!match(pathend, pattern, restpattern)) {
773 *pathend = EOS;
774 continue;
775 }
776 err = glob2(pathbuf, --dc, pathend_last, restpattern,
777 pglob, limit);
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/*
791 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
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
805globextend(const Char *path, glob_t *pglob, size_t *limit)
806{
807 char **pathv;
808 size_t i, newsize, len;
809 char *copy;
810 const Char *p;
811
812 if (*limit && pglob->gl_pathc > *limit) {
813 errno = 0;
814 return (GLOB_NOSPACE);
815 }
816
817 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
818 pathv = pglob->gl_pathv ?
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 }
826 return(GLOB_NOSPACE);
827 }
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;
832 for (i = pglob->gl_offs + 1; --i > 0; )
833 *--pathv = NULL;
834 }
835 pglob->gl_pathv = pathv;
836
837 for (p = path; *p++;)
838 continue;
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 }
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
851/*
852 * pattern matching function for filenames. Each occurrence of the *
853 * pattern causes a recursion level.
854 */
855static int
856match(Char *name, Char *pat, Char *patend)
857{
858 int ok, negate_range;
859 Char *c, *k;
860 size_t k_len;
861
862 while (pat < patend) {
863 c = pat++;
864 switch (*c & M_MASK) {
865 case M_ALL:
866 if (pat == patend)
867 return(1);
868 do
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;
879 if (*(k = name) == EOS)
880 return(0);
881 k_len = next_unicode_char (k);
882 name += k_len;
883 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
884 ++pat;
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++))
890 ok = 1;
891 continue;
892 }
893 if ((*c & M_MASK) == M_EQUIV) {
894 if (is_unicode_equiv (*k, *pat++))
895 ok = 1;
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);
906#ifdef __CYGWIN__
907 if ((!__get_current_collate_locale ()->win_locale[0]) ?
908#else
909 if (__collate_load_error ?
910#endif
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
914 )
915 ok = 1;
916 pat += len2 + 1;
917 } else if (len1 == k_len &&
918 wcincmp (c, k, len1) == 0)
919 ok = 1;
920 }
921 if (ok == negate_range)
922 return(0);
923 break;
924 default:
925 if (Cchar(*name++) != Cchar(*c))
926 return(0);
927 break;
928 }
929 }
930 return(*name == EOS);
931}
932
933/* Free allocated data belonging to a glob_t structure. */
934void
935globfree(glob_t *pglob)
936{
937 size_t i;
938 char **pp;
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);
946 pglob->gl_pathv = NULL;
947 }
948}
949
950static DIR *
951g_opendir(Char *str, glob_t *pglob)
952{
953 char buf[MAXPATHLEN];
954
955 if (!*str)
956 strcpy(buf, ".");
957 else {
958 if (g_Ctoc(str, buf, sizeof(buf)))
959 return (NULL);
960 }
961
962 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
963 return (DIR *) ((*pglob->gl_opendir)((const char *) buf));
964
965 return(opendir(buf));
966}
967
968#define CYGWIN_gl_stat(sfptr) ((*pglob->sfptr) (buf, sb))
969
970static int
971g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
972{
973 char buf[MAXPATHLEN];
974
975 if (g_Ctoc(fn, buf, sizeof(buf))) {
976 errno = ENAMETOOLONG;
977 return (-1);
978 }
979 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
980 return CYGWIN_gl_stat (gl_lstat);
981 return(lstat(buf, sb));
982}
983
984static int
985g_stat(Char *fn, struct stat *sb, glob_t *pglob)
986{
987 char buf[MAXPATHLEN];
988
989 if (g_Ctoc(fn, buf, sizeof(buf))) {
990 errno = ENAMETOOLONG;
991 return (-1);
992 }
993 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
994 return CYGWIN_gl_stat (gl_stat);
995 return(stat(buf, sb));
996}
997
998static const Char *
999g_strchr(const Char *str, wint_t ch)
1000{
1001
1002 do {
1003 if (*str == ch)
1004 return (str);
1005 } while (*str++);
1006 return (NULL);
1007}
1008
1009static int
1010g_Ctoc(const Char *str, char *buf, size_t len)
1011{
1012 mbstate_t mbs;
1013 size_t clen;
1014
1015 memset(&mbs, 0, sizeof(mbs));
1016 while (len >= (size_t) MB_CUR_MAX) {
1017 clen = wirtomb(buf, CHAR (*str), &mbs);
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);
1027}
1028
1029#ifdef DEBUG
1030static void
1031qprintf(const char *str, Char *s)
1032{
1033 Char *p;
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.033238 seconds and 6 git commands to generate.