1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericopenlibs/openenvcore/libc/src/glob.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1092 @@
1.4 +// glob.c
1.5 +
1.6 +
1.7 +/*
1.8 + * Copyright (c) 1989, 1993
1.9 + * The Regents of the University of California. All rights reserved.
1.10 + *
1.11 + * This code is derived from software contributed to Berkeley by
1.12 + * Guido van Rossum.
1.13 + *
1.14 + * Redistribution and use in source and binary forms, with or without
1.15 + * modification, are permitted provided that the following conditions
1.16 + * are met:
1.17 + * 1. Redistributions of source code must retain the above copyright
1.18 + * notice, this list of conditions and the following disclaimer.
1.19 + * 2. Redistributions in binary form must reproduce the above copyright
1.20 + * notice, this list of conditions and the following disclaimer in the
1.21 + * documentation and/or other materials provided with the distribution.
1.22 + * 4. Neither the name of the University nor the names of its contributors
1.23 + * may be used to endorse or promote products derived from this software
1.24 + * without specific prior written permission.
1.25 + *
1.26 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1.27 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1.28 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1.29 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1.30 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1.31 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1.32 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1.33 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1.34 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1.35 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1.36 + * SUCH DAMAGE.
1.37 + */
1.38 +
1.39 +/* Portions Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).All rights reserved. */
1.40 +
1.41 +#if defined(LIBC_SCCS) && !defined(lint)
1.42 +static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
1.43 +#endif /* LIBC_SCCS and not lint */
1.44 +#include <sys/cdefs.h>
1.45 +__FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.23 2005/09/14 19:14:32 ache Exp $");
1.46 +
1.47 +
1.48 +/*
1.49 + * glob(3) -- a superset of the one defined in POSIX 1003.2.
1.50 + *
1.51 + * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
1.52 + *
1.53 + * Optional extra services, controlled by flags not defined by POSIX:
1.54 + *
1.55 + * GLOB_QUOTE:
1.56 + * Escaping convention: \ inhibits any special meaning the following
1.57 + * character might have (except \ at end of string is retained).
1.58 + * GLOB_MAGCHAR:
1.59 + * Set in gl_flags if pattern contained a globbing character.
1.60 + * GLOB_NOMAGIC:
1.61 + * Same as GLOB_NOCHECK, but it will only append pattern if it did
1.62 + * not contain any magic characters. [Used in csh style globbing]
1.63 + * GLOB_ALTDIRFUNC:
1.64 + * Use alternately specified directory access functions.
1.65 + * GLOB_TILDE:
1.66 + * expand ~user/foo to the /home/dir/of/user/foo
1.67 + * GLOB_BRACE:
1.68 + * expand {1,2}{a,b} to 1a 1b 2a 2b
1.69 + * gl_matchc:
1.70 + * Number of matches in the current invocation of glob.
1.71 + */
1.72 +
1.73 +/*
1.74 + * Some notes on multibyte character support:
1.75 + * 1. Patterns with illegal byte sequences match nothing - even if
1.76 + * GLOB_NOCHECK is specified.
1.77 + * 2. Illegal byte sequences in filenames are handled by treating them as
1.78 + * single-byte characters with a value of the first byte of the sequence
1.79 + * cast to wchar_t.
1.80 + * 3. State-dependent encodings are not currently supported.
1.81 + */
1.82 +
1.83 +#include <sys/param.h>
1.84 +#include <sys/stat.h>
1.85 +
1.86 +#include <ctype.h>
1.87 +#include <dirent.h>
1.88 +#include <errno.h>
1.89 +#include <glob.h>
1.90 +#include <limits.h>
1.91 +#include <pwd.h>
1.92 +#include <stdint.h>
1.93 +#include <stdio.h>
1.94 +#include <stdlib.h>
1.95 +#include <string.h>
1.96 +#include <unistd.h>
1.97 +#include <wchar.h>
1.98 +
1.99 +#include "libc_collate.h"
1.100 +
1.101 +
1.102 +#if (defined(__SYMBIAN32__) && (defined(__WINSCW__) || defined(__WINS__)))
1.103 +
1.104 +#include "libc_wsd_defs.h"
1.105 +#include "reent.h"
1.106 +
1.107 +#endif //defined(__SYMBIAN32__) && (defined(__WINSCW__) || defined(__WINS__))
1.108 +
1.109 +#ifdef __cplusplus
1.110 +extern "C" {
1.111 +#endif
1.112 +#ifdef __SYMBIAN32__
1.113 +extern char LC_COLLATE_LocaleName[30];
1.114 +#ifdef EMULATOR
1.115 +char *GET_WSD_VAR_NAME(LC_COLLATE_LocaleName, g)();
1.116 +#define LC_COLLATE_LocaleName (GET_WSD_VAR_NAME(LC_COLLATE_LocaleName, g)())
1.117 +#endif //EMULATOR
1.118 +
1.119 +//Declared and defined from libc_collate.h and vfscanf.c
1.120 +extern int __collate_range_cmp(int , int );
1.121 +#endif //__SYMBIAN32__
1.122 +
1.123 +
1.124 +
1.125 +#define DOLLAR '$'
1.126 +#define DOT '.'
1.127 +#define EOS '\0'
1.128 +#define LBRACKET '['
1.129 +#define NOT '!'
1.130 +#define QUESTION '?'
1.131 +#define QUOTE '\\'
1.132 +#define RANGE '-'
1.133 +#define RBRACKET ']'
1.134 +
1.135 +// For Symbian Environment the path is specified using the '\'
1.136 +// unlike in the Linux where the path seprator '/' is used.
1.137 +// Since '\\' as path seprator is used the escaping flag
1.138 +// 'QUOTE' cannot be used here.
1.139 +// For e.g. ..\\test\\hollows\\*
1.140 +
1.141 +#ifdef __SYMBIAN32__
1.142 + #define SEP '\\'
1.143 +#else
1.144 + #define SEP '/'
1.145 +#endif //__SYMBIAN32__
1.146 +
1.147 +
1.148 +#define STAR '*'
1.149 +#define TILDE '~'
1.150 +#define UNDERSCORE '_'
1.151 +#define LBRACE '{'
1.152 +#define RBRACE '}'
1.153 +#define SLASH '/'
1.154 +#define COMMA ','
1.155 +
1.156 +
1.157 +#ifndef __SYMBIAN32__
1.158 +
1.159 +#ifndef DEBUG
1.160 +
1.161 +#define M_QUOTE 0x8000000000ULL
1.162 +#define M_PROTECT 0x4000000000ULL
1.163 +#define M_MASK 0xffffffffffULL
1.164 +#define M_CHAR 0x00ffffffffULL
1.165 +
1.166 +typedef uint_fast64_t Char;
1.167 +
1.168 +#else //DEBUG
1.169 +
1.170 +#define M_QUOTE 0x80
1.171 +#define M_PROTECT 0x40
1.172 +#define M_MASK 0xff
1.173 +#define M_CHAR 0x7f
1.174 +
1.175 +typedef char Char;
1.176 +
1.177 +#endif //DEBUG
1.178 +
1.179 +#else //__SYMBIAN32__
1.180 +
1.181 +#define M_QUOTE 0x80
1.182 +#define M_PROTECT 0x40
1.183 +#define M_MASK 0xff
1.184 +#define M_CHAR 0x7f
1.185 +
1.186 +typedef unsigned char Char;
1.187 +
1.188 +#endif //__SYMBIAN32__
1.189 +
1.190 +#define CHAR(c) ((Char)((c)&M_CHAR))
1.191 +#define META(c) ((Char)((c)|M_QUOTE))
1.192 +#define M_ALL META('*')
1.193 +#define M_END META(']')
1.194 +#define M_NOT META('!')
1.195 +#define M_ONE META('?')
1.196 +#define M_RNG META('-')
1.197 +#define M_SET META('[')
1.198 +#define ismeta(c) (((c)&M_QUOTE) != 0)
1.199 +
1.200 +
1.201 +static int compare(const void *, const void *);
1.202 +static int g_Ctoc(const Char *, char *, u_int);
1.203 +static int g_lstat(Char *, struct stat *, glob_t *);
1.204 +static DIR *g_opendir(Char *, glob_t *);
1.205 +static Char *g_strchr(Char *, wchar_t);
1.206 +#ifdef notdef
1.207 +static Char *g_strcat(Char *, const Char *);
1.208 +#endif
1.209 +static int g_stat(Char *, struct stat *, glob_t *);
1.210 +static int glob0(const Char *, glob_t *, int *);
1.211 +static int glob1(Char *, glob_t *, int *);
1.212 +static int glob2(Char *, Char *, Char *, Char *, glob_t *, int *);
1.213 +static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *);
1.214 +static int globextend(const Char *, glob_t *, int *);
1.215 +static const Char *
1.216 + globtilde(const Char *, Char *, size_t, glob_t *);
1.217 +static int globexp1(const Char *, glob_t *, int *);
1.218 +static int globexp2(const Char *, const Char *, glob_t *, int *, int *);
1.219 +static int match(Char *, Char *, Char *);
1.220 +#ifdef DEBUG
1.221 +static void qprintf(const char *, Char *);
1.222 +#endif
1.223 +
1.224 +// EXTERNAL FUNCTION PROTOTYPES
1.225 +
1.226 +
1.227 +//--------------------------------------------------------------------------------------------
1.228 +//Function Name : int glob(glob(const char *, int flags, int (*)(const char *, int), glob_t *)
1.229 +//Description : It takes pattern to be searched, flags and the structure of the type glob_t.
1.230 +// It can optionally also take If errfunc is not NULL, it will be called in
1.231 +// error with the arguments epath, a pointer to the case of an path which
1.232 +// failed
1.233 +//
1.234 +//Return Value : If successful returns the pathnames of the searched pattern contained
1.235 +// in the glob_t structure member reference pointer gl_pathv. In case
1.236 +// failure, gl_pathv is NULL.
1.237 +//----------------------------------------------------------------------------------------------
1.238 +
1.239 +EXPORT_C int
1.240 +glob(pattern, flags, errfunc, pglob)
1.241 + const char *pattern;
1.242 + int flags, (*errfunc)(const char *, int);
1.243 + glob_t *pglob;
1.244 +{
1.245 + const u_char *patnext;
1.246 + int limit;
1.247 + Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
1.248 + mbstate_t mbs;
1.249 + wchar_t wc;
1.250 + size_t clen;
1.251 +
1.252 + patnext = (u_char *) pattern;
1.253 +
1.254 + // Since we are using '\\' as path seprator, this flag needs to be mentioned
1.255 + // by default in Symbian. Instead this can be hardcoded here.
1.256 +
1.257 + #ifdef __SYMBIAN32__
1.258 + flags = flags | GLOB_NOESCAPE;
1.259 + #endif
1.260 +
1.261 + if (!(flags & GLOB_APPEND)) {
1.262 + pglob->gl_pathc = 0;
1.263 + pglob->gl_pathv = NULL;
1.264 + if (!(flags & GLOB_DOOFFS))
1.265 + pglob->gl_offs = 0;
1.266 + }
1.267 + if (flags & GLOB_LIMIT) {
1.268 + limit = pglob->gl_matchc;
1.269 + if (limit == 0)
1.270 + limit = ARG_MAX;
1.271 + } else
1.272 + limit = 0;
1.273 + pglob->gl_flags = flags & ~GLOB_MAGCHAR;
1.274 + pglob->gl_errfunc = errfunc;
1.275 + pglob->gl_matchc = 0;
1.276 +
1.277 + bufnext = patbuf;
1.278 + bufend = bufnext + MAXPATHLEN - 1;
1.279 + if (flags & GLOB_NOESCAPE) {
1.280 + memset(&mbs, 0, sizeof(mbs));
1.281 + while (bufend - bufnext >= MB_CUR_MAX) {
1.282 + clen = mbrtowc(&wc,(char*)patnext, MB_LEN_MAX, &mbs);
1.283 + if (clen == (size_t)-1 || clen == (size_t)-2)
1.284 + return (GLOB_NOMATCH);
1.285 + else if (clen == 0)
1.286 + break;
1.287 + *bufnext++ = wc;
1.288 + patnext += clen;
1.289 + }
1.290 + } else {
1.291 + /* Protect the quoted characters. */
1.292 + memset(&mbs, 0, sizeof(mbs));
1.293 + while (bufend - bufnext >= MB_CUR_MAX) {
1.294 + if (*patnext == QUOTE) {
1.295 + if (*++patnext == EOS) {
1.296 + *bufnext++ = QUOTE | M_PROTECT;
1.297 + continue;
1.298 + }
1.299 + prot = M_PROTECT;
1.300 + } else
1.301 + prot = 0;
1.302 + clen = mbrtowc(&wc, (char*)patnext, MB_LEN_MAX, &mbs);
1.303 + if (clen == (size_t)-1 || clen == (size_t)-2)
1.304 + return (GLOB_NOMATCH);
1.305 + else if (clen == 0)
1.306 + break;
1.307 + *bufnext++ = wc | prot;
1.308 + patnext += clen;
1.309 + }
1.310 + }
1.311 + *bufnext = EOS;
1.312 +
1.313 + if (flags & GLOB_BRACE)
1.314 + return globexp1(patbuf, pglob, &limit);
1.315 + else
1.316 + return glob0(patbuf, pglob, &limit);
1.317 +}
1.318 +
1.319 +/*
1.320 + * Expand recursively a glob {} pattern. When there is no more expansion
1.321 + * invoke the standard globbing routine to glob the rest of the magic
1.322 + * characters
1.323 + */
1.324 +static int
1.325 +globexp1(pattern, pglob, limit)
1.326 + const Char *pattern;
1.327 + glob_t *pglob;
1.328 + int *limit;
1.329 +{
1.330 + const Char* ptr = pattern;
1.331 + int rv;
1.332 +
1.333 + /* Protect a single {}, for find(1), like csh */
1.334 + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
1.335 + return glob0(pattern, pglob, limit);
1.336 +
1.337 + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
1.338 + if (!globexp2(ptr, pattern, pglob, &rv, limit))
1.339 + return rv;
1.340 +
1.341 + return glob0(pattern, pglob, limit);
1.342 +}
1.343 +
1.344 +
1.345 +/*
1.346 + * Recursive brace globbing helper. Tries to expand a single brace.
1.347 + * If it succeeds then it invokes globexp1 with the new pattern.
1.348 + * If it fails then it tries to glob the rest of the pattern and returns.
1.349 + */
1.350 +static int
1.351 +globexp2(ptr, pattern, pglob, rv, limit)
1.352 + const Char *ptr, *pattern;
1.353 + glob_t *pglob;
1.354 + int *rv, *limit;
1.355 +{
1.356 + int i;
1.357 + Char *lm, *ls;
1.358 + const Char *pe, *pm, *pm1, *pl;
1.359 + Char patbuf[MAXPATHLEN];
1.360 +
1.361 + /* copy part up to the brace */
1.362 + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
1.363 + continue;
1.364 + *lm = EOS;
1.365 + ls = lm;
1.366 +
1.367 + /* Find the balanced brace */
1.368 + for (i = 0, pe = ++ptr; *pe; pe++)
1.369 + if (*pe == LBRACKET) {
1.370 + /* Ignore everything between [] */
1.371 + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
1.372 + continue;
1.373 + if (*pe == EOS) {
1.374 + /*
1.375 + * We could not find a matching RBRACKET.
1.376 + * Ignore and just look for RBRACE
1.377 + */
1.378 + pe = pm;
1.379 + }
1.380 + }
1.381 + else if (*pe == LBRACE)
1.382 + i++;
1.383 + else if (*pe == RBRACE) {
1.384 + if (i == 0)
1.385 + break;
1.386 + i--;
1.387 + }
1.388 +
1.389 + /* Non matching braces; just glob the pattern */
1.390 + if (i != 0 || *pe == EOS) {
1.391 + *rv = glob0(patbuf, pglob, limit);
1.392 + return 0;
1.393 + }
1.394 +
1.395 + for (i = 0, pl = pm = ptr; pm <= pe; pm++)
1.396 + switch (*pm) {
1.397 + case LBRACKET:
1.398 + /* Ignore everything between [] */
1.399 + for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
1.400 + continue;
1.401 + if (*pm == EOS) {
1.402 + /*
1.403 + * We could not find a matching RBRACKET.
1.404 + * Ignore and just look for RBRACE
1.405 + */
1.406 + pm = pm1;
1.407 + }
1.408 + break;
1.409 +
1.410 + case LBRACE:
1.411 + i++;
1.412 + break;
1.413 +
1.414 + case RBRACE:
1.415 + if (i) {
1.416 + i--;
1.417 + break;
1.418 + }
1.419 + /* FALLTHROUGH */
1.420 + case COMMA:
1.421 + if (i && *pm == COMMA)
1.422 + break;
1.423 + else {
1.424 + /* Append the current string */
1.425 + for (lm = ls; (pl < pm); *lm++ = *pl++)
1.426 + continue;
1.427 + /*
1.428 + * Append the rest of the pattern after the
1.429 + * closing brace
1.430 + */
1.431 + for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
1.432 + continue;
1.433 +
1.434 + /* Expand the current pattern */
1.435 +#ifdef DEBUG
1.436 + qprintf("globexp2:", patbuf);
1.437 +#endif
1.438 + *rv = globexp1(patbuf, pglob, limit);
1.439 +
1.440 + /* move after the comma, to the next string */
1.441 + pl = pm + 1;
1.442 + }
1.443 + break;
1.444 +
1.445 + default:
1.446 + break;
1.447 + }
1.448 + *rv = 0;
1.449 + return 0;
1.450 +}
1.451 +
1.452 +
1.453 +/*
1.454 + * expand tilde from the passwd file.
1.455 + */
1.456 +
1.457 +static const Char *
1.458 +globtilde(pattern, patbuf, patbuf_len, pglob)
1.459 + const Char *pattern;
1.460 + Char *patbuf;
1.461 + size_t patbuf_len;
1.462 + glob_t *pglob;
1.463 +{
1.464 +
1.465 +#ifndef __SYMBIAN32__
1.466 + struct passwd *pwd;
1.467 +#endif
1.468 +
1.469 + char *h;
1.470 + const Char *p;
1.471 + Char *b, *eb;
1.472 +
1.473 + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
1.474 + return pattern;
1.475 +
1.476 + /*
1.477 + * Copy up to the end of the string or /
1.478 + */
1.479 +
1.480 + eb = &patbuf[patbuf_len - 1];
1.481 +
1.482 +#ifdef __SYMBIAN32__
1.483 +
1.484 + for (p = pattern + 1, h = (char *) patbuf;
1.485 + h < (char *)eb && *p && *p != SEP ; *h++ = *p++)
1.486 + continue;
1.487 +
1.488 + *h = EOS;
1.489 +
1.490 + if (((char *) patbuf)[0] == EOS) {
1.491 + /*
1.492 + * handle a plain ~ or ~\\ by getting the
1.493 + * secure Id for this process. It shall
1.494 + * return the path as C:\\private\\<secureId>
1.495 + * on emulator and Z:\\private\\<secureId>
1.496 + * on hardware
1.497 + */
1.498 + if( NULL == getcwd(h, patbuf_len) )
1.499 + return pattern;
1.500 + }
1.501 +
1.502 + else{
1.503 + /*
1.504 + * Its ~<path>\\.. This will not be handled. Returns the
1.505 + * pattern as it is.
1.506 + */
1.507 + return pattern;
1.508 + }
1.509 +
1.510 +# else
1.511 +
1.512 + for (p = pattern + 1, h = (char *) patbuf;
1.513 + h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
1.514 + continue;
1.515 +
1.516 + *h = EOS;
1.517 +
1.518 + if (((char *) patbuf)[0] == EOS) {
1.519 + /*
1.520 + * handle a plain ~ or ~/ by expanding $HOME first (iff
1.521 + * we're not running setuid or setgid) and then trying
1.522 + * the password file
1.523 + */
1.524 + if (issetugid() != 0 ||
1.525 + (h = getenv("HOME")) == NULL) {
1.526 + if (((h = getlogin()) != NULL &&
1.527 + (pwd = getpwnam(h)) != NULL) ||
1.528 + (pwd = getpwuid(getuid())) != NULL)
1.529 + h = pwd->pw_dir;
1.530 + else
1.531 + return pattern;
1.532 + }
1.533 + }
1.534 + else {
1.535 + /*
1.536 + * Expand a ~user
1.537 + */
1.538 + if ((pwd = getpwnam((char*) patbuf)) == NULL)
1.539 + return pattern;
1.540 + else
1.541 + h = pwd->pw_dir;
1.542 + }
1.543 +
1.544 +#endif //__SYMBIAN32__
1.545 +
1.546 +
1.547 + /* Copy the home directory */
1.548 + for (b = patbuf; b < eb && *h; *b++ = *h++)
1.549 + continue;
1.550 +
1.551 + /* Append the rest of the pattern */
1.552 + while (b < eb && (*b++ = *p++) != EOS)
1.553 + continue;
1.554 + *b = EOS;
1.555 +
1.556 + return patbuf;
1.557 +}
1.558 +
1.559 +
1.560 +/*
1.561 + * The main glob() routine: compiles the pattern (optionally processing
1.562 + * quotes), calls glob1() to do the real pattern matching, and finally
1.563 + * sorts the list (unless unsorted operation is requested). Returns 0
1.564 + * if things went well, nonzero if errors occurred.
1.565 + */
1.566 +static int
1.567 +glob0(pattern, pglob, limit)
1.568 + const Char *pattern;
1.569 + glob_t *pglob;
1.570 + int *limit;
1.571 +{
1.572 + const Char *qpatnext;
1.573 + int c, err, oldpathc;
1.574 + Char *bufnext, patbuf[MAXPATHLEN];
1.575 +
1.576 + qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
1.577 + oldpathc = pglob->gl_pathc;
1.578 + bufnext = patbuf;
1.579 +
1.580 + /* We don't need to check for buffer overflow any more. */
1.581 + while ((c = *qpatnext++) != EOS) {
1.582 + switch (c) {
1.583 + case LBRACKET:
1.584 + c = *qpatnext;
1.585 + if (c == NOT)
1.586 + ++qpatnext;
1.587 + if (*qpatnext == EOS ||
1.588 + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
1.589 + *bufnext++ = LBRACKET;
1.590 + if (c == NOT)
1.591 + --qpatnext;
1.592 + break;
1.593 + }
1.594 + *bufnext++ = M_SET;
1.595 + if (c == NOT)
1.596 + *bufnext++ = M_NOT;
1.597 + c = *qpatnext++;
1.598 + do {
1.599 + *bufnext++ = CHAR(c);
1.600 + if (*qpatnext == RANGE &&
1.601 + (c = qpatnext[1]) != RBRACKET) {
1.602 + *bufnext++ = M_RNG;
1.603 + *bufnext++ = CHAR(c);
1.604 + qpatnext += 2;
1.605 + }
1.606 + } while ((c = *qpatnext++) != RBRACKET);
1.607 + pglob->gl_flags |= GLOB_MAGCHAR;
1.608 + *bufnext++ = M_END;
1.609 + break;
1.610 + case QUESTION:
1.611 + pglob->gl_flags |= GLOB_MAGCHAR;
1.612 + *bufnext++ = M_ONE;
1.613 + break;
1.614 + case STAR:
1.615 + pglob->gl_flags |= GLOB_MAGCHAR;
1.616 + /* collapse adjacent stars to one,
1.617 + * to avoid exponential behavior
1.618 + */
1.619 + if (bufnext == patbuf || bufnext[-1] != M_ALL)
1.620 + *bufnext++ = M_ALL;
1.621 + break;
1.622 + default:
1.623 + *bufnext++ = CHAR(c);
1.624 + break;
1.625 + }
1.626 + }
1.627 + *bufnext = EOS;
1.628 +#ifdef DEBUG
1.629 + qprintf("glob0:", patbuf);
1.630 +#endif
1.631 +
1.632 + if ((err = glob1(patbuf, pglob, limit)) != 0)
1.633 + return(err);
1.634 +
1.635 + /*
1.636 + * If there was no match we are going to append the pattern
1.637 + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
1.638 + * and the pattern did not contain any magic characters
1.639 + * GLOB_NOMAGIC is there just for compatibility with csh.
1.640 + */
1.641 + if (pglob->gl_pathc == oldpathc) {
1.642 + if (((pglob->gl_flags & GLOB_NOCHECK) ||
1.643 + ((pglob->gl_flags & GLOB_NOMAGIC) &&
1.644 + !(pglob->gl_flags & GLOB_MAGCHAR))))
1.645 + return(globextend(pattern, pglob, limit));
1.646 + else
1.647 + return(GLOB_NOMATCH);
1.648 + }
1.649 + if (!(pglob->gl_flags & GLOB_NOSORT))
1.650 + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
1.651 + pglob->gl_pathc - oldpathc, sizeof(char *), compare);
1.652 + return(0);
1.653 +}
1.654 +
1.655 +static int
1.656 +compare(p, q)
1.657 + const void *p, *q;
1.658 +{
1.659 + return(strcmp(*(char **)p, *(char **)q));
1.660 +}
1.661 +
1.662 +static int
1.663 +glob1(pattern, pglob, limit)
1.664 + Char *pattern;
1.665 + glob_t *pglob;
1.666 + int *limit;
1.667 +{
1.668 + Char pathbuf[MAXPATHLEN];
1.669 +
1.670 + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
1.671 + if (*pattern == EOS)
1.672 + return(0);
1.673 + return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
1.674 + pattern, pglob, limit));
1.675 +}
1.676 +
1.677 +/*
1.678 + * The functions glob2 and glob3 are mutually recursive; there is one level
1.679 + * of recursion for each segment in the pattern that contains one or more
1.680 + * meta characters.
1.681 + */
1.682 +static int
1.683 +glob2(pathbuf, pathend, pathend_last, pattern, pglob, limit)
1.684 + Char *pathbuf, *pathend, *pathend_last, *pattern;
1.685 + glob_t *pglob;
1.686 + int *limit;
1.687 +{
1.688 + struct stat sb;
1.689 + Char *p, *q;
1.690 + int anymeta;
1.691 +
1.692 + /*
1.693 + * Loop over pattern segments until end of pattern or until
1.694 + * segment with meta character found.
1.695 + */
1.696 + for (anymeta = 0;;) {
1.697 + if (*pattern == EOS) { /* End of pattern? */
1.698 + *pathend = EOS;
1.699 + if (g_lstat(pathbuf, &sb, pglob))
1.700 + return(0);
1.701 +
1.702 + if (((pglob->gl_flags & GLOB_MARK) &&
1.703 + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
1.704 + || (S_ISLNK(sb.st_mode) &&
1.705 + (g_stat(pathbuf, &sb, pglob) == 0) &&
1.706 + S_ISDIR(sb.st_mode)))) {
1.707 + if (pathend + 1 > pathend_last)
1.708 + return (GLOB_ABORTED);
1.709 + *pathend++ = SEP;
1.710 + *pathend = EOS;
1.711 + }
1.712 + ++pglob->gl_matchc;
1.713 + return(globextend(pathbuf, pglob, limit));
1.714 + }
1.715 +
1.716 + /* Find end of next segment, copy tentatively to pathend. */
1.717 + q = pathend;
1.718 + p = pattern;
1.719 + while (*p != EOS && *p != SEP) {
1.720 + if (ismeta(*p))
1.721 + anymeta = 1;
1.722 + if (q + 1 > pathend_last)
1.723 + return (GLOB_ABORTED);
1.724 + *q++ = *p++;
1.725 + }
1.726 +
1.727 + if (!anymeta) { /* No expansion, do next segment. */
1.728 + pathend = q;
1.729 + pattern = p;
1.730 + while (*pattern == SEP) {
1.731 + if (pathend + 1 > pathend_last)
1.732 + return (GLOB_ABORTED);
1.733 + *pathend++ = *pattern++;
1.734 + }
1.735 + } else /* Need expansion, recurse. */
1.736 + return(glob3(pathbuf, pathend, pathend_last, pattern, p,
1.737 + pglob, limit));
1.738 + }
1.739 + /* NOTREACHED */
1.740 +}
1.741 +
1.742 +static int
1.743 +glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
1.744 + Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern;
1.745 + glob_t *pglob;
1.746 + int *limit;
1.747 +{
1.748 + struct dirent *dp;
1.749 + DIR *dirp;
1.750 + int err;
1.751 + char buf[MAXPATHLEN];
1.752 +
1.753 + /*
1.754 + * The readdirfunc declaration can't be prototyped, because it is
1.755 + * assigned, below, to two functions which are prototyped in glob.h
1.756 + * and dirent.h as taking pointers to differently typed opaque
1.757 + * structures.
1.758 + */
1.759 + struct dirent *(*readdirfunc)();
1.760 +
1.761 + if (pathend > pathend_last)
1.762 + return (GLOB_ABORTED);
1.763 + *pathend = EOS;
1.764 + errno = 0;
1.765 +
1.766 + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
1.767 + /* TODO: don't call for ENOENT or ENOTDIR? */
1.768 + if (pglob->gl_errfunc) {
1.769 + if (g_Ctoc(pathbuf, buf, sizeof(buf)))
1.770 + return (GLOB_ABORTED);
1.771 + if (pglob->gl_errfunc(buf, errno) ||
1.772 + pglob->gl_flags & GLOB_ERR)
1.773 + return (GLOB_ABORTED);
1.774 + }
1.775 + return(0);
1.776 + }
1.777 +
1.778 + err = 0;
1.779 +
1.780 + /* Search directory for matching names. */
1.781 + if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1.782 + readdirfunc = pglob->gl_readdir;
1.783 + else
1.784 + readdirfunc = readdir;
1.785 + while (NULL != (dp = (*readdirfunc)(dirp))) {
1.786 + u_char *sc;
1.787 + Char *dc;
1.788 + wchar_t wc;
1.789 + size_t clen;
1.790 + mbstate_t mbs;
1.791 +
1.792 + /* Initial DOT must be matched literally. */
1.793 + if (dp->d_name[0] == DOT && *pattern != DOT)
1.794 + continue;
1.795 + memset(&mbs, 0, sizeof(mbs));
1.796 + dc = pathend;
1.797 + sc = (u_char *) dp->d_name;
1.798 + while (dc < pathend_last) {
1.799 + clen = mbrtowc(&wc,(char*)sc, MB_LEN_MAX, &mbs);
1.800 + if (clen == (size_t)-1 || clen == (size_t)-2) {
1.801 + wc = *sc;
1.802 + clen = 1;
1.803 + memset(&mbs, 0, sizeof(mbs));
1.804 + }
1.805 + if ((*dc++ = wc) == EOS)
1.806 + break;
1.807 + sc += clen;
1.808 + }
1.809 + if (!match(pathend, pattern, restpattern)) {
1.810 + *pathend = EOS;
1.811 + continue;
1.812 + }
1.813 + err = glob2(pathbuf, --dc, pathend_last, restpattern,
1.814 + pglob, limit);
1.815 + if (err)
1.816 + break;
1.817 + }
1.818 +
1.819 + if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1.820 + (*pglob->gl_closedir)(dirp);
1.821 + else
1.822 + closedir(dirp);
1.823 + return(err);
1.824 +}
1.825 +
1.826 +
1.827 +/*
1.828 + * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
1.829 + * add the new item, and update gl_pathc.
1.830 + *
1.831 + * This assumes the BSD realloc, which only copies the block when its size
1.832 + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
1.833 + * behavior.
1.834 + *
1.835 + * Return 0 if new item added, error code if memory couldn't be allocated.
1.836 + *
1.837 + * Invariant of the glob_t structure:
1.838 + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
1.839 + * gl_pathv points to (gl_offs + gl_pathc + 1) items.
1.840 + */
1.841 +static int
1.842 +globextend(path, pglob, limit)
1.843 + const Char *path;
1.844 + glob_t *pglob;
1.845 + int *limit;
1.846 +{
1.847 + char **pathv;
1.848 + int i;
1.849 + u_int newsize, len;
1.850 + char *copy;
1.851 + const Char *p;
1.852 +
1.853 + if (*limit && pglob->gl_pathc > *limit) {
1.854 + errno = 0;
1.855 + return (GLOB_NOSPACE);
1.856 + }
1.857 +
1.858 + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
1.859 + pathv = pglob->gl_pathv ?
1.860 + realloc((char *)pglob->gl_pathv, newsize) :
1.861 + malloc(newsize);
1.862 + if (pathv == NULL) {
1.863 + if (pglob->gl_pathv) {
1.864 + free(pglob->gl_pathv);
1.865 + pglob->gl_pathv = NULL;
1.866 + }
1.867 + return(GLOB_NOSPACE);
1.868 + }
1.869 +
1.870 + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
1.871 + /* first time around -- clear initial gl_offs items */
1.872 + pathv += pglob->gl_offs;
1.873 + for (i = pglob->gl_offs; --i >= 0; )
1.874 + *--pathv = NULL;
1.875 + }
1.876 + pglob->gl_pathv = pathv;
1.877 +
1.878 + for (p = path; *p++;)
1.879 + continue;
1.880 + len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
1.881 + if ((copy = malloc(len)) != NULL) {
1.882 + if (g_Ctoc(path, copy, len)) {
1.883 + free(copy);
1.884 + return (GLOB_NOSPACE);
1.885 + }
1.886 + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
1.887 + }
1.888 + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
1.889 + return(copy == NULL ? GLOB_NOSPACE : 0);
1.890 +}
1.891 +
1.892 +/*
1.893 + * pattern matching function for filenames. Each occurrence of the *
1.894 + * pattern causes a recursion level.
1.895 + */
1.896 +static int
1.897 +match(name, pat, patend)
1.898 + Char *name, *pat, *patend;
1.899 +{
1.900 + int ok, negate_range;
1.901 + Char c, k;
1.902 +
1.903 + while (pat < patend) {
1.904 + c = *pat++;
1.905 + switch (c & M_MASK) {
1.906 + case M_ALL:
1.907 + if (pat == patend)
1.908 + return(1);
1.909 + do
1.910 + if (match(name, pat, patend))
1.911 + return(1);
1.912 + while (*name++ != EOS);
1.913 + return(0);
1.914 + case M_ONE:
1.915 + if (*name++ == EOS)
1.916 + return(0);
1.917 + break;
1.918 + case M_SET:
1.919 + ok = 0;
1.920 + if ((k = *name++) == EOS)
1.921 + return(0);
1.922 + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
1.923 + ++pat;
1.924 + while (((c = *pat++) & M_MASK) != M_END)
1.925 + if ((*pat & M_MASK) == M_RNG) {
1.926 + if (
1.927 + // As used in vfscanf.c
1.928 + #ifndef __SYMBIAN32__
1.929 + __collate_load_error ?
1.930 + #else
1.931 + ((strcmp("C",(const char*) LC_COLLATE_LocaleName)==0) ||(strcmp("POSIX", (const char*) LC_COLLATE_LocaleName)==0 )) ?
1.932 + #endif
1.933 + CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
1.934 + __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
1.935 + && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
1.936 + )
1.937 + ok = 1;
1.938 + pat += 2;
1.939 + } else if (c == k)
1.940 + ok = 1;
1.941 + if (ok == negate_range)
1.942 + return(0);
1.943 + break;
1.944 + default:
1.945 + if (*name++ != c)
1.946 + return(0);
1.947 + break;
1.948 + }
1.949 + }
1.950 + return(*name == EOS);
1.951 +}
1.952 +
1.953 +
1.954 +
1.955 +
1.956 +// EXTERNAL FUNCTION PROTOTYPES
1.957 +//-----------------------------------------------------------------------------
1.958 +//Function Name : void globfree(struct glob_t*)
1.959 +//
1.960 +//Description : Free allocated data belonging to a glob_t structure. Memory
1.961 +// which was dynamically allocated storage from an earlier call to glob()
1.962 +//
1.963 +//Return Value : None
1.964 +//
1.965 +//-----------------------------------------------------------------------------
1.966 +
1.967 +
1.968 +EXPORT_C void
1.969 +globfree(pglob)
1.970 + glob_t *pglob;
1.971 +{
1.972 + int i;
1.973 + char **pp;
1.974 +
1.975 + if (pglob->gl_pathv != NULL) {
1.976 + pp = pglob->gl_pathv + pglob->gl_offs;
1.977 + for (i = pglob->gl_pathc; i--; ++pp)
1.978 + if (*pp)
1.979 + free(*pp);
1.980 + free(pglob->gl_pathv);
1.981 + pglob->gl_pathv = NULL;
1.982 + }
1.983 +}
1.984 +
1.985 +static DIR *
1.986 +g_opendir(str, pglob)
1.987 + Char *str;
1.988 + glob_t *pglob;
1.989 +{
1.990 + char buf[MAXPATHLEN];
1.991 +
1.992 + if (!*str)
1.993 + strcpy(buf, ".");
1.994 + else {
1.995 + if (g_Ctoc(str, buf, sizeof(buf)))
1.996 + return (NULL);
1.997 + }
1.998 +
1.999 + if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1.1000 + return((*pglob->gl_opendir)(buf));
1.1001 +
1.1002 + return(opendir(buf));
1.1003 +}
1.1004 +
1.1005 +static int
1.1006 +g_lstat(fn, sb, pglob)
1.1007 + Char *fn;
1.1008 + struct stat *sb;
1.1009 + glob_t *pglob;
1.1010 +{
1.1011 + char buf[MAXPATHLEN];
1.1012 +
1.1013 + if (g_Ctoc(fn, buf, sizeof(buf))) {
1.1014 + errno = ENAMETOOLONG;
1.1015 + return (-1);
1.1016 + }
1.1017 + if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1.1018 + return((*pglob->gl_lstat)(buf, sb));
1.1019 + return(lstat(buf, sb));
1.1020 +}
1.1021 +
1.1022 +static int
1.1023 +g_stat(fn, sb, pglob)
1.1024 + Char *fn;
1.1025 + struct stat *sb;
1.1026 + glob_t *pglob;
1.1027 +{
1.1028 + char buf[MAXPATHLEN];
1.1029 +
1.1030 + if (g_Ctoc(fn, buf, sizeof(buf))) {
1.1031 + errno = ENAMETOOLONG;
1.1032 + return (-1);
1.1033 + }
1.1034 + if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1.1035 + return((*pglob->gl_stat)(buf, sb));
1.1036 + return(stat(buf, sb));
1.1037 +}
1.1038 +
1.1039 +static Char *
1.1040 +g_strchr(Char *str, wchar_t ch)
1.1041 +{
1.1042 + do {
1.1043 + if (*str == ch)
1.1044 + return (str);
1.1045 + } while (*str++);
1.1046 + return (NULL);
1.1047 +}
1.1048 +
1.1049 +static int
1.1050 +g_Ctoc(str, buf, len)
1.1051 + const Char *str;
1.1052 + char *buf;
1.1053 + u_int len;
1.1054 +{
1.1055 + mbstate_t mbs;
1.1056 + size_t clen;
1.1057 +
1.1058 + memset(&mbs, 0, sizeof(mbs));
1.1059 + while (len >= MB_CUR_MAX) {
1.1060 + clen = wcrtomb(buf, *str, &mbs);
1.1061 + if (clen == (size_t)-1)
1.1062 + return (1);
1.1063 + if (*str == L'\0')
1.1064 + return (0);
1.1065 + str++;
1.1066 + buf += clen;
1.1067 + len -= clen;
1.1068 + }
1.1069 + return (1);
1.1070 +}
1.1071 +
1.1072 +#ifdef DEBUG
1.1073 +static void
1.1074 +qprintf(str, s)
1.1075 + const char *str;
1.1076 + Char *s;
1.1077 +{
1.1078 + Char *p;
1.1079 +
1.1080 + (void)printf("%s:\n", str);
1.1081 + for (p = s; *p; p++)
1.1082 + (void)printf("%c", CHAR(*p));
1.1083 + (void)printf("\n");
1.1084 + for (p = s; *p; p++)
1.1085 + (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
1.1086 + (void)printf("\n");
1.1087 + for (p = s; *p; p++)
1.1088 + (void)printf("%c", ismeta(*p) ? '_' : ' ');
1.1089 + (void)printf("\n");
1.1090 +}
1.1091 +#endif
1.1092 +
1.1093 +#ifdef __cplusplus
1.1094 +} // extern "C"
1.1095 +#endif