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