File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / win32 / glob.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:34 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    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:  * 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: 
   37: /* $Id: glob.c,v 1.1.1.2 2012/05/29 12:34:34 misho Exp $ */
   38: 
   39: /*
   40:  * glob(3) -- a superset of the one defined in POSIX 1003.2.
   41:  *
   42:  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
   43:  *
   44:  * Optional extra services, controlled by flags not defined by POSIX:
   45:  *
   46:  * GLOB_QUOTE:
   47:  *	Escaping convention: \ inhibits any special meaning the following
   48:  *	character might have (except \ at end of string is retained).
   49:  * GLOB_MAGCHAR:
   50:  *	Set in gl_flags if pattern contained a globbing character.
   51:  * GLOB_NOMAGIC:
   52:  *	Same as GLOB_NOCHECK, but it will only append pattern if it did
   53:  *	not contain any magic characters.  [Used in csh style globbing]
   54:  * GLOB_ALTDIRFUNC:
   55:  *	Use alternately specified directory access functions.
   56:  * GLOB_TILDE:
   57:  *	expand ~user/foo to the /home/dir/of/user/foo
   58:  * GLOB_BRACE:
   59:  *	expand {1,2}{a,b} to 1a 1b 2a 2b
   60:  * gl_matchc:
   61:  *	Number of matches in the current invocation of glob.
   62:  */
   63: #ifdef PHP_WIN32
   64: #define _POSIX_
   65: #include <limits.h>
   66: #undef _POSIX_
   67: #ifndef S_ISDIR
   68: #define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR)
   69: #endif
   70: #ifndef S_ISLNK
   71: #define S_ISLNK(m) (0)
   72: #endif
   73: #endif
   74: 
   75: #include "php.h"
   76: #include <sys/stat.h>
   77: 
   78: #include <ctype.h>
   79: #ifndef PHP_WIN32
   80: #include <sys/param.h>
   81: #include <dirent.h>
   82: #include <pwd.h>
   83: #include <unistd.h>
   84: #endif
   85: #include <errno.h>
   86: #include "glob.h"
   87: #include <stdio.h>
   88: #include <stdlib.h>
   89: #include <string.h>
   90: 
   91: #define	DOLLAR		'$'
   92: #define	DOT		'.'
   93: #define	EOS		'\0'
   94: #define	LBRACKET	'['
   95: #define	NOT		'!'
   96: #define	QUESTION	'?'
   97: #define	QUOTE		'\\'
   98: #define	RANGE		'-'
   99: #define	RBRACKET	']'
  100: #define	SEP		DEFAULT_SLASH
  101: #define	STAR		'*'
  102: #define	TILDE		'~'
  103: #define	UNDERSCORE	'_'
  104: #define	LBRACE		'{'
  105: #define	RBRACE		'}'
  106: #define	SLASH		'/'
  107: #define	COMMA		','
  108: 
  109: #ifndef DEBUG
  110: 
  111: #define	M_QUOTE		0x8000
  112: #define	M_PROTECT	0x4000
  113: #define	M_MASK		0xffff
  114: #define	M_ASCII		0x00ff
  115: 
  116: typedef u_short Char;
  117: 
  118: #else
  119: 
  120: #define	M_QUOTE		0x80
  121: #define	M_PROTECT	0x40
  122: #define	M_MASK		0xff
  123: #define	M_ASCII		0x7f
  124: 
  125: typedef char Char;
  126: 
  127: #endif
  128: 
  129: 
  130: #define	CHAR(c)		((Char)((c)&M_ASCII))
  131: #define	META(c)		((Char)((c)|M_QUOTE))
  132: #define	M_ALL		META('*')
  133: #define	M_END		META(']')
  134: #define	M_NOT		META('!')
  135: #define	M_ONE		META('?')
  136: #define	M_RNG		META('-')
  137: #define	M_SET		META('[')
  138: #define	ismeta(c)	(((c)&M_QUOTE) != 0)
  139: 
  140: static int	 compare(const void *, const void *);
  141: static int	 g_Ctoc(const Char *, char *, u_int);
  142: static int	 g_lstat(Char *, struct stat *, glob_t *);
  143: static DIR	*g_opendir(Char *, glob_t *);
  144: static Char	*g_strchr(Char *, int);
  145: static int	 g_stat(Char *, struct stat *, glob_t *);
  146: static int	 glob0(const Char *, glob_t *);
  147: static int	 glob1(Char *, Char *, glob_t *, size_t *);
  148: static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
  149: 				glob_t *, size_t *);
  150: static int	 glob3(Char *, Char *, Char *, Char *, Char *, Char *,
  151: 				Char *, Char *, glob_t *, size_t *);
  152: static int	 globextend(const Char *, glob_t *, size_t *);
  153: static const Char *globtilde(const Char *, Char *, size_t, glob_t *);
  154: static int	 globexp1(const Char *, glob_t *);
  155: static int	 globexp2(const Char *, const Char *, glob_t *, int *);
  156: static int	 match(Char *, Char *, Char *);
  157: #ifdef DEBUG
  158: static void	 qprintf(const char *, Char *);
  159: #endif
  160: 
  161: PHPAPI int
  162: glob(pattern, flags, errfunc, pglob)
  163: 	const char *pattern;
  164: 	int flags, (*errfunc)(const char *, int);
  165: 	glob_t *pglob;
  166: {
  167: 	const u_char *patnext;
  168: 	int c;
  169: 	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
  170: 
  171: #ifdef PHP_WIN32
  172: 	/* Force skipping escape sequences on windows
  173: 	 * due to the ambiguity with path backslashes
  174: 	 */
  175: 	flags |= GLOB_NOESCAPE;
  176: #endif
  177: 
  178: 	patnext = (u_char *) pattern;
  179: 	if (!(flags & GLOB_APPEND)) {
  180: 		pglob->gl_pathc = 0;
  181: 		pglob->gl_pathv = NULL;
  182: 		if (!(flags & GLOB_DOOFFS))
  183: 			pglob->gl_offs = 0;
  184: 	}
  185: 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  186: 	pglob->gl_errfunc = errfunc;
  187: 	pglob->gl_matchc = 0;
  188: 
  189: 	bufnext = patbuf;
  190: 	bufend = bufnext + MAXPATHLEN - 1;
  191: 	if (flags & GLOB_NOESCAPE)
  192: 		while (bufnext < bufend && (c = *patnext++) != EOS)
  193: 			*bufnext++ = c;
  194: 	else {
  195: 		/* Protect the quoted characters. */
  196: 		while (bufnext < bufend && (c = *patnext++) != EOS)
  197: 			if (c == QUOTE) {
  198: 				if ((c = *patnext++) == EOS) {
  199: 					c = QUOTE;
  200: 					--patnext;
  201: 				}
  202: 				*bufnext++ = c | M_PROTECT;
  203: 			} else
  204: 				*bufnext++ = c;
  205: 	}
  206: 	*bufnext = EOS;
  207: 
  208: 	if (flags & GLOB_BRACE)
  209: 		return globexp1(patbuf, pglob);
  210: 	else
  211: 		return glob0(patbuf, pglob);
  212: }
  213: 
  214: /*
  215:  * Expand recursively a glob {} pattern. When there is no more expansion
  216:  * invoke the standard globbing routine to glob the rest of the magic
  217:  * characters
  218:  */
  219: static int
  220: globexp1(pattern, pglob)
  221: 	const Char *pattern;
  222: 	glob_t *pglob;
  223: {
  224: 	const Char* ptr = pattern;
  225: 	int rv;
  226: 
  227: 	/* Protect a single {}, for find(1), like csh */
  228: 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
  229: 		return glob0(pattern, pglob);
  230: 
  231: 	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
  232: 		if (!globexp2(ptr, pattern, pglob, &rv))
  233: 			return rv;
  234: 
  235: 	return glob0(pattern, pglob);
  236: }
  237: 
  238: 
  239: /*
  240:  * Recursive brace globbing helper. Tries to expand a single brace.
  241:  * If it succeeds then it invokes globexp1 with the new pattern.
  242:  * If it fails then it tries to glob the rest of the pattern and returns.
  243:  */
  244: static int
  245: globexp2(ptr, pattern, pglob, rv)
  246: 	const Char *ptr, *pattern;
  247: 	glob_t *pglob;
  248: 	int *rv;
  249: {
  250: 	int     i;
  251: 	Char   *lm, *ls;
  252: 	const Char *pe, *pm, *pl;
  253: 	Char    patbuf[MAXPATHLEN];
  254: 
  255: 	/* copy part up to the brace */
  256: 	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
  257: 		;
  258: 	*lm = EOS;
  259: 	ls = lm;
  260: 
  261: 	/* Find the balanced brace */
  262: 	for (i = 0, pe = ++ptr; *pe; pe++)
  263: 		if (*pe == LBRACKET) {
  264: 			/* Ignore everything between [] */
  265: 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
  266: 				;
  267: 			if (*pe == EOS) {
  268: 				/*
  269: 				 * We could not find a matching RBRACKET.
  270: 				 * Ignore and just look for RBRACE
  271: 				 */
  272: 				pe = pm;
  273: 			}
  274: 		} else if (*pe == LBRACE)
  275: 			i++;
  276: 		else if (*pe == RBRACE) {
  277: 			if (i == 0)
  278: 				break;
  279: 			i--;
  280: 		}
  281: 
  282: 	/* Non matching braces; just glob the pattern */
  283: 	if (i != 0 || *pe == EOS) {
  284: 		*rv = glob0(patbuf, pglob);
  285: 		return 0;
  286: 	}
  287: 
  288: 	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
  289: 		switch (*pm) {
  290: 		case LBRACKET:
  291: 			/* Ignore everything between [] */
  292: 			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
  293: 				;
  294: 			if (*pm == EOS) {
  295: 				/*
  296: 				 * We could not find a matching RBRACKET.
  297: 				 * Ignore and just look for RBRACE
  298: 				 */
  299: 				pm = pl;
  300: 			}
  301: 			break;
  302: 
  303: 		case LBRACE:
  304: 			i++;
  305: 			break;
  306: 
  307: 		case RBRACE:
  308: 			if (i) {
  309: 				i--;
  310: 				break;
  311: 			}
  312: 			/* FALLTHROUGH */
  313: 		case COMMA:
  314: 			if (i && *pm == COMMA)
  315: 				break;
  316: 			else {
  317: 				/* Append the current string */
  318: 				for (lm = ls; (pl < pm); *lm++ = *pl++)
  319: 					;
  320: 
  321: 				/*
  322: 				 * Append the rest of the pattern after the
  323: 				 * closing brace
  324: 				 */
  325: 				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
  326: 					;
  327: 
  328: 				/* Expand the current pattern */
  329: #ifdef DEBUG
  330: 				qprintf("globexp2:", patbuf);
  331: #endif
  332: 				*rv = globexp1(patbuf, pglob);
  333: 
  334: 				/* move after the comma, to the next string */
  335: 				pl = pm + 1;
  336: 			}
  337: 			break;
  338: 
  339: 		default:
  340: 			break;
  341: 		}
  342: 	}
  343: 	*rv = 0;
  344: 	return 0;
  345: }
  346: 
  347: 
  348: 
  349: /*
  350:  * expand tilde from the passwd file.
  351:  */
  352: static const Char *
  353: globtilde(pattern, patbuf, patbuf_len, pglob)
  354: 	const Char *pattern;
  355: 	Char *patbuf;
  356: 	size_t patbuf_len;
  357: 	glob_t *pglob;
  358: {
  359: #ifndef PHP_WIN32
  360: 	struct passwd *pwd;
  361: #endif
  362: 	char *h;
  363: 	const Char *p;
  364: 	Char *b, *eb;
  365: 
  366: 	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
  367: 		return pattern;
  368: 
  369: 	/* Copy up to the end of the string or / */
  370: 	eb = &patbuf[patbuf_len - 1];
  371: 	for (p = pattern + 1, h = (char *) patbuf;
  372: 		h < (char *)eb && *p && *p != SLASH; *h++ = (char) *p++)
  373: 		;
  374: 
  375: 	*h = EOS;
  376: 
  377: #if 0
  378: 	if (h == (char *)eb)
  379: 		return what;
  380: #endif
  381: 
  382: 	if (((char *) patbuf)[0] == EOS) {
  383: 		/*
  384: 		 * handle a plain ~ or ~/ by expanding $HOME
  385: 		 * first and then trying the password file
  386: 		 */
  387: 		if ((h = getenv("HOME")) == NULL) {
  388: #ifndef PHP_WIN32
  389: 			if ((pwd = getpwuid(getuid())) == NULL)
  390: 				return pattern;
  391: 			else
  392: 				h = pwd->pw_dir;
  393: #else
  394: 			return pattern;
  395: #endif
  396: 		}
  397: 	} else {
  398: 		/*
  399: 		 * Expand a ~user
  400: 		 */
  401: #ifndef PHP_WIN32
  402: 		if ((pwd = getpwnam((char*) patbuf)) == NULL)
  403: 			return pattern;
  404: 		else
  405: 			h = pwd->pw_dir;
  406: #else
  407: 		return pattern;
  408: #endif
  409: 	}
  410: 
  411: 	/* Copy the home directory */
  412: 	for (b = patbuf; b < eb && *h; *b++ = *h++)
  413: 		;
  414: 
  415: 	/* Append the rest of the pattern */
  416: 	while (b < eb && (*b++ = *p++) != EOS)
  417: 		;
  418: 	*b = EOS;
  419: 
  420: 	return patbuf;
  421: }
  422: 
  423: 
  424: /*
  425:  * The main glob() routine: compiles the pattern (optionally processing
  426:  * quotes), calls glob1() to do the real pattern matching, and finally
  427:  * sorts the list (unless unsorted operation is requested).  Returns 0
  428:  * if things went well, nonzero if errors occurred.  It is not an error
  429:  * to find no matches.
  430:  */
  431: static int
  432: glob0(pattern, pglob)
  433: 	const Char *pattern;
  434: 	glob_t *pglob;
  435: {
  436: 	const Char *qpatnext;
  437: 	int c, err, oldpathc;
  438: 	Char *bufnext, patbuf[MAXPATHLEN];
  439: 	size_t limit = 0;
  440: 
  441: 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
  442: 	oldpathc = pglob->gl_pathc;
  443: 	bufnext = patbuf;
  444: 
  445: 	/* We don't need to check for buffer overflow any more. */
  446: 	while ((c = *qpatnext++) != EOS) {
  447: 		switch (c) {
  448: 		case LBRACKET:
  449: 			c = *qpatnext;
  450: 			if (c == NOT)
  451: 				++qpatnext;
  452: 			if (*qpatnext == EOS ||
  453: 				g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
  454: 				*bufnext++ = LBRACKET;
  455: 				if (c == NOT)
  456: 					--qpatnext;
  457: 				break;
  458: 			}
  459: 			*bufnext++ = M_SET;
  460: 			if (c == NOT)
  461: 				*bufnext++ = M_NOT;
  462: 			c = *qpatnext++;
  463: 			do {
  464: 				*bufnext++ = CHAR(c);
  465: 				if (*qpatnext == RANGE &&
  466: 					(c = qpatnext[1]) != RBRACKET) {
  467: 					*bufnext++ = M_RNG;
  468: 					*bufnext++ = CHAR(c);
  469: 					qpatnext += 2;
  470: 				}
  471: 			} while ((c = *qpatnext++) != RBRACKET);
  472: 			pglob->gl_flags |= GLOB_MAGCHAR;
  473: 			*bufnext++ = M_END;
  474: 			break;
  475: 		case QUESTION:
  476: 			pglob->gl_flags |= GLOB_MAGCHAR;
  477: 			*bufnext++ = M_ONE;
  478: 			break;
  479: 		case STAR:
  480: 			pglob->gl_flags |= GLOB_MAGCHAR;
  481: 			/* collapse adjacent stars to one,
  482: 			 * to avoid exponential behavior
  483: 			 */
  484: 			if (bufnext == patbuf || bufnext[-1] != M_ALL)
  485: 				*bufnext++ = M_ALL;
  486: 			break;
  487: 		default:
  488: 			*bufnext++ = CHAR(c);
  489: 			break;
  490: 		}
  491: 	}
  492: 	*bufnext = EOS;
  493: #ifdef DEBUG
  494: 	qprintf("glob0:", patbuf);
  495: #endif
  496: 
  497: 	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
  498: 		return(err);
  499: 
  500: 	/*
  501: 	 * If there was no match we are going to append the pattern
  502: 	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
  503: 	 * and the pattern did not contain any magic characters
  504: 	 * GLOB_NOMAGIC is there just for compatibility with csh.
  505: 	 */
  506: 	if (pglob->gl_pathc == oldpathc) {
  507: 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
  508: 			((pglob->gl_flags & GLOB_NOMAGIC) &&
  509: 			!(pglob->gl_flags & GLOB_MAGCHAR)))
  510: 			return(globextend(pattern, pglob, &limit));
  511: 		else
  512: 			return(GLOB_NOMATCH);
  513: 	}
  514: 	if (!(pglob->gl_flags & GLOB_NOSORT))
  515: 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
  516: 			pglob->gl_pathc - oldpathc, sizeof(char *), compare);
  517: 	return(0);
  518: }
  519: 
  520: static int
  521: compare(const void *p, const void *q)
  522: {
  523: 	return(strcmp(*(char **)p, *(char **)q));
  524: }
  525: 
  526: static int
  527: glob1(pattern, pattern_last, pglob, limitp)
  528: 	Char *pattern, *pattern_last;
  529: 	glob_t *pglob;
  530: 	size_t *limitp;
  531: {
  532: 	Char pathbuf[MAXPATHLEN];
  533: 
  534: 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
  535: 	if (*pattern == EOS)
  536: 		return(0);
  537: 	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
  538: 		pathbuf, pathbuf+MAXPATHLEN-1,
  539: 		pattern, pattern_last, pglob, limitp));
  540: }
  541: 
  542: /*
  543:  * The functions glob2 and glob3 are mutually recursive; there is one level
  544:  * of recursion for each segment in the pattern that contains one or more
  545:  * meta characters.
  546:  */
  547: static int
  548: glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
  549: 		pattern_last, pglob, limitp)
  550: 	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
  551: 	Char *pattern, *pattern_last;
  552: 	glob_t *pglob;
  553: 	size_t *limitp;
  554: {
  555: 	struct stat sb;
  556: 	Char *p, *q;
  557: 	int anymeta;
  558: 
  559: 	/*
  560: 	 * Loop over pattern segments until end of pattern or until
  561: 	 * segment with meta character found.
  562: 	 */
  563: 	for (anymeta = 0;;) {
  564: 		if (*pattern == EOS) {		/* End of pattern? */
  565: 			*pathend = EOS;
  566: 			if (g_lstat(pathbuf, &sb, pglob))
  567: 				return(0);
  568: 
  569: 			if (((pglob->gl_flags & GLOB_MARK) &&
  570: 				!IS_SLASH(pathend[-1])) && (S_ISDIR(sb.st_mode) ||
  571: 				(S_ISLNK(sb.st_mode) &&
  572: 				(g_stat(pathbuf, &sb, pglob) == 0) &&
  573: 				S_ISDIR(sb.st_mode)))) {
  574: 				if (pathend+1 > pathend_last)
  575: 					return (1);
  576: 				*pathend++ = SEP;
  577: 				*pathend = EOS;
  578: 			}
  579: 			++pglob->gl_matchc;
  580: 			return(globextend(pathbuf, pglob, limitp));
  581: 		}
  582: 
  583: 		/* Find end of next segment, copy tentatively to pathend. */
  584: 		q = pathend;
  585: 		p = pattern;
  586: 		while (*p != EOS && !IS_SLASH(*p)) {
  587: 			if (ismeta(*p))
  588: 				anymeta = 1;
  589: 			if (q+1 > pathend_last)
  590: 				return (1);
  591: 			*q++ = *p++;
  592: 		}
  593: 
  594: 		if (!anymeta) {		/* No expansion, do next segment. */
  595: 			pathend = q;
  596: 			pattern = p;
  597: 			while (IS_SLASH(*pattern)) {
  598: 				if (pathend+1 > pathend_last)
  599: 					return (1);
  600: 				*pathend++ = *pattern++;
  601: 			}
  602: 		} else
  603: 			/* Need expansion, recurse. */
  604: 			return(glob3(pathbuf, pathbuf_last, pathend,
  605: 				pathend_last, pattern, pattern_last,
  606: 				p, pattern_last, pglob, limitp));
  607: 	}
  608: 	/* NOTREACHED */
  609: }
  610: 
  611: static int
  612: glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
  613: 	restpattern, restpattern_last, pglob, limitp)
  614: 	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
  615: 	Char *pattern, *pattern_last, *restpattern, *restpattern_last;
  616: 	glob_t *pglob;
  617: 	size_t *limitp;
  618: {
  619: 	register struct dirent *dp;
  620: 	DIR *dirp;
  621: 	int err;
  622: 	char buf[MAXPATHLEN];
  623: 
  624: 	/*
  625: 	 * The readdirfunc declaration can't be prototyped, because it is
  626: 	 * assigned, below, to two functions which are prototyped in glob.h
  627: 	 * and dirent.h as taking pointers to differently typed opaque
  628: 	 * structures.
  629: 	 */
  630: 	struct dirent *(*readdirfunc)();
  631: 
  632: 	if (pathend > pathend_last)
  633: 		return (1);
  634: 	*pathend = EOS;
  635: 	errno = 0;
  636: 
  637: 	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
  638: 		/* TODO: don't call for ENOENT or ENOTDIR? */
  639: 		if (pglob->gl_errfunc) {
  640: 			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
  641: 				return(GLOB_ABORTED);
  642: 			if (pglob->gl_errfunc(buf, errno) ||
  643: 				pglob->gl_flags & GLOB_ERR)
  644: 				return(GLOB_ABORTED);
  645: 		}
  646: 		return(0);
  647: 	}
  648: 
  649: 	err = 0;
  650: 
  651: 	/* Search directory for matching names. */
  652: 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  653: 		readdirfunc = pglob->gl_readdir;
  654: 	else
  655: 		readdirfunc = readdir;
  656: 	while ((dp = (*readdirfunc)(dirp))) {
  657: 		register u_char *sc;
  658: 		register Char *dc;
  659: 
  660: 		/* Initial DOT must be matched literally. */
  661: 		if (dp->d_name[0] == DOT && *pattern != DOT)
  662: 			continue;
  663: 		dc = pathend;
  664: 		sc = (u_char *) dp->d_name;
  665: 		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
  666: 			;
  667: 		if (dc >= pathend_last) {
  668: 			*dc = EOS;
  669: 			err = 1;
  670: 			break;
  671: 		}
  672: 
  673: 		if (!match(pathend, pattern, restpattern)) {
  674: 			*pathend = EOS;
  675: 			continue;
  676: 		}
  677: 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
  678: 			restpattern, restpattern_last, pglob, limitp);
  679: 		if (err)
  680: 			break;
  681: 	}
  682: 
  683: 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  684: 		(*pglob->gl_closedir)(dirp);
  685: 	else
  686: 		closedir(dirp);
  687: 	return(err);
  688: }
  689: 
  690: 
  691: /*
  692:  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
  693:  * add the new item, and update gl_pathc.
  694:  *
  695:  * This assumes the BSD realloc, which only copies the block when its size
  696:  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  697:  * behavior.
  698:  *
  699:  * Return 0 if new item added, error code if memory couldn't be allocated.
  700:  *
  701:  * Invariant of the glob_t structure:
  702:  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  703:  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  704:  */
  705: static int
  706: globextend(path, pglob, limitp)
  707: 	const Char *path;
  708: 	glob_t *pglob;
  709: 	size_t *limitp;
  710: {
  711: 	register char **pathv;
  712: 	register int i;
  713: 	u_int newsize, len;
  714: 	char *copy;
  715: 	const Char *p;
  716: 
  717: 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  718: 	pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
  719: 		malloc(newsize);
  720: 	if (pathv == NULL) {
  721: 		if (pglob->gl_pathv) {
  722: 			free(pglob->gl_pathv);
  723: 			pglob->gl_pathv = NULL;
  724: 		}
  725: 		return(GLOB_NOSPACE);
  726: 	}
  727: 
  728: 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  729: 		/* first time around -- clear initial gl_offs items */
  730: 		pathv += pglob->gl_offs;
  731: 		for (i = pglob->gl_offs; --i >= 0; )
  732: 			*--pathv = NULL;
  733: 	}
  734: 	pglob->gl_pathv = pathv;
  735: 
  736: 	for (p = path; *p++;)
  737: 		;
  738: 	len = (size_t)(p - path);
  739: 	*limitp += len;
  740: 	if ((copy = malloc(len)) != NULL) {
  741: 		if (g_Ctoc(path, copy, len)) {
  742: 			free(copy);
  743: 			return(GLOB_NOSPACE);
  744: 		}
  745: 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  746: 	}
  747: 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  748: 
  749: 	if ((pglob->gl_flags & GLOB_LIMIT) &&
  750: 		newsize + *limitp >= ARG_MAX) {
  751: 		errno = 0;
  752: 		return(GLOB_NOSPACE);
  753: 	}
  754: 
  755: 	return(copy == NULL ? GLOB_NOSPACE : 0);
  756: }
  757: 
  758: 
  759: /*
  760:  * pattern matching function for filenames.  Each occurrence of the *
  761:  * pattern causes a recursion level.
  762:  */
  763: static int
  764: match(name, pat, patend)
  765: 	register Char *name, *pat, *patend;
  766: {
  767: 	int ok, negate_range;
  768: 	Char c, k;
  769: 
  770: 	while (pat < patend) {
  771: 		c = *pat++;
  772: 		switch (c & M_MASK) {
  773: 		case M_ALL:
  774: 			if (pat == patend)
  775: 				return(1);
  776: 			do
  777: 				if (match(name, pat, patend))
  778: 					return(1);
  779: 			while (*name++ != EOS)
  780: 				;
  781: 			return(0);
  782: 		case M_ONE:
  783: 			if (*name++ == EOS)
  784: 				return(0);
  785: 			break;
  786: 		case M_SET:
  787: 			ok = 0;
  788: 			if ((k = *name++) == EOS)
  789: 				return(0);
  790: 			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
  791: 				++pat;
  792: 			while (((c = *pat++) & M_MASK) != M_END)
  793: 				if ((*pat & M_MASK) == M_RNG) {
  794: 					if (c <= k && k <= pat[1])
  795: 						ok = 1;
  796: 					pat += 2;
  797: 				} else if (c == k)
  798: 					ok = 1;
  799: 			if (ok == negate_range)
  800: 				return(0);
  801: 			break;
  802: 		default:
  803: 			if (*name++ != c)
  804: 				return(0);
  805: 			break;
  806: 		}
  807: 	}
  808: 	return(*name == EOS);
  809: }
  810: 
  811: /* Free allocated data belonging to a glob_t structure. */
  812: PHPAPI void
  813: globfree(pglob)
  814: 	glob_t *pglob;
  815: {
  816: 	register int i;
  817: 	register char **pp;
  818: 
  819: 	if (pglob->gl_pathv != NULL) {
  820: 		pp = pglob->gl_pathv + pglob->gl_offs;
  821: 		for (i = pglob->gl_pathc; i--; ++pp)
  822: 			if (*pp)
  823: 				free(*pp);
  824: 		free(pglob->gl_pathv);
  825: 		pglob->gl_pathv = NULL;
  826: 	}
  827: }
  828: 
  829: static DIR *
  830: g_opendir(str, pglob)
  831: 	register Char *str;
  832: 	glob_t *pglob;
  833: {
  834: 	char buf[MAXPATHLEN];
  835: 
  836: 	if (!*str)
  837: 		strlcpy(buf, ".", sizeof buf);
  838: 	else {
  839: 		if (g_Ctoc(str, buf, sizeof(buf)))
  840: 			return(NULL);
  841: 	}
  842: 
  843: 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  844: 		return((*pglob->gl_opendir)(buf));
  845: 
  846: 	return(opendir(buf));
  847: }
  848: 
  849: static int
  850: g_lstat(fn, sb, pglob)
  851: 	register Char *fn;
  852: 	struct stat *sb;
  853: 	glob_t *pglob;
  854: {
  855: 	char buf[MAXPATHLEN];
  856: 
  857: 	if (g_Ctoc(fn, buf, sizeof(buf)))
  858: 		return(-1);
  859: 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  860: 		return((*pglob->gl_lstat)(buf, sb));
  861: 	return(php_sys_lstat(buf, sb));
  862: }
  863: 
  864: static int
  865: g_stat(fn, sb, pglob)
  866: 	register Char *fn;
  867: 	struct stat *sb;
  868: 	glob_t *pglob;
  869: {
  870: 	char buf[MAXPATHLEN];
  871: 
  872: 	if (g_Ctoc(fn, buf, sizeof(buf)))
  873: 		return(-1);
  874: 	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
  875: 		return((*pglob->gl_stat)(buf, sb));
  876: 	return(php_sys_stat(buf, sb));
  877: }
  878: 
  879: static Char *
  880: g_strchr(str, ch)
  881: 	Char *str;
  882: 	int ch;
  883: {
  884: 	do {
  885: 		if (*str == ch)
  886: 			return (str);
  887: 	} while (*str++);
  888: 	return (NULL);
  889: }
  890: 
  891: static int
  892: g_Ctoc(str, buf, len)
  893: 	register const Char *str;
  894: 	char *buf;
  895: 	u_int len;
  896: {
  897: 
  898: 	while (len--) {
  899: 		if ((*buf++ = (char) *str++) == EOS)
  900: 			return (0);
  901: 	}
  902: 	return (1);
  903: }
  904: 
  905: #ifdef DEBUG
  906: static void
  907: qprintf(str, s)
  908: 	const char *str;
  909: 	register Char *s;
  910: {
  911: 	register Char *p;
  912: 
  913: 	(void)printf("%s:\n", str);
  914: 	for (p = s; *p; p++)
  915: 		(void)printf("%c", CHAR(*p));
  916: 	(void)printf("\n");
  917: 	for (p = s; *p; p++)
  918: 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
  919: 	(void)printf("\n");
  920: 	for (p = s; *p; p++)
  921: 		(void)printf("%c", ismeta(*p) ? '_' : ' ');
  922: 	(void)printf("\n");
  923: }
  924: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>