glob.c revision 69408
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * 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 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36#if defined(LIBC_SCCS) && !defined(lint)
37static char sccsid[] = "@(#)glob.c	5.12 (Berkeley) 6/24/91";
38#endif /* LIBC_SCCS and not lint */
39/*
40 * Glob: the interface is a superset of the one defined in POSIX 1003.2,
41 * draft 9.
42 *
43 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
44 *
45 * Optional extra services, controlled by flags not defined by POSIX:
46 *
47 * GLOB_QUOTE:
48 *	Escaping convention: \ inhibits any special meaning the following
49 *	character might have (except \ at end of string is retained).
50 * GLOB_MAGCHAR:
51 *	Set in gl_flags if pattern contained a globbing character.
52 * GLOB_ALTNOT:
53 *	Use ^ instead of ! for "not".
54 * gl_matchc:
55 *	Number of matches in the current invocation of glob.
56 */
57
58#ifdef notdef
59#include <sys/types.h>
60#include <sys/param.h>
61#include <sys/stat.h>
62#include <dirent.h>
63#include <ctype.h>
64typedef void * ptr_t;
65#endif
66#ifdef WINNT_NATIVE
67	#pragma warning(disable:4244)
68#endif /* WINNT_NATIVE */
69
70#define Char __Char
71#include "sh.h"
72#undef Char
73#undef QUOTE
74#undef TILDE
75#undef META
76#undef CHAR
77#undef ismeta
78#undef Strchr
79
80#include "glob.h"
81
82#ifndef S_ISDIR
83#define S_ISDIR(a)	(((a) & S_IFMT) == S_IFDIR)
84#endif
85
86#if !defined(S_ISLNK) && defined(S_IFLNK)
87#define S_ISLNK(a)	(((a) & S_IFMT) == S_IFLNK)
88#endif
89
90#if !defined(S_ISLNK) && !defined(lstat)
91#define lstat stat
92#endif
93
94typedef unsigned short Char;
95
96static	int	 glob1 		__P((Char *, glob_t *, int));
97static	int	 glob2		__P((Char *, Char *, Char *, glob_t *, int));
98static	int	 glob3		__P((Char *, Char *, Char *, Char *,
99				     glob_t *, int));
100static	int	 globextend	__P((Char *, glob_t *));
101static	int	 match		__P((Char *, Char *, Char *, int));
102#ifndef __clipper__
103static	int	 compare	__P((const ptr_t, const ptr_t));
104#endif
105static 	DIR	*Opendir	__P((Char *));
106#ifdef S_IFLNK
107static	int	 Lstat		__P((Char *, struct stat *));
108#endif
109static	int	 Stat		__P((Char *, struct stat *sb));
110static 	Char 	*Strchr		__P((Char *, int));
111#ifdef DEBUG
112static	void	 qprintf	__P((Char *));
113#endif
114
115#define	DOLLAR		'$'
116#define	DOT		'.'
117#define	EOS		'\0'
118#define	LBRACKET	'['
119#define	NOT		'!'
120#define ALTNOT		'^'
121#define	QUESTION	'?'
122#define	QUOTE		'\\'
123#define	RANGE		'-'
124#define	RBRACKET	']'
125#define	SEP		'/'
126#define	STAR		'*'
127#define	TILDE		'~'
128#define	UNDERSCORE	'_'
129
130#define	M_META		0x8000
131#define M_PROTECT	0x4000
132#define	M_MASK		0xffff
133#define	M_ASCII		0x00ff
134
135#define	CHAR(c)		((c)&M_ASCII)
136#define	META(c)		((c)|M_META)
137#define	M_ALL		META('*')
138#define	M_END		META(']')
139#define	M_NOT		META('!')
140#define	M_ALTNOT	META('^')
141#define	M_ONE		META('?')
142#define	M_RNG		META('-')
143#define	M_SET		META('[')
144#define	ismeta(c)	(((c)&M_META) != 0)
145
146#ifndef BUFSIZE
147#define GLOBBUFLEN	MAXPATHLEN
148#else
149#define GLOBBUFLEN	BUFSIZE
150#endif
151
152int
153globcharcoll(c1, c2)
154    int c1, c2;
155{
156#if defined(NLS) && defined(LC_COLLATE) && !defined(NOSTRCOLL)
157    char s1[2], s2[2];
158
159    if (c1 == c2)
160	return (0);
161    /*
162     * From kevin lyda <kevin@suberic.net>:
163     * strcoll does not guarantee case sorting, so we pre-process now:
164     */
165    if (islower(c1) && isupper(c2))
166	return (1);
167    s1[0] = c1;
168    s2[0] = c2;
169    s1[1] = s2[1] = '\0';
170    return strcoll(s1, s2);
171#else
172    return (c1 - c2);
173#endif
174}
175
176/*
177 * Need to dodge two kernel bugs:
178 * opendir("") != opendir(".")
179 * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
180 *            POSIX specifies that they should be ignored in directories.
181 */
182
183static DIR *
184Opendir(str)
185    register Char *str;
186{
187    char    buf[GLOBBUFLEN];
188    register char *dc = buf;
189#if defined(hpux) || defined(__hpux)
190    struct stat st;
191#endif
192
193    if (!*str)
194	return (opendir("."));
195    while ((*dc++ = *str++) != '\0')
196	continue;
197#if defined(hpux) || defined(__hpux)
198    /*
199     * Opendir on some device files hangs, so avoid it
200     */
201    if (stat(buf, &st) == -1 || !S_ISDIR(st.st_mode))
202	return NULL;
203#endif
204    return (opendir(buf));
205}
206
207#ifdef S_IFLNK
208static int
209Lstat(fn, sb)
210    register Char *fn;
211    struct stat *sb;
212{
213    char    buf[GLOBBUFLEN];
214    register char *dc = buf;
215
216    while ((*dc++ = *fn++) != '\0')
217	continue;
218# ifdef NAMEI_BUG
219    {
220	int     st;
221
222	st = lstat(buf, sb);
223	if (*buf)
224	    dc--;
225	return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
226    }
227# else
228    return (lstat(buf, sb));
229# endif	/* NAMEI_BUG */
230}
231#else
232#define Lstat Stat
233#endif /* S_IFLNK */
234
235static int
236Stat(fn, sb)
237    register Char *fn;
238    struct stat *sb;
239{
240    char    buf[GLOBBUFLEN];
241    register char *dc = buf;
242
243    while ((*dc++ = *fn++) != '\0')
244	continue;
245#ifdef NAMEI_BUG
246    {
247	int     st;
248
249	st = stat(buf, sb);
250	if (*buf)
251	    dc--;
252	return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
253    }
254#else
255    return (stat(buf, sb));
256#endif /* NAMEI_BUG */
257}
258
259static Char *
260Strchr(str, ch)
261    Char *str;
262    int ch;
263{
264    do
265	if (*str == ch)
266	    return (str);
267    while (*str++);
268    return (NULL);
269}
270
271#ifdef DEBUG
272static void
273qprintf(s)
274Char *s;
275{
276    Char *p;
277
278    for (p = s; *p; p++)
279	printf("%c", *p & 0xff);
280    printf("\n");
281    for (p = s; *p; p++)
282	printf("%c", *p & M_PROTECT ? '"' : ' ');
283    printf("\n");
284    for (p = s; *p; p++)
285	printf("%c", *p & M_META ? '_' : ' ');
286    printf("\n");
287}
288#endif /* DEBUG */
289
290static int
291compare(p, q)
292    const ptr_t  p, q;
293{
294#if defined(NLS) && !defined(NOSTRCOLL)
295    errno = 0;  /* strcoll sets errno, another brain-damage */
296
297    return (strcoll(*(char **) p, *(char **) q));
298#else
299    return (strcmp(*(char **) p, *(char **) q));
300#endif /* NLS && !NOSTRCOLL */
301}
302
303/*
304 * The main glob() routine: compiles the pattern (optionally processing
305 * quotes), calls glob1() to do the real pattern matching, and finally
306 * sorts the list (unless unsorted operation is requested).  Returns 0
307 * if things went well, nonzero if errors occurred.  It is not an error
308 * to find no matches.
309 */
310int
311glob(pattern, flags, errfunc, pglob)
312    const char *pattern;
313    int     flags;
314    int     (*errfunc) __P((const char *, int));
315    glob_t *pglob;
316{
317    int     err, oldpathc;
318    Char *bufnext, *bufend, *compilebuf, m_not;
319    const unsigned char *compilepat, *patnext;
320    int     c, not;
321    Char patbuf[GLOBBUFLEN + 1], *qpatnext;
322    int     no_match;
323
324    patnext = (unsigned char *) pattern;
325    if (!(flags & GLOB_APPEND)) {
326	pglob->gl_pathc = 0;
327	pglob->gl_pathv = NULL;
328	if (!(flags & GLOB_DOOFFS))
329	    pglob->gl_offs = 0;
330    }
331    pglob->gl_flags = flags & ~GLOB_MAGCHAR;
332    pglob->gl_errfunc = errfunc;
333    oldpathc = pglob->gl_pathc;
334    pglob->gl_matchc = 0;
335
336    if (pglob->gl_flags & GLOB_ALTNOT) {
337	not = ALTNOT;
338	m_not = M_ALTNOT;
339    }
340    else {
341	not = NOT;
342	m_not = M_NOT;
343    }
344
345    bufnext = patbuf;
346    bufend = bufnext + GLOBBUFLEN;
347    compilebuf = bufnext;
348    compilepat = patnext;
349
350    no_match = *patnext == not;
351    if (no_match)
352	patnext++;
353
354    if (flags & GLOB_QUOTE) {
355	/* Protect the quoted characters */
356	while (bufnext < bufend && (c = *patnext++) != EOS)
357#ifdef DSPMBYTE
358	    if (Ismbyte1(c) && *patnext != EOS)
359	    {
360	      *bufnext++ = (Char) c;
361	      *bufnext++ = (Char) *patnext++;
362	    }
363	    else
364#endif /* DSPMBYTE */
365	    if (c == QUOTE) {
366		if ((c = *patnext++) == EOS) {
367		    c = QUOTE;
368		    --patnext;
369		}
370		*bufnext++ = (Char) (c | M_PROTECT);
371	    }
372	    else
373		*bufnext++ = (Char) c;
374    }
375    else
376	while (bufnext < bufend && (c = *patnext++) != EOS)
377	    *bufnext++ = (Char) c;
378    *bufnext = EOS;
379
380    bufnext = patbuf;
381    qpatnext = patbuf;
382    /* we don't need to check for buffer overflow any more */
383    while ((c = *qpatnext++) != EOS) {
384#ifdef DSPMBYTE
385	if (Ismbyte1(c) && *qpatnext != EOS)
386	{
387	  *bufnext++ = CHAR(c);
388	  *bufnext++ = CHAR(*qpatnext++);
389	}
390	else
391#endif /* DSPMBYTE */
392	switch (c) {
393	case LBRACKET:
394	    c = *qpatnext;
395	    if (c == not)
396		++qpatnext;
397	    if (*qpatnext == EOS ||
398		Strchr(qpatnext + 1, RBRACKET) == NULL) {
399		*bufnext++ = LBRACKET;
400		if (c == not)
401		    --qpatnext;
402		break;
403	    }
404	    pglob->gl_flags |= GLOB_MAGCHAR;
405	    *bufnext++ = M_SET;
406	    if (c == not)
407		*bufnext++ = m_not;
408	    c = *qpatnext++;
409	    do {
410		*bufnext++ = CHAR(c);
411		if (*qpatnext == RANGE &&
412		    (c = qpatnext[1]) != RBRACKET) {
413		    *bufnext++ = M_RNG;
414		    *bufnext++ = CHAR(c);
415		    qpatnext += 2;
416		}
417	    } while ((c = *qpatnext++) != RBRACKET);
418	    *bufnext++ = M_END;
419	    break;
420	case QUESTION:
421	    pglob->gl_flags |= GLOB_MAGCHAR;
422	    *bufnext++ = M_ONE;
423	    break;
424	case STAR:
425	    pglob->gl_flags |= GLOB_MAGCHAR;
426	    /* collapse adjacent stars to one, to avoid
427	     * exponential behavior
428	     */
429	    if (bufnext == patbuf || bufnext[-1] != M_ALL)
430		*bufnext++ = M_ALL;
431	    break;
432	default:
433	    *bufnext++ = CHAR(c);
434	    break;
435	}
436    }
437    *bufnext = EOS;
438#ifdef DEBUG
439    qprintf(patbuf);
440#endif
441
442    if ((err = glob1(patbuf, pglob, no_match)) != 0)
443	return (err);
444
445    /*
446     * If there was no match we are going to append the pattern
447     * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
448     * and the pattern did not contain any magic characters
449     * GLOB_NOMAGIC is there just for compatibility with csh.
450     */
451    if (pglob->gl_pathc == oldpathc &&
452	((flags & GLOB_NOCHECK) ||
453	 ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
454	if (!(flags & GLOB_QUOTE)) {
455	    Char *dp = compilebuf;
456	    const unsigned char *sp = compilepat;
457
458	    while ((*dp++ = *sp++) != '\0')
459		continue;
460	}
461	else {
462	    /*
463	     * copy pattern, interpreting quotes; this is slightly different
464	     * than the interpretation of quotes above -- which should prevail?
465	     */
466	    while (*compilepat != EOS) {
467		if (*compilepat == QUOTE) {
468		    if (*++compilepat == EOS)
469			--compilepat;
470		}
471		*compilebuf++ = (unsigned char) *compilepat++;
472	    }
473	    *compilebuf = EOS;
474	}
475	return (globextend(patbuf, pglob));
476    }
477    else if (!(flags & GLOB_NOSORT) && (pglob->gl_pathc != oldpathc))
478	qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc),
479	      pglob->gl_pathc - oldpathc, sizeof(char *),
480	      (int (*) __P((const void *, const void *))) compare);
481    return (0);
482}
483
484static int
485glob1(pattern, pglob, no_match)
486    Char *pattern;
487    glob_t *pglob;
488    int     no_match;
489{
490    Char pathbuf[GLOBBUFLEN + 1];
491
492    /*
493     * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
494     */
495    if (*pattern == EOS)
496	return (0);
497    return (glob2(pathbuf, pathbuf, pattern, pglob, no_match));
498}
499
500/*
501 * functions glob2 and glob3 are mutually recursive; there is one level
502 * of recursion for each segment in the pattern that contains one or
503 * more meta characters.
504 */
505static int
506glob2(pathbuf, pathend, pattern, pglob, no_match)
507    Char *pathbuf, *pathend, *pattern;
508    glob_t *pglob;
509    int     no_match;
510{
511    struct stat sbuf;
512    int anymeta;
513    Char *p, *q;
514
515    /*
516     * loop over pattern segments until end of pattern or until segment with
517     * meta character found.
518     */
519    anymeta = 0;
520    for (;;) {
521	if (*pattern == EOS) {	/* end of pattern? */
522	    *pathend = EOS;
523
524	    if (Lstat(pathbuf, &sbuf))
525		return (0);
526
527	    if (((pglob->gl_flags & GLOB_MARK) &&
528		 pathend[-1] != SEP) &&
529		(S_ISDIR(sbuf.st_mode)
530#ifdef S_IFLNK
531		 || (S_ISLNK(sbuf.st_mode) &&
532		     (Stat(pathbuf, &sbuf) == 0) &&
533		     S_ISDIR(sbuf.st_mode))
534#endif
535		 )) {
536		*pathend++ = SEP;
537		*pathend = EOS;
538	    }
539	    ++pglob->gl_matchc;
540	    return (globextend(pathbuf, pglob));
541	}
542
543	/* find end of next segment, copy tentatively to pathend */
544	q = pathend;
545	p = pattern;
546	while (*p != EOS && *p != SEP) {
547	    if (ismeta(*p))
548		anymeta = 1;
549	    *q++ = *p++;
550	}
551
552	if (!anymeta) {		/* no expansion, do next segment */
553	    pathend = q;
554	    pattern = p;
555	    while (*pattern == SEP)
556		*pathend++ = *pattern++;
557	}
558	else			/* need expansion, recurse */
559	    return (glob3(pathbuf, pathend, pattern, p, pglob, no_match));
560    }
561    /* NOTREACHED */
562}
563
564
565static int
566glob3(pathbuf, pathend, pattern, restpattern, pglob, no_match)
567    Char *pathbuf, *pathend, *pattern, *restpattern;
568    glob_t *pglob;
569    int     no_match;
570{
571    DIR    *dirp;
572    struct dirent *dp;
573    int     err;
574    Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
575    char cpathbuf[GLOBBUFLEN], *ptr;;
576
577    *pathend = EOS;
578    errno = 0;
579
580    if (!(dirp = Opendir(pathbuf))) {
581	/* todo: don't call for ENOENT or ENOTDIR? */
582	for (ptr = cpathbuf; (*ptr++ = (char) *pathbuf++) != EOS;)
583	    continue;
584	if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (cpathbuf, errno)) ||
585	    (pglob->gl_flags & GLOB_ERR))
586	    return (GLOB_ABEND);
587	else
588	    return (0);
589    }
590
591    err = 0;
592
593    /* search directory for matching names */
594    while ((dp = readdir(dirp)) != NULL) {
595	register unsigned char *sc;
596	register Char *dc;
597
598	/* initial DOT must be matched literally */
599	if (dp->d_name[0] == DOT && *pattern != DOT)
600	    continue;
601	for (sc = (unsigned char *) dp->d_name, dc = pathend;
602	     (*dc++ = *sc++) != '\0';)
603	    continue;
604	if (match(pathend, pattern, restpattern, (int) m_not) == no_match) {
605	    *pathend = EOS;
606	    continue;
607	}
608	err = glob2(pathbuf, --dc, restpattern, pglob, no_match);
609	if (err)
610	    break;
611    }
612    /* todo: check error from readdir? */
613    (void) closedir(dirp);
614    return (err);
615}
616
617
618/*
619 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
620 * add the new item, and update gl_pathc.
621 *
622 * This assumes the BSD realloc, which only copies the block when its size
623 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
624 * behavior.
625 *
626 * Return 0 if new item added, error code if memory couldn't be allocated.
627 *
628 * Invariant of the glob_t structure:
629 *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
630 *	 gl_pathv points to (gl_offs + gl_pathc + 1) items.
631 */
632static int
633globextend(path, pglob)
634    Char *path;
635    glob_t *pglob;
636{
637    register char **pathv;
638    register int i;
639    unsigned int newsize;
640    char   *copy;
641    Char *p;
642
643    newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
644    pathv = (char **) (pglob->gl_pathv ?
645		       xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) :
646		       xmalloc((size_t) newsize));
647    if (pathv == NULL)
648	return (GLOB_NOSPACE);
649
650    if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
651	/* first time around -- clear initial gl_offs items */
652	pathv += pglob->gl_offs;
653	for (i = pglob->gl_offs; --i >= 0;)
654	    *--pathv = NULL;
655    }
656    pglob->gl_pathv = pathv;
657
658    for (p = path; *p++;)
659	continue;
660    if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) {
661	register char *dc = copy;
662	register Char *sc = path;
663
664	while ((*dc++ = *sc++) != '\0')
665	    continue;
666	pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
667    }
668    pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
669    return ((copy == NULL) ? GLOB_NOSPACE : 0);
670}
671
672
673/*
674 * pattern matching function for filenames.  Each occurrence of the *
675 * pattern causes a recursion level.
676 */
677static  int
678match(name, pat, patend, m_not)
679    register Char *name, *pat, *patend;
680    int m_not;
681{
682    int ok, negate_range;
683    Char c, k;
684
685    while (pat < patend) {
686	c = *pat++;
687	switch (c & M_MASK) {
688	case M_ALL:
689	    if (pat == patend)
690		return (1);
691	    do
692		if (match(name, pat, patend, m_not))
693		    return (1);
694	    while (*name++ != EOS);
695	    return (0);
696	case M_ONE:
697	    if (*name++ == EOS)
698		return (0);
699	    break;
700	case M_SET:
701	    ok = 0;
702	    if ((k = *name++) == EOS)
703		return (0);
704	    if ((negate_range = ((*pat & M_MASK) == m_not)) != 0)
705		++pat;
706	    while (((c = *pat++) & M_MASK) != M_END) {
707		if ((*pat & M_MASK) == M_RNG) {
708		    if (globcharcoll(CHAR(c), CHAR(k)) <= 0 &&
709			globcharcoll(CHAR(k), CHAR(pat[1])) <= 0)
710			ok = 1;
711		    pat += 2;
712		}
713		else if (c == k)
714		    ok = 1;
715	    }
716	    if (ok == negate_range)
717		return (0);
718	    break;
719	default:
720	    k = *name++;
721	    if (samecase(k) != samecase(c))
722		return (0);
723	    break;
724	}
725    }
726    return (*name == EOS);
727}
728
729/* free allocated data belonging to a glob_t structure */
730void
731globfree(pglob)
732    glob_t *pglob;
733{
734    register int i;
735    register char **pp;
736
737    if (pglob->gl_pathv != NULL) {
738	pp = pglob->gl_pathv + pglob->gl_offs;
739	for (i = pglob->gl_pathc; i--; ++pp)
740	    if (*pp)
741		xfree((ptr_t) *pp), *pp = NULL;
742	xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL;
743    }
744}
745