glob.c revision 131962
1228753Smm/*
2228753Smm * Copyright (c) 1989 The Regents of the University of California.
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * This code is derived from software contributed to Berkeley by
6228753Smm * Guido van Rossum.
7228753Smm *
8228753Smm * Redistribution and use in source and binary forms, with or without
9228753Smm * modification, are permitted provided that the following conditions
10228753Smm * are met:
11228753Smm * 1. Redistributions of source code must retain the above copyright
12228753Smm *    notice, this list of conditions and the following disclaimer.
13228753Smm * 2. Redistributions in binary form must reproduce the above copyright
14228753Smm *    notice, this list of conditions and the following disclaimer in the
15228753Smm *    documentation and/or other materials provided with the distribution.
16228753Smm * 3. Neither the name of the University nor the names of its contributors
17228753Smm *    may be used to endorse or promote products derived from this software
18228753Smm *    without specific prior written permission.
19228753Smm *
20228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23228753Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28228753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30228753Smm * SUCH DAMAGE.
31228753Smm */
32228753Smm#if defined(LIBC_SCCS) && !defined(lint)
33228753Smmstatic char sccsid[] = "@(#)glob.c	5.12 (Berkeley) 6/24/91";
34228753Smm#endif /* LIBC_SCCS and not lint */
35228753Smm/*
36228753Smm * Glob: the interface is a superset of the one defined in POSIX 1003.2,
37228753Smm * draft 9.
38228753Smm *
39228753Smm * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
40228753Smm *
41228753Smm * Optional extra services, controlled by flags not defined by POSIX:
42228753Smm *
43228753Smm * GLOB_QUOTE:
44228753Smm *	Escaping convention: \ inhibits any special meaning the following
45228753Smm *	character might have (except \ at end of string is retained).
46228753Smm * GLOB_MAGCHAR:
47228753Smm *	Set in gl_flags if pattern contained a globbing character.
48228753Smm * GLOB_ALTNOT:
49228753Smm *	Use ^ instead of ! for "not".
50228753Smm * gl_matchc:
51228753Smm *	Number of matches in the current invocation of glob.
52228753Smm */
53228753Smm
54228753Smm#ifdef notdef
55228753Smm#include <sys/types.h>
56228753Smm#include <sys/param.h>
57228753Smm#include <sys/stat.h>
58228753Smm#include <dirent.h>
59228753Smm#include <ctype.h>
60228753Smmtypedef void * ptr_t;
61228753Smm#endif
62228753Smm#ifdef WINNT_NATIVE
63228753Smm	#pragma warning(disable:4244)
64228753Smm#endif /* WINNT_NATIVE */
65228753Smm
66228753Smm#define Char __Char
67228753Smm#include "sh.h"
68228753Smm#undef Char
69228753Smm#undef QUOTE
70228753Smm#undef TILDE
71228753Smm#undef META
72228753Smm#undef CHAR
73228753Smm#undef ismeta
74228753Smm#undef Strchr
75228753Smm
76228753Smm#include "glob.h"
77228753Smm
78228753Smm#ifndef S_ISDIR
79228753Smm#define S_ISDIR(a)	(((a) & S_IFMT) == S_IFDIR)
80228753Smm#endif
81228753Smm
82228753Smm#if !defined(S_ISLNK) && defined(S_IFLNK)
83228753Smm#define S_ISLNK(a)	(((a) & S_IFMT) == S_IFLNK)
84228753Smm#endif
85228753Smm
86228753Smm#if !defined(S_ISLNK) && !defined(lstat)
87228753Smm#define lstat stat
88228753Smm#endif
89228753Smm
90228753Smmtypedef unsigned short Char;
91228753Smm
92228753Smmstatic	int	 glob1 		__P((Char *, glob_t *, int));
93228753Smmstatic	int	 glob2		__P((Char *, Char *, Char *, glob_t *, int));
94228753Smmstatic	int	 glob3		__P((Char *, Char *, Char *, Char *,
95228753Smm				     glob_t *, int));
96228753Smmstatic	int	 globextend	__P((Char *, glob_t *));
97228753Smmstatic	int	 match		__P((Char *, Char *, Char *, int));
98228753Smm#ifndef __clipper__
99228753Smmstatic	int	 compare	__P((const ptr_t, const ptr_t));
100228753Smm#endif
101228753Smmstatic 	DIR	*Opendir	__P((Char *));
102228753Smm#ifdef S_IFLNK
103228753Smmstatic	int	 Lstat		__P((Char *, struct stat *));
104228753Smm#endif
105228753Smmstatic	int	 Stat		__P((Char *, struct stat *sb));
106228753Smmstatic 	Char 	*Strchr		__P((Char *, int));
107228753Smm#ifdef DEBUG
108228753Smmstatic	void	 qprintf	__P((Char *));
109228753Smm#endif
110228753Smm
111228753Smm#define	DOLLAR		'$'
112228753Smm#define	DOT		'.'
113228753Smm#define	EOS		'\0'
114228753Smm#define	LBRACKET	'['
115228753Smm#define	NOT		'!'
116228753Smm#define ALTNOT		'^'
117228753Smm#define	QUESTION	'?'
118228753Smm#define	QUOTE		'\\'
119228753Smm#define	RANGE		'-'
120228753Smm#define	RBRACKET	']'
121228753Smm#define	SEP		'/'
122228753Smm#define	STAR		'*'
123228753Smm#define	TILDE		'~'
124228753Smm#define	UNDERSCORE	'_'
125228753Smm
126228753Smm#define	M_META		0x8000
127228753Smm#define M_PROTECT	0x4000
128228753Smm#define	M_MASK		0xffff
129228753Smm#define	M_ASCII		0x00ff
130228753Smm
131228753Smm#define	CHAR(c)		((c)&M_ASCII)
132228753Smm#define	META(c)		((c)|M_META)
133228753Smm#define	M_ALL		META('*')
134228753Smm#define	M_END		META(']')
135228753Smm#define	M_NOT		META('!')
136228753Smm#define	M_ALTNOT	META('^')
137228753Smm#define	M_ONE		META('?')
138228753Smm#define	M_RNG		META('-')
139228753Smm#define	M_SET		META('[')
140228753Smm#define	ismeta(c)	(((c)&M_META) != 0)
141228753Smm
142228753Smm#ifndef BUFSIZE
143228753Smm#define GLOBBUFLEN	MAXPATHLEN
144228753Smm#else
145228753Smm#define GLOBBUFLEN	BUFSIZE
146228753Smm#endif
147228753Smm
148228753Smmint
149228753Smmglobcharcoll(c1, c2, cs)
150228753Smm    int c1, c2, cs;
151228753Smm{
152228753Smm#if defined(NLS) && defined(LC_COLLATE) && !defined(NOSTRCOLL)
153228753Smm    char s1[2], s2[2];
154228753Smm
155228753Smm    if (c1 == c2)
156228753Smm	return (0);
157228753Smm    /*
158228753Smm     * From kevin lyda <kevin@suberic.net>:
159228753Smm     * strcoll does not guarantee case sorting, so we pre-process now:
160228753Smm     */
161228753Smm    if (cs) {
162228753Smm	c1 = islower(c1) ? c1 : tolower(c1);
163228753Smm	c2 = islower(c2) ? c2 : tolower(c2);
164228753Smm    } else {
165228753Smm	if (islower(c1) && isupper(c2))
166228753Smm	    return (1);
167228753Smm    }
168228753Smm    s1[0] = c1;
169228753Smm    s2[0] = c2;
170228753Smm    s1[1] = s2[1] = '\0';
171228753Smm    return strcoll(s1, s2);
172228753Smm#else
173228753Smm    return (c1 - c2);
174228753Smm#endif
175228753Smm}
176228753Smm
177228753Smm/*
178228753Smm * Need to dodge two kernel bugs:
179228753Smm * opendir("") != opendir(".")
180228753Smm * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
181228753Smm *            POSIX specifies that they should be ignored in directories.
182228753Smm */
183228753Smm
184228753Smmstatic DIR *
185228753SmmOpendir(str)
186228753Smm    register Char *str;
187228753Smm{
188228753Smm    char    buf[GLOBBUFLEN];
189228753Smm    register char *dc = buf;
190228753Smm#if defined(hpux) || defined(__hpux)
191228753Smm    struct stat st;
192228753Smm#endif
193228753Smm
194228753Smm    if (!*str)
195228753Smm	return (opendir("."));
196228753Smm    while ((*dc++ = *str++) != '\0')
197228753Smm	continue;
198228753Smm#if defined(hpux) || defined(__hpux)
199228753Smm    /*
200228753Smm     * Opendir on some device files hangs, so avoid it
201228753Smm     */
202228753Smm    if (stat(buf, &st) == -1 || !S_ISDIR(st.st_mode))
203228753Smm	return NULL;
204228753Smm#endif
205228753Smm    return (opendir(buf));
206228753Smm}
207228753Smm
208228753Smm#ifdef S_IFLNK
209228753Smmstatic int
210228753SmmLstat(fn, sb)
211228753Smm    register Char *fn;
212228753Smm    struct stat *sb;
213228753Smm{
214228753Smm    char    buf[GLOBBUFLEN];
215228753Smm    register char *dc = buf;
216228753Smm
217228753Smm    while ((*dc++ = *fn++) != '\0')
218228753Smm	continue;
219228753Smm# ifdef NAMEI_BUG
220228753Smm    {
221228753Smm	int     st;
222228753Smm
223228753Smm	st = lstat(buf, sb);
224228753Smm	if (*buf)
225228753Smm	    dc--;
226228753Smm	return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
227228753Smm    }
228228753Smm# else
229228753Smm    return (lstat(buf, sb));
230228753Smm# endif	/* NAMEI_BUG */
231228753Smm}
232228753Smm#else
233228753Smm#define Lstat Stat
234228753Smm#endif /* S_IFLNK */
235228753Smm
236228753Smmstatic int
237228753SmmStat(fn, sb)
238228753Smm    register Char *fn;
239228753Smm    struct stat *sb;
240228753Smm{
241228753Smm    char    buf[GLOBBUFLEN];
242228753Smm    register char *dc = buf;
243228753Smm
244228753Smm    while ((*dc++ = *fn++) != '\0')
245228753Smm	continue;
246228753Smm#ifdef NAMEI_BUG
247228753Smm    {
248228753Smm	int     st;
249228753Smm
250228753Smm	st = stat(buf, sb);
251228753Smm	if (*buf)
252228753Smm	    dc--;
253228753Smm	return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
254228753Smm    }
255228753Smm#else
256228753Smm    return (stat(buf, sb));
257228753Smm#endif /* NAMEI_BUG */
258228753Smm}
259228753Smm
260228753Smmstatic Char *
261228753SmmStrchr(str, ch)
262228753Smm    Char *str;
263228753Smm    int ch;
264228753Smm{
265228753Smm    do
266228753Smm	if (*str == ch)
267228753Smm	    return (str);
268228753Smm    while (*str++);
269228753Smm    return (NULL);
270228753Smm}
271228753Smm
272228753Smm#ifdef DEBUG
273228753Smmstatic void
274228753Smmqprintf(s)
275228753SmmChar *s;
276228753Smm{
277228753Smm    Char *p;
278228753Smm
279228753Smm    for (p = s; *p; p++)
280228753Smm	printf("%c", *p & 0xff);
281228753Smm    printf("\n");
282228753Smm    for (p = s; *p; p++)
283228753Smm	printf("%c", *p & M_PROTECT ? '"' : ' ');
284228753Smm    printf("\n");
285228753Smm    for (p = s; *p; p++)
286228753Smm	printf("%c", *p & M_META ? '_' : ' ');
287228753Smm    printf("\n");
288228753Smm}
289228753Smm#endif /* DEBUG */
290228753Smm
291228753Smmstatic int
292228753Smmcompare(p, q)
293228753Smm    const ptr_t  p, q;
294228753Smm{
295228753Smm#if defined(NLS) && !defined(NOSTRCOLL)
296228753Smm    errno = 0;  /* strcoll sets errno, another brain-damage */
297228753Smm
298228753Smm    return (strcoll(*(char **) p, *(char **) q));
299228753Smm#else
300228753Smm    return (strcmp(*(char **) p, *(char **) q));
301228753Smm#endif /* NLS && !NOSTRCOLL */
302228753Smm}
303228753Smm
304228753Smm/*
305228753Smm * The main glob() routine: compiles the pattern (optionally processing
306228753Smm * quotes), calls glob1() to do the real pattern matching, and finally
307228753Smm * sorts the list (unless unsorted operation is requested).  Returns 0
308228753Smm * if things went well, nonzero if errors occurred.  It is not an error
309228753Smm * to find no matches.
310228753Smm */
311228753Smmint
312228753Smmglob(pattern, flags, errfunc, pglob)
313228753Smm    const char *pattern;
314228753Smm    int     flags;
315228753Smm    int     (*errfunc) __P((const char *, int));
316228753Smm    glob_t *pglob;
317228753Smm{
318228753Smm    int     err, oldpathc;
319228753Smm    Char *bufnext, *bufend, *compilebuf, m_not;
320228753Smm    const unsigned char *compilepat, *patnext;
321228753Smm    int     c, not;
322228753Smm    Char patbuf[GLOBBUFLEN + 1], *qpatnext;
323228753Smm    int     no_match;
324228753Smm
325228753Smm    patnext = (unsigned char *) pattern;
326228753Smm    if (!(flags & GLOB_APPEND)) {
327228753Smm	pglob->gl_pathc = 0;
328228753Smm	pglob->gl_pathv = NULL;
329228753Smm	if (!(flags & GLOB_DOOFFS))
330228753Smm	    pglob->gl_offs = 0;
331228753Smm    }
332228753Smm    pglob->gl_flags = flags & ~GLOB_MAGCHAR;
333228753Smm    pglob->gl_errfunc = errfunc;
334228753Smm    oldpathc = pglob->gl_pathc;
335228753Smm    pglob->gl_matchc = 0;
336228753Smm
337228753Smm    if (pglob->gl_flags & GLOB_ALTNOT) {
338228753Smm	not = ALTNOT;
339228753Smm	m_not = M_ALTNOT;
340228753Smm    }
341228753Smm    else {
342228753Smm	not = NOT;
343228753Smm	m_not = M_NOT;
344228753Smm    }
345228753Smm
346228753Smm    bufnext = patbuf;
347228753Smm    bufend = bufnext + GLOBBUFLEN;
348228753Smm    compilebuf = bufnext;
349228753Smm    compilepat = patnext;
350228753Smm
351228753Smm    no_match = *patnext == not;
352228753Smm    if (no_match)
353228753Smm	patnext++;
354228753Smm
355228753Smm    if (flags & GLOB_QUOTE) {
356228753Smm	/* Protect the quoted characters */
357228753Smm	while (bufnext < bufend && (c = *patnext++) != EOS)
358228753Smm#ifdef DSPMBYTE
359228753Smm	    if (Ismbyte1(c) && *patnext != EOS)
360228753Smm	    {
361228753Smm	      *bufnext++ = (Char) c;
362228753Smm	      *bufnext++ = (Char) *patnext++;
363228753Smm	    }
364228753Smm	    else
365228753Smm#endif /* DSPMBYTE */
366228753Smm	    if (c == QUOTE) {
367228753Smm		if ((c = *patnext++) == EOS) {
368228753Smm		    c = QUOTE;
369228753Smm		    --patnext;
370228753Smm		}
371228753Smm		*bufnext++ = (Char) (c | M_PROTECT);
372228753Smm	    }
373228753Smm	    else
374228753Smm		*bufnext++ = (Char) c;
375228753Smm    }
376228753Smm    else
377228753Smm	while (bufnext < bufend && (c = *patnext++) != EOS)
378228753Smm	    *bufnext++ = (Char) c;
379228753Smm    *bufnext = EOS;
380228753Smm
381228753Smm    bufnext = patbuf;
382228753Smm    qpatnext = patbuf;
383228753Smm    /* we don't need to check for buffer overflow any more */
384228753Smm    while ((c = *qpatnext++) != EOS) {
385228753Smm#ifdef DSPMBYTE
386228753Smm	if (Ismbyte1(c) && *qpatnext != EOS)
387228753Smm	{
388228753Smm	  *bufnext++ = CHAR(c);
389228753Smm	  *bufnext++ = CHAR(*qpatnext++);
390228753Smm	}
391228753Smm	else
392228753Smm#endif /* DSPMBYTE */
393228753Smm	switch (c) {
394228753Smm	case LBRACKET:
395228753Smm	    c = *qpatnext;
396228753Smm	    if (c == not)
397228753Smm		++qpatnext;
398228753Smm	    if (*qpatnext == EOS ||
399228753Smm		Strchr(qpatnext + 1, RBRACKET) == NULL) {
400228753Smm		*bufnext++ = LBRACKET;
401228753Smm		if (c == not)
402228753Smm		    --qpatnext;
403228753Smm		break;
404228753Smm	    }
405228753Smm	    pglob->gl_flags |= GLOB_MAGCHAR;
406228753Smm	    *bufnext++ = M_SET;
407228753Smm	    if (c == not)
408228753Smm		*bufnext++ = m_not;
409228753Smm	    c = *qpatnext++;
410228753Smm	    do {
411228753Smm		*bufnext++ = CHAR(c);
412228753Smm		if (*qpatnext == RANGE &&
413228753Smm		    (c = qpatnext[1]) != RBRACKET) {
414228753Smm		    *bufnext++ = M_RNG;
415228753Smm		    *bufnext++ = CHAR(c);
416228753Smm		    qpatnext += 2;
417228753Smm		}
418228753Smm	    } while ((c = *qpatnext++) != RBRACKET);
419228753Smm	    *bufnext++ = M_END;
420228753Smm	    break;
421228753Smm	case QUESTION:
422228753Smm	    pglob->gl_flags |= GLOB_MAGCHAR;
423228753Smm	    *bufnext++ = M_ONE;
424228753Smm	    break;
425228753Smm	case STAR:
426228753Smm	    pglob->gl_flags |= GLOB_MAGCHAR;
427228753Smm	    /* collapse adjacent stars to one, to avoid
428228753Smm	     * exponential behavior
429228753Smm	     */
430228753Smm	    if (bufnext == patbuf || bufnext[-1] != M_ALL)
431228753Smm		*bufnext++ = M_ALL;
432228753Smm	    break;
433228753Smm	default:
434228753Smm	    *bufnext++ = CHAR(c);
435228753Smm	    break;
436228753Smm	}
437228753Smm    }
438228753Smm    *bufnext = EOS;
439228753Smm#ifdef DEBUG
440228753Smm    qprintf(patbuf);
441228753Smm#endif
442228753Smm
443228753Smm    if ((err = glob1(patbuf, pglob, no_match)) != 0)
444228753Smm	return (err);
445228753Smm
446228753Smm    /*
447228753Smm     * If there was no match we are going to append the pattern
448228753Smm     * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
449228753Smm     * and the pattern did not contain any magic characters
450228753Smm     * GLOB_NOMAGIC is there just for compatibility with csh.
451228753Smm     */
452228753Smm    if (pglob->gl_pathc == oldpathc &&
453228753Smm	((flags & GLOB_NOCHECK) ||
454228753Smm	 ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
455228753Smm	if (!(flags & GLOB_QUOTE)) {
456228753Smm	    Char *dp = compilebuf;
457228753Smm	    const unsigned char *sp = compilepat;
458228753Smm
459228753Smm	    while ((*dp++ = *sp++) != '\0')
460228753Smm		continue;
461228753Smm	}
462228753Smm	else {
463228753Smm	    /*
464228753Smm	     * copy pattern, interpreting quotes; this is slightly different
465228753Smm	     * than the interpretation of quotes above -- which should prevail?
466228753Smm	     */
467228753Smm	    while (*compilepat != EOS) {
468228753Smm		if (*compilepat == QUOTE) {
469228753Smm		    if (*++compilepat == EOS)
470228753Smm			--compilepat;
471228753Smm		}
472228753Smm		*compilebuf++ = (unsigned char) *compilepat++;
473228753Smm	    }
474228753Smm	    *compilebuf = EOS;
475228753Smm	}
476228753Smm	return (globextend(patbuf, pglob));
477228753Smm    }
478228753Smm    else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc))
479228753Smm	qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc),
480228753Smm	      pglob->gl_pathc - oldpathc, sizeof(char *),
481228753Smm	      (int (*) __P((const void *, const void *))) compare);
482228753Smm    return (0);
483228753Smm}
484228753Smm
485228753Smmstatic int
486228753Smmglob1(pattern, pglob, no_match)
487228753Smm    Char *pattern;
488228753Smm    glob_t *pglob;
489228753Smm    int     no_match;
490228753Smm{
491228753Smm    Char pathbuf[GLOBBUFLEN + 1];
492228753Smm
493228753Smm    /*
494228753Smm     * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
495228753Smm     */
496228753Smm    if (*pattern == EOS)
497228753Smm	return (0);
498228753Smm    return (glob2(pathbuf, pathbuf, pattern, pglob, no_match));
499228753Smm}
500228753Smm
501228753Smm/*
502228753Smm * functions glob2 and glob3 are mutually recursive; there is one level
503228753Smm * of recursion for each segment in the pattern that contains one or
504228753Smm * more meta characters.
505228753Smm */
506228753Smmstatic int
507228753Smmglob2(pathbuf, pathend, pattern, pglob, no_match)
508228753Smm    Char *pathbuf, *pathend, *pattern;
509228753Smm    glob_t *pglob;
510228753Smm    int     no_match;
511228753Smm{
512228753Smm    struct stat sbuf;
513228753Smm    int anymeta;
514228753Smm    Char *p, *q;
515228753Smm
516228753Smm    /*
517228753Smm     * loop over pattern segments until end of pattern or until segment with
518228753Smm     * meta character found.
519228753Smm     */
520228753Smm    anymeta = 0;
521228753Smm    for (;;) {
522228753Smm	if (*pattern == EOS) {	/* end of pattern? */
523228753Smm	    *pathend = EOS;
524228753Smm
525228753Smm	    if (Lstat(pathbuf, &sbuf))
526228753Smm		return (0);
527228753Smm
528228753Smm	    if (((pglob->gl_flags & GLOB_MARK) &&
529228753Smm		 pathend[-1] != SEP) &&
530228753Smm		(S_ISDIR(sbuf.st_mode)
531228753Smm#ifdef S_IFLNK
532228753Smm		 || (S_ISLNK(sbuf.st_mode) &&
533228753Smm		     (Stat(pathbuf, &sbuf) == 0) &&
534228753Smm		     S_ISDIR(sbuf.st_mode))
535228753Smm#endif
536228753Smm		 )) {
537228753Smm		*pathend++ = SEP;
538228753Smm		*pathend = EOS;
539228753Smm	    }
540228753Smm	    ++pglob->gl_matchc;
541228753Smm	    return (globextend(pathbuf, pglob));
542228753Smm	}
543228753Smm
544228753Smm	/* find end of next segment, copy tentatively to pathend */
545228753Smm	q = pathend;
546228753Smm	p = pattern;
547228753Smm	while (*p != EOS && *p != SEP) {
548228753Smm	    if (ismeta(*p))
549228753Smm		anymeta = 1;
550228753Smm	    *q++ = *p++;
551228753Smm	}
552228753Smm
553228753Smm	if (!anymeta) {		/* no expansion, do next segment */
554228753Smm	    pathend = q;
555228753Smm	    pattern = p;
556228753Smm	    while (*pattern == SEP)
557228753Smm		*pathend++ = *pattern++;
558228753Smm	}
559228753Smm	else			/* need expansion, recurse */
560228753Smm	    return (glob3(pathbuf, pathend, pattern, p, pglob, no_match));
561228753Smm    }
562228753Smm    /* NOTREACHED */
563228753Smm}
564228753Smm
565228753Smm
566228753Smmstatic int
567228753Smmglob3(pathbuf, pathend, pattern, restpattern, pglob, no_match)
568228753Smm    Char *pathbuf, *pathend, *pattern, *restpattern;
569228753Smm    glob_t *pglob;
570228753Smm    int     no_match;
571228753Smm{
572228753Smm    DIR    *dirp;
573228753Smm    struct dirent *dp;
574228753Smm    int     err;
575228753Smm    Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
576228753Smm    char cpathbuf[GLOBBUFLEN], *ptr;;
577228753Smm
578228753Smm    *pathend = EOS;
579228753Smm    errno = 0;
580228753Smm
581228753Smm    if (!(dirp = Opendir(pathbuf))) {
582228753Smm	/* todo: don't call for ENOENT or ENOTDIR? */
583228753Smm	for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;)
584228753Smm	    continue;
585228753Smm	if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) ||
586228753Smm	    (pglob->gl_flags & GLOB_ERR))
587228753Smm	    return (GLOB_ABEND);
588228753Smm	else
589228753Smm	    return (0);
590228753Smm    }
591228753Smm
592228753Smm    err = 0;
593228753Smm
594228753Smm    /* search directory for matching names */
595228753Smm    while ((dp = readdir(dirp)) != NULL) {
596228753Smm	register unsigned char *sc;
597228753Smm	register Char *dc;
598228753Smm
599228753Smm	/* initial DOT must be matched literally */
600228753Smm	if (dp->d_name[0] == DOT && *pattern != DOT)
601228753Smm	    continue;
602228753Smm	for (sc = (unsigned char *) dp->d_name, dc = pathend;
603228753Smm	     (*dc++ = *sc++) != '\0';)
604228753Smm	    continue;
605228753Smm	if (match(pathend, pattern, restpattern, (int) m_not) == no_match) {
606228753Smm	    *pathend = EOS;
607228753Smm	    continue;
608228753Smm	}
609228753Smm	err = glob2(pathbuf, --dc, restpattern, pglob, no_match);
610228753Smm	if (err)
611228753Smm	    break;
612228753Smm    }
613228753Smm    /* todo: check error from readdir? */
614228753Smm    (void) closedir(dirp);
615228753Smm    return (err);
616228753Smm}
617228753Smm
618228753Smm
619228753Smm/*
620228753Smm * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
621228753Smm * add the new item, and update gl_pathc.
622228753Smm *
623228753Smm * This assumes the BSD realloc, which only copies the block when its size
624228753Smm * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
625228753Smm * behavior.
626228753Smm *
627228753Smm * Return 0 if new item added, error code if memory couldn't be allocated.
628228753Smm *
629228753Smm * Invariant of the glob_t structure:
630228753Smm *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
631228753Smm *	 gl_pathv points to (gl_offs + gl_pathc + 1) items.
632228753Smm */
633228753Smmstatic int
634228753Smmglobextend(path, pglob)
635228753Smm    Char *path;
636228753Smm    glob_t *pglob;
637228753Smm{
638228753Smm    register char **pathv;
639228753Smm    register int i;
640228753Smm    unsigned int newsize;
641228753Smm    char   *copy;
642228753Smm    Char *p;
643228753Smm
644228753Smm    newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
645228753Smm    pathv = (char **) (pglob->gl_pathv ?
646228753Smm		       xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) :
647228753Smm		       xmalloc((size_t) newsize));
648228753Smm    if (pathv == NULL)
649228753Smm	return (GLOB_NOSPACE);
650228753Smm
651228753Smm    if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
652228753Smm	/* first time around -- clear initial gl_offs items */
653228753Smm	pathv += pglob->gl_offs;
654228753Smm	for (i = pglob->gl_offs; --i >= 0;)
655228753Smm	    *--pathv = NULL;
656228753Smm    }
657228753Smm    pglob->gl_pathv = pathv;
658228753Smm
659228753Smm    for (p = path; *p++;)
660228753Smm	continue;
661228753Smm    if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) {
662228753Smm	register char *dc = copy;
663228753Smm	register Char *sc = path;
664228753Smm
665228753Smm	while ((*dc++ = *sc++) != '\0')
666228753Smm	    continue;
667228753Smm	pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
668228753Smm    }
669228753Smm    pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
670228753Smm    return ((copy == NULL) ? GLOB_NOSPACE : 0);
671228753Smm}
672228753Smm
673228753Smm
674228753Smm/*
675228753Smm * pattern matching function for filenames.  Each occurrence of the *
676228753Smm * pattern causes a recursion level.
677228753Smm */
678228753Smmstatic  int
679228753Smmmatch(name, pat, patend, m_not)
680228753Smm    register Char *name, *pat, *patend;
681228753Smm    int m_not;
682228753Smm{
683228753Smm    int ok, negate_range;
684228753Smm    Char c, k;
685228753Smm
686228753Smm    while (pat < patend) {
687228753Smm	c = *pat++;
688228753Smm	switch (c & M_MASK) {
689228753Smm	case M_ALL:
690228753Smm	    if (pat == patend)
691228753Smm		return (1);
692228753Smm	    do
693228753Smm		if (match(name, pat, patend, m_not))
694228753Smm		    return (1);
695228753Smm	    while (*name++ != EOS);
696228753Smm	    return (0);
697228753Smm	case M_ONE:
698228753Smm	    if (*name++ == EOS)
699228753Smm		return (0);
700228753Smm	    break;
701228753Smm	case M_SET:
702228753Smm	    ok = 0;
703228753Smm	    if ((k = *name++) == EOS)
704228753Smm		return (0);
705228753Smm	    if ((negate_range = ((*pat & M_MASK) == m_not)) != 0)
706228753Smm		++pat;
707228753Smm	    while (((c = *pat++) & M_MASK) != M_END) {
708228753Smm		if ((*pat & M_MASK) == M_RNG) {
709228753Smm		    if (globcharcoll(CHAR(c), CHAR(k), 0) <= 0 &&
710228753Smm			globcharcoll(CHAR(k), CHAR(pat[1]), 0) <= 0)
711228753Smm			ok = 1;
712228753Smm		    pat += 2;
713228753Smm		}
714228753Smm		else if (c == k)
715228753Smm		    ok = 1;
716228753Smm	    }
717228753Smm	    if (ok == negate_range)
718228753Smm		return (0);
719228753Smm	    break;
720228753Smm	default:
721228753Smm	    k = *name++;
722228753Smm	    if (samecase(k) != samecase(c))
723228753Smm		return (0);
724228753Smm	    break;
725228753Smm	}
726228753Smm    }
727228753Smm    return (*name == EOS);
728228753Smm}
729228753Smm
730228753Smm/* free allocated data belonging to a glob_t structure */
731228753Smmvoid
732228753Smmglobfree(pglob)
733228753Smm    glob_t *pglob;
734228753Smm{
735228753Smm    register int i;
736228753Smm    register char **pp;
737228753Smm
738228753Smm    if (pglob->gl_pathv != NULL) {
739228753Smm	pp = pglob->gl_pathv + pglob->gl_offs;
740228753Smm	for (i = pglob->gl_pathc; i--; ++pp)
741228753Smm	    if (*pp)
742228753Smm		xfree((ptr_t) *pp), *pp = NULL;
743228753Smm	xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL;
744228753Smm    }
745228753Smm}
746228753Smm