add globbing support
This commit is contained in:
parent
2209ae02ba
commit
187847b2b4
|
@ -20,7 +20,8 @@ CFLAGS := -fno-common -Os -Dmalloc=u_boot_malloc \
|
|||
-Dputc=u_boot_putc -Dfgetc=u_boot_fgetc \
|
||||
-Dfputc=u_boot_fputc -Dfgets=u_boot_fgets \
|
||||
-Dfputs=u_boot_fputs -Dsetenv=u_boot_setenv \
|
||||
-Dgetenv=u_boot_getenv -Dprintf=u_boot_printf
|
||||
-Dgetenv=u_boot_getenv -Dprintf=u_boot_printf \
|
||||
-Dglob=u_boot_glob -Dglobfree=u_boot_globfree
|
||||
|
||||
ifeq ($(incdir-y),)
|
||||
incdir-y := $(machine-y)
|
||||
|
|
|
@ -114,6 +114,13 @@ choice
|
|||
|
||||
endchoice
|
||||
|
||||
config GLOB
|
||||
bool
|
||||
prompt "hush globbing support"
|
||||
depends on SHELL_HUSH
|
||||
help
|
||||
If you want to use wildcards like * or ? say y here.
|
||||
|
||||
config PROMPT_HUSH_PS2
|
||||
string
|
||||
depends on SHELL_HUSH
|
||||
|
|
130
common/hush.c
130
common/hush.c
|
@ -120,6 +120,7 @@
|
|||
#include <errno.h>
|
||||
#include <fs.h>
|
||||
#include <libbb.h>
|
||||
#include <glob.h>
|
||||
|
||||
/*cmd_boot.c*/
|
||||
extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); /* do_bootd */
|
||||
|
@ -192,6 +193,7 @@ struct child_prog {
|
|||
struct pipe *group; /* if non-NULL, first in group or subshell */
|
||||
int sp; /* number of SPECIAL_VAR_SYMBOL */
|
||||
int type;
|
||||
glob_t glob_result; /* result of parameter globbing */
|
||||
};
|
||||
|
||||
struct pipe {
|
||||
|
@ -585,6 +587,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||
free(str);
|
||||
return last_return_code;
|
||||
}
|
||||
|
||||
if (strchr(child->argv[i], '/')) {
|
||||
return execute_script(child->argv[i], child->argc-i, &child->argv[i]);
|
||||
}
|
||||
|
@ -754,11 +757,7 @@ static int free_pipe(struct pipe *pi, int indent)
|
|||
for (a=0,p=child->argv; *p; a++,p++) {
|
||||
final_printf("%s argv[%d] = %s\n",ind,a,*p);
|
||||
}
|
||||
for (a = child->argc;a >= 0;a--) {
|
||||
free(child->argv[a]);
|
||||
}
|
||||
free(child->argv);
|
||||
child->argc = 0;
|
||||
globfree(&child->glob_result);
|
||||
child->argv=NULL;
|
||||
} else if (child->group) {
|
||||
ret_code = free_pipe_list(child->group,indent+3);
|
||||
|
@ -788,6 +787,86 @@ static int free_pipe_list(struct pipe *head, int indent)
|
|||
return rcode;
|
||||
}
|
||||
|
||||
/* The API for glob is arguably broken. This routine pushes a non-matching
|
||||
* string into the output structure, removing non-backslashed backslashes.
|
||||
* If someone can prove me wrong, by performing this function within the
|
||||
* original glob(3) api, feel free to rewrite this routine into oblivion.
|
||||
* Return code (0 vs. GLOB_NOSPACE) matches glob(3).
|
||||
* XXX broken if the last character is '\\', check that before calling.
|
||||
*/
|
||||
static int globhack(const char *src, int flags, glob_t *pglob)
|
||||
{
|
||||
int cnt=0, pathc;
|
||||
const char *s;
|
||||
char *dest;
|
||||
for (cnt=1, s=src; s && *s; s++) {
|
||||
if (*s == '\\') s++;
|
||||
cnt++;
|
||||
}
|
||||
dest = xmalloc(cnt);
|
||||
if (!(flags & GLOB_APPEND)) {
|
||||
pglob->gl_pathv = NULL;
|
||||
pglob->gl_pathc = 0;
|
||||
pglob->gl_offs = 0;
|
||||
}
|
||||
pathc = ++pglob->gl_pathc;
|
||||
pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
|
||||
pglob->gl_pathv[pathc-1] = dest;
|
||||
pglob->gl_pathv[pathc] = NULL;
|
||||
for (s=src; s && *s; s++, dest++) {
|
||||
if (*s == '\\') s++;
|
||||
*dest = *s;
|
||||
}
|
||||
*dest='\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX broken if the last character is '\\', check that before calling */
|
||||
static int glob_needed(const char *s)
|
||||
{
|
||||
#ifdef CONFIG_GLOB
|
||||
for (; *s; s++) {
|
||||
if (*s == '\\') s++;
|
||||
if (strchr("*[?",*s))
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xglob(o_string *dest, int flags, glob_t *pglob)
|
||||
{
|
||||
int gr;
|
||||
|
||||
/* short-circuit for null word */
|
||||
/* we can code this better when the debug_printf's are gone */
|
||||
if (dest->length == 0) {
|
||||
if (dest->nonnull) {
|
||||
/* bash man page calls this an "explicit" null */
|
||||
gr = globhack(dest->data, flags, pglob);
|
||||
debug_printf("globhack returned %d\n",gr);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (glob_needed(dest->data)) {
|
||||
gr = glob(dest->data, flags, NULL, pglob);
|
||||
debug_printf("glob returned %d\n",gr);
|
||||
if (gr == GLOB_NOMATCH) {
|
||||
/* quote removal, or more accurately, backslash removal */
|
||||
gr = globhack(dest->data, flags, pglob);
|
||||
debug_printf("globhack returned %d\n",gr);
|
||||
}
|
||||
} else {
|
||||
gr = globhack(dest->data, flags, pglob);
|
||||
debug_printf("globhack returned %d\n",gr);
|
||||
}
|
||||
if (gr != 0) { /* GLOB_ABORTED ? */
|
||||
error_msg("glob(3) error %d",gr);
|
||||
}
|
||||
/* globprint(glob_target); */
|
||||
return gr;
|
||||
}
|
||||
|
||||
/* Select which version we will use */
|
||||
static int run_list(struct pipe *pi)
|
||||
{
|
||||
|
@ -946,8 +1025,8 @@ static int reserved_word(o_string *dest, struct p_context *ctx)
|
|||
static int done_word(o_string *dest, struct p_context *ctx)
|
||||
{
|
||||
struct child_prog *child=ctx->child;
|
||||
char *str, *s;
|
||||
int argc, cnt;
|
||||
glob_t *glob_target;
|
||||
int gr, flags = 0;
|
||||
|
||||
debug_printf("done_word: %s %p\n", dest->data, child);
|
||||
if (dest->length == 0 && !dest->nonnull) {
|
||||
|
@ -963,27 +1042,20 @@ static int done_word(o_string *dest, struct p_context *ctx)
|
|||
if (reserved_word(dest,ctx))
|
||||
return ctx->w==RES_SNTX;
|
||||
}
|
||||
for (cnt = 1, s = dest->data; s && *s; s++) {
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
cnt++;
|
||||
}
|
||||
str = xmalloc(cnt);
|
||||
if ( child->argv == NULL) {
|
||||
child->argc=0;
|
||||
}
|
||||
argc = ++child->argc;
|
||||
child->argv = xrealloc(child->argv, (argc+1)*sizeof(*child->argv));
|
||||
child->argv[argc-1]=str;
|
||||
child->argv[argc]=NULL;
|
||||
for (s = dest->data; s && *s; s++,str++) {
|
||||
if (*s == '\\')
|
||||
s++;
|
||||
*str = *s;
|
||||
}
|
||||
*str = '\0';
|
||||
|
||||
glob_target = &child->glob_result;
|
||||
if (child->argv)
|
||||
flags |= GLOB_APPEND;
|
||||
|
||||
gr = xglob(dest, flags, glob_target);
|
||||
if (gr)
|
||||
return 1;
|
||||
|
||||
b_reset(dest);
|
||||
|
||||
child->argv = glob_target->gl_pathv;
|
||||
child->argc = glob_target->gl_pathc;
|
||||
|
||||
if (ctx->w == RES_FOR) {
|
||||
done_word(dest,ctx);
|
||||
done_pipe(ctx,PIPE_SEQ);
|
||||
|
@ -1017,6 +1089,8 @@ static int done_command(struct p_context *ctx)
|
|||
pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
|
||||
|
||||
prog = pi->progs + pi->num_progs;
|
||||
prog->glob_result.gl_pathv = NULL;
|
||||
|
||||
prog->argv = NULL;
|
||||
prog->group = NULL;
|
||||
prog->sp = 0;
|
||||
|
@ -1496,8 +1570,10 @@ static int source_script(const char *path, int argc, char *argv[])
|
|||
ctx.global_argv = argv;
|
||||
|
||||
script = read_file(path, NULL);
|
||||
if (!script)
|
||||
if (!script) {
|
||||
perror("sh");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = parse_string_outer(&ctx, script, FLAG_PARSE_SEMICOLON);
|
||||
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* Copyright (C) 1991,92,93,96,97,98,99,2001 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#ifndef _FNMATCH_H
|
||||
#define _FNMATCH_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
|
||||
# if !defined __GLIBC__ || !defined __P
|
||||
# undef __P
|
||||
# define __P(protos) protos
|
||||
# endif
|
||||
#else /* Not C++ or ANSI C. */
|
||||
# undef __P
|
||||
# define __P(protos) ()
|
||||
/* We can get away without defining `const' here only because in this file
|
||||
it is used only inside the prototype for `fnmatch', which is elided in
|
||||
non-ANSI C where `const' is problematical. */
|
||||
#endif /* C++ or ANSI C. */
|
||||
|
||||
#ifndef const
|
||||
# if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
# define __const const
|
||||
# else
|
||||
# define __const
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* We #undef these before defining them because some losing systems
|
||||
(HP-UX A.08.07 for example) define these in <unistd.h>. */
|
||||
#undef FNM_PATHNAME
|
||||
#undef FNM_NOESCAPE
|
||||
#undef FNM_PERIOD
|
||||
|
||||
/* Bits set in the FLAGS argument to `fnmatch'. */
|
||||
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
||||
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
|
||||
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
|
||||
|
||||
#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
|
||||
# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
|
||||
# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
|
||||
# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
|
||||
# define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */
|
||||
#endif
|
||||
|
||||
/* Value returned by `fnmatch' if STRING does not match PATTERN. */
|
||||
#define FNM_NOMATCH 1
|
||||
|
||||
/* This value is returned if the implementation does not support
|
||||
`fnmatch'. Since this is not the case here it will never be
|
||||
returned but the conformance test suites still require the symbol
|
||||
to be defined. */
|
||||
#ifdef _XOPEN_SOURCE
|
||||
# define FNM_NOSYS (-1)
|
||||
#endif
|
||||
|
||||
/* Match NAME against the filename pattern PATTERN,
|
||||
returning zero if it matches, FNM_NOMATCH if not. */
|
||||
extern int fnmatch __P ((__const char *__pattern, __const char *__name,
|
||||
int __flags));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* fnmatch.h */
|
|
@ -0,0 +1,231 @@
|
|||
/* Copyright (C) 1991,92,95,96,97,98,2000,2001 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#ifndef _GLOB_H
|
||||
#define _GLOB_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#undef __ptr_t
|
||||
#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
|
||||
# if !defined __GLIBC__ || !defined __P
|
||||
# undef __P
|
||||
# undef __PMT
|
||||
# define __P(protos) protos
|
||||
# define __PMT(protos) protos
|
||||
# if !defined __GNUC__ || __GNUC__ < 2
|
||||
# undef __const
|
||||
# define __const const
|
||||
# endif
|
||||
# endif
|
||||
# define __ptr_t void *
|
||||
#else /* Not C++ or ANSI C. */
|
||||
# undef __P
|
||||
# undef __PMT
|
||||
# define __P(protos) ()
|
||||
# define __PMT(protos) ()
|
||||
# undef __const
|
||||
# define __const
|
||||
# define __ptr_t char *
|
||||
#endif /* C++ or ANSI C. */
|
||||
|
||||
/* We need `size_t' for the following definitions. */
|
||||
#ifndef __size_t
|
||||
# if defined __GNUC__ && __GNUC__ >= 2
|
||||
typedef __SIZE_TYPE__ __size_t;
|
||||
# ifdef _XOPEN_SOURCE
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
# endif
|
||||
# else
|
||||
/* This is a guess. */
|
||||
typedef unsigned long int __size_t;
|
||||
# endif
|
||||
#else
|
||||
/* The GNU CC stddef.h version defines __size_t as empty. We need a real
|
||||
definition. */
|
||||
# undef __size_t
|
||||
# define __size_t size_t
|
||||
#endif
|
||||
|
||||
/* Bits set in the FLAGS argument to `glob'. */
|
||||
#define GLOB_ERR (1 << 0)/* Return on read errors. */
|
||||
#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
|
||||
#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
|
||||
#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
|
||||
#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
|
||||
#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
|
||||
#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
|
||||
#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
|
||||
|
||||
#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \
|
||||
|| defined _GNU_SOURCE)
|
||||
# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
|
||||
# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
|
||||
# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
|
||||
# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
|
||||
# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
|
||||
# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
|
||||
# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
|
||||
if the user name is not available. */
|
||||
# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
|
||||
GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
|
||||
GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
|
||||
GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
|
||||
#else
|
||||
# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
|
||||
GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
|
||||
GLOB_PERIOD)
|
||||
#endif
|
||||
|
||||
/* Error returns from `glob'. */
|
||||
#define GLOB_NOSPACE 1 /* Ran out of memory. */
|
||||
#define GLOB_ABORTED 2 /* Read error. */
|
||||
#define GLOB_NOMATCH 3 /* No matches found. */
|
||||
#define GLOB_NOSYS 4 /* Not implemented. */
|
||||
#ifdef _GNU_SOURCE
|
||||
/* Previous versions of this file defined GLOB_ABEND instead of
|
||||
GLOB_ABORTED. Provide a compatibility definition here. */
|
||||
# define GLOB_ABEND GLOB_ABORTED
|
||||
#endif
|
||||
|
||||
/* Structure describing a globbing run. */
|
||||
#if !defined _AMIGA && !defined VMS /* Buggy compiler. */
|
||||
# ifdef _GNU_SOURCE
|
||||
struct stat;
|
||||
# endif
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
__size_t gl_pathc; /* Count of paths matched by the pattern. */
|
||||
char **gl_pathv; /* List of matched pathnames. */
|
||||
__size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
|
||||
int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
|
||||
|
||||
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
|
||||
are used instead of the normal file access functions. */
|
||||
void (*gl_closedir) __PMT ((void *));
|
||||
#ifdef _GNU_SOURCE
|
||||
struct dirent *(*gl_readdir) __PMT ((void *));
|
||||
#else
|
||||
void *(*gl_readdir) __PMT ((void *));
|
||||
#endif
|
||||
__ptr_t (*gl_opendir) __PMT ((__const char *));
|
||||
#ifdef _GNU_SOURCE
|
||||
int (*gl_lstat) __PMT ((__const char *__restrict,
|
||||
struct stat *__restrict));
|
||||
int (*gl_stat) __PMT ((__const char *__restrict, struct stat *__restrict));
|
||||
#else
|
||||
int (*gl_lstat) __PMT ((__const char *__restrict, void *__restrict));
|
||||
int (*gl_stat) __PMT ((__const char *__restrict, void *__restrict));
|
||||
#endif
|
||||
} glob_t;
|
||||
|
||||
#ifdef _LARGEFILE64_SOURCE
|
||||
# ifdef _GNU_SOURCE
|
||||
struct stat64;
|
||||
# endif
|
||||
typedef struct
|
||||
{
|
||||
__size_t gl_pathc;
|
||||
char **gl_pathv;
|
||||
__size_t gl_offs;
|
||||
int gl_flags;
|
||||
|
||||
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
|
||||
are used instead of the normal file access functions. */
|
||||
void (*gl_closedir) __PMT ((void *));
|
||||
# ifdef _GNU_SOURCE
|
||||
struct dirent64 *(*gl_readdir) __PMT ((void *));
|
||||
# else
|
||||
void *(*gl_readdir) __PMT ((void *));
|
||||
# endif
|
||||
__ptr_t (*gl_opendir) __PMT ((__const char *));
|
||||
# ifdef _GNU_SOURCE
|
||||
int (*gl_lstat) __PMT ((__const char *__restrict,
|
||||
struct stat64 *__restrict));
|
||||
int (*gl_stat) __PMT ((__const char *__restrict,
|
||||
struct stat64 *__restrict));
|
||||
# else
|
||||
int (*gl_lstat) __PMT ((__const char *__restrict, void *__restrict));
|
||||
int (*gl_stat) __PMT ((__const char *__restrict, void *__restrict));
|
||||
# endif
|
||||
} glob64_t;
|
||||
#endif
|
||||
|
||||
#if _FILE_OFFSET_BITS == 64 && __GNUC__ < 2
|
||||
# define glob glob64
|
||||
# define globfree globfree64
|
||||
#endif
|
||||
|
||||
/* Do glob searching for PATTERN, placing results in PGLOB.
|
||||
The bits defined above may be set in FLAGS.
|
||||
If a directory cannot be opened or read and ERRFUNC is not nil,
|
||||
it is called with the pathname that caused the error, and the
|
||||
`errno' value from the failing call; if it returns non-zero
|
||||
`glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
|
||||
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
|
||||
Otherwise, `glob' returns zero. */
|
||||
#if _FILE_OFFSET_BITS != 64 || __GNUC__ < 2
|
||||
#if defined CONFIG_GLOB || defined CONFIG_FAKE_GLOB
|
||||
extern int glob __P ((__const char *__restrict __pattern, int __flags,
|
||||
int (*__errfunc) (__const char *, int),
|
||||
glob_t *__restrict __pglob));
|
||||
|
||||
#else
|
||||
static inline int glob __P ((__const char *__restrict __pattern, int __flags,
|
||||
int (*__errfunc) (__const char *, int),
|
||||
glob_t *__restrict __pglob))
|
||||
{
|
||||
return GLOB_ABORTED;
|
||||
}
|
||||
#endif
|
||||
/* Free storage allocated in PGLOB by a previous `glob' call. */
|
||||
extern void globfree __P ((glob_t *__pglob));
|
||||
#else
|
||||
extern int glob __P ((__const char *__restrict __pattern, int __flags,
|
||||
int (*__errfunc) (__const char *, int),
|
||||
glob_t *__restrict __pglob)) __asm__ ("glob64");
|
||||
|
||||
extern void globfree __P ((glob_t *__pglob)) __asm__ ("globfree64");
|
||||
#endif
|
||||
|
||||
#ifdef _LARGEFILE64_SOURCE
|
||||
extern int glob64 __P ((__const char *__restrict __pattern, int __flags,
|
||||
int (*__errfunc) (__const char *, int),
|
||||
glob64_t *__restrict __pglob));
|
||||
|
||||
extern void globfree64 __P ((glob64_t *__pglob));
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
/* Return nonzero if PATTERN contains any metacharacters.
|
||||
Metacharacters can be quoted with backslashes if QUOTE is nonzero.
|
||||
|
||||
This function is not part of the interface specified by POSIX.2
|
||||
but several programs want to use it. */
|
||||
extern int glob_pattern_p __P ((__const char *__pattern, int __quote));
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* glob.h */
|
|
@ -0,0 +1,228 @@
|
|||
/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Enable GNU extensions in fnmatch.h. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
# if defined (STDC_HEADERS) || !defined (isascii)
|
||||
# define ISASCII(c) 1
|
||||
# else
|
||||
# define ISASCII(c) isascii(c)
|
||||
# endif
|
||||
|
||||
# define ISUPPER(c) (ISASCII (c) && isupper (c))
|
||||
|
||||
|
||||
# ifndef errno
|
||||
extern int errno;
|
||||
# endif
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, nonzero if not. */
|
||||
int fnmatch(pattern, string, flags)
|
||||
const char *pattern;
|
||||
const char *string;
|
||||
int flags;
|
||||
{
|
||||
register const char *p = pattern, *n = string;
|
||||
register char c;
|
||||
|
||||
/* Note that this evaluates C many times. */
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
|
||||
|
||||
while ((c = *p++) != '\0') {
|
||||
c = FOLD(c);
|
||||
|
||||
switch (c) {
|
||||
case '?':
|
||||
if (*n == '\0')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_FILE_NAME) && *n == '/')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
(n == string
|
||||
|| ((flags & FNM_FILE_NAME)
|
||||
&& n[-1] == '/'))) return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE)) {
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
/* Trailing \ loses. */
|
||||
return FNM_NOMATCH;
|
||||
c = FOLD(c);
|
||||
}
|
||||
if (FOLD(*n) != c)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
for (c = *p++; c == '?' || c == '*'; c = *p++) {
|
||||
if ((flags & FNM_FILE_NAME) && *n == '/')
|
||||
/* A slash does not match a wildcard under FNM_FILE_NAME. */
|
||||
return FNM_NOMATCH;
|
||||
else if (c == '?') {
|
||||
/* A ? needs to match one character. */
|
||||
if (*n == '\0')
|
||||
/* There isn't another character; no match. */
|
||||
return FNM_NOMATCH;
|
||||
else
|
||||
/* One character of the string is consumed in matching
|
||||
this ? wildcard, so *??? won't match if there are
|
||||
less than three characters. */
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
|
||||
{
|
||||
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
|
||||
|
||||
c1 = FOLD(c1);
|
||||
for (--p; *n != '\0'; ++n)
|
||||
if ((c == '[' || FOLD(*n) == c1) &&
|
||||
fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
|
||||
return 0;
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
case '[':
|
||||
{
|
||||
/* Nonzero if the sense of the character class is inverted. */
|
||||
register int not;
|
||||
|
||||
if (*n == '\0')
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
not = (*p == '!' || *p == '^');
|
||||
if (not)
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;) {
|
||||
register char cstart = c, cend = c;
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\') {
|
||||
if (*p == '\0')
|
||||
return FNM_NOMATCH;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
cstart = cend = FOLD(cstart);
|
||||
|
||||
if (c == '\0')
|
||||
/* [ (unterminated) loses. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
c = *p++;
|
||||
c = FOLD(c);
|
||||
|
||||
if ((flags & FNM_FILE_NAME) && c == '/')
|
||||
/* [/] can never match. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if (c == '-' && *p != ']') {
|
||||
cend = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && cend == '\\')
|
||||
cend = *p++;
|
||||
if (cend == '\0')
|
||||
return FNM_NOMATCH;
|
||||
cend = FOLD(cend);
|
||||
|
||||
c = *p++;
|
||||
}
|
||||
|
||||
if (FOLD(*n) >= cstart && FOLD(*n) <= cend)
|
||||
goto matched;
|
||||
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
if (!not)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
matched:;
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
while (c != ']') {
|
||||
if (c == '\0')
|
||||
/* [... (unterminated) loses. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
c = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\') {
|
||||
if (*p == '\0')
|
||||
return FNM_NOMATCH;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
if (not)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (c != FOLD(*n))
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
if (*n == '\0')
|
||||
return 0;
|
||||
|
||||
if ((flags & FNM_LEADING_DIR) && *n == '/')
|
||||
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
|
||||
return 0;
|
||||
|
||||
return FNM_NOMATCH;
|
||||
|
||||
# undef FOLD
|
||||
}
|
||||
|
|
@ -0,0 +1,471 @@
|
|||
/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <malloc.h>
|
||||
#include <xfuncs.h>
|
||||
#include <fnmatch.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <glob.h>
|
||||
|
||||
#ifdef CONFIG_GLOB
|
||||
|
||||
extern __ptr_t(*__glob_opendir_hook) __P((const char *directory));
|
||||
extern void (*__glob_closedir_hook) __P((__ptr_t stream));
|
||||
extern const char *(*__glob_readdir_hook) __P((__ptr_t stream));
|
||||
|
||||
static int glob_in_dir __P((const char *pattern, const char *directory,
|
||||
int flags,
|
||||
int (*errfunc) __P((const char *, int)),
|
||||
glob_t * pglob));
|
||||
static int prefix_array __P((const char *prefix, char **array, size_t n,
|
||||
int add_slash));
|
||||
|
||||
#ifdef __GLOB64
|
||||
extern int glob_pattern_p(const char *pattern, int quote);
|
||||
#else
|
||||
/* Return nonzero if PATTERN contains any metacharacters.
|
||||
Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
|
||||
int glob_pattern_p(const char *pattern, int quote)
|
||||
{
|
||||
const char *p;
|
||||
int open = 0;
|
||||
|
||||
for (p = pattern; *p != '\0'; ++p)
|
||||
switch (*p) {
|
||||
case '?':
|
||||
case '*':
|
||||
return 1;
|
||||
|
||||
case '\\':
|
||||
if (quote && p[1] != '\0')
|
||||
++p;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
open = 1;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
if (open)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GLOB_SORT
|
||||
/* Do a collated comparison of A and B. */
|
||||
static int collated_compare(a, b)
|
||||
const __ptr_t a;
|
||||
const __ptr_t b;
|
||||
{
|
||||
const char *const s1 = *(const char *const *)a;
|
||||
const char *const s2 = *(const char *const *)b;
|
||||
|
||||
if (s1 == s2)
|
||||
return 0;
|
||||
if (s1 == NULL)
|
||||
return 1;
|
||||
if (s2 == NULL)
|
||||
return -1;
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do glob searching for PATTERN, placing results in PGLOB.
|
||||
The bits defined above may be set in FLAGS.
|
||||
If a directory cannot be opened or read and ERRFUNC is not nil,
|
||||
it is called with the pathname that caused the error, and the
|
||||
`errno' value from the failing call; if it returns non-zero
|
||||
`glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
|
||||
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
|
||||
Otherwise, `glob' returns zero. */
|
||||
int glob(pattern, flags, errfunc, pglob)
|
||||
const char *pattern;
|
||||
int flags;
|
||||
int (*errfunc) __P((const char *, int));
|
||||
glob_t *pglob;
|
||||
{
|
||||
const char *filename;
|
||||
char *dirname = NULL;
|
||||
size_t dirlen;
|
||||
int status;
|
||||
int oldcount;
|
||||
|
||||
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find the filename. */
|
||||
filename = strrchr(pattern, '/');
|
||||
if (filename == NULL) {
|
||||
filename = pattern;
|
||||
dirname = strdup(".");
|
||||
dirlen = 0;
|
||||
} else if (filename == pattern) {
|
||||
/* "/pattern". */
|
||||
dirname = strdup("/");
|
||||
dirlen = 1;
|
||||
++filename;
|
||||
} else {
|
||||
dirlen = filename - pattern;
|
||||
dirname = (char *)xmalloc(dirlen + 1);
|
||||
memcpy(dirname, pattern, dirlen);
|
||||
dirname[dirlen] = '\0';
|
||||
++filename;
|
||||
}
|
||||
|
||||
if (filename[0] == '\0' && dirlen > 1) {
|
||||
/* "pattern/". Expand "pattern", appending slashes. */
|
||||
int val = glob(dirname, flags | GLOB_MARK, errfunc, pglob);
|
||||
if (val == 0)
|
||||
pglob->gl_flags =
|
||||
(pglob->
|
||||
gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK);
|
||||
status = val;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(flags & GLOB_APPEND)) {
|
||||
pglob->gl_pathc = 0;
|
||||
pglob->gl_pathv = NULL;
|
||||
}
|
||||
|
||||
oldcount = pglob->gl_pathc;
|
||||
|
||||
if (glob_pattern_p(dirname, !(flags & GLOB_NOESCAPE))) {
|
||||
/* The directory name contains metacharacters, so we
|
||||
have to glob for the directory, and then glob for
|
||||
the pattern in each directory found. */
|
||||
glob_t dirs;
|
||||
register int i;
|
||||
status = glob(dirname,
|
||||
((flags &
|
||||
(GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) |
|
||||
GLOB_NOSORT), errfunc, &dirs);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
|
||||
/* We have successfully globbed the preceding directory name.
|
||||
For each name we found, call glob_in_dir on it and FILENAME,
|
||||
appending the results to PGLOB. */
|
||||
for (i = 0; i < dirs.gl_pathc; ++i) {
|
||||
int oldcount;
|
||||
|
||||
#ifdef SHELL
|
||||
{
|
||||
/* Make globbing interruptible in the bash shell. */
|
||||
extern int interrupt_state;
|
||||
|
||||
if (interrupt_state) {
|
||||
globfree(&dirs);
|
||||
globfree(&files);
|
||||
status = GLOB_ABEND goto out;
|
||||
}
|
||||
}
|
||||
#endif /* SHELL. */
|
||||
|
||||
oldcount = pglob->gl_pathc;
|
||||
status = glob_in_dir(filename, dirs.gl_pathv[i],
|
||||
(flags | GLOB_APPEND) &
|
||||
~GLOB_NOCHECK, errfunc, pglob);
|
||||
if (status == GLOB_NOMATCH) {
|
||||
/* No matches in this directory. Try the next. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
globfree(pglob);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Stick the directory on the front of each name. */
|
||||
prefix_array(dirs.gl_pathv[i],
|
||||
&pglob->gl_pathv[oldcount],
|
||||
pglob->gl_pathc - oldcount,
|
||||
flags & GLOB_MARK);
|
||||
}
|
||||
|
||||
globfree(&dirs);
|
||||
flags |= GLOB_MAGCHAR;
|
||||
|
||||
if (pglob->gl_pathc == oldcount) {
|
||||
/* No matches. */
|
||||
#ifdef CONFIG_GLOB_NOCHECK
|
||||
if (flags & GLOB_NOCHECK) {
|
||||
size_t len = strlen(pattern) + 1;
|
||||
char *patcopy = (char *)xmalloc(len);
|
||||
memcpy(patcopy, pattern, len);
|
||||
|
||||
pglob->gl_pathv
|
||||
= (char **)xrealloc(pglob->gl_pathv,
|
||||
(pglob->gl_pathc +
|
||||
((flags & GLOB_DOOFFS) ?
|
||||
pglob->gl_offs : 0) +
|
||||
1 + 1) *
|
||||
sizeof(char *));
|
||||
|
||||
if (flags & GLOB_DOOFFS)
|
||||
while (pglob->gl_pathc < pglob->gl_offs)
|
||||
pglob->gl_pathv[pglob->
|
||||
gl_pathc++] =
|
||||
NULL;
|
||||
|
||||
pglob->gl_pathv[pglob->gl_pathc++] = patcopy;
|
||||
pglob->gl_pathv[pglob->gl_pathc] = NULL;
|
||||
pglob->gl_flags = flags;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
status = GLOB_NOMATCH;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = glob_in_dir(filename, dirname, flags, errfunc, pglob);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
|
||||
if (dirlen > 0) {
|
||||
/* Stick the directory on the front of each name. */
|
||||
prefix_array(dirname,
|
||||
&pglob->gl_pathv[oldcount],
|
||||
pglob->gl_pathc - oldcount,
|
||||
flags & GLOB_MARK);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & GLOB_MARK) {
|
||||
/* Append slashes to directory names. glob_in_dir has already
|
||||
allocated the extra character for us. */
|
||||
int i;
|
||||
struct stat st;
|
||||
for (i = oldcount; i < pglob->gl_pathc; ++i)
|
||||
if (stat(pglob->gl_pathv[i], &st) == 0 &&
|
||||
S_ISDIR(st.st_mode))
|
||||
strcat(pglob->gl_pathv[i], "/");
|
||||
}
|
||||
#ifdef CONFIG_GLOB_SORT
|
||||
if (!(flags & GLOB_NOSORT))
|
||||
/* Sort the vector. */
|
||||
qsort((__ptr_t) & pglob->gl_pathv[oldcount],
|
||||
pglob->gl_pathc - oldcount,
|
||||
sizeof(char *), (__compar_fn_t) collated_compare);
|
||||
#endif
|
||||
status = 0;
|
||||
out:
|
||||
free(dirname);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
|
||||
elements in place. Return nonzero if out of memory, zero if successful.
|
||||
A slash is inserted between DIRNAME and each elt of ARRAY,
|
||||
unless DIRNAME is just "/". Each old element of ARRAY is freed.
|
||||
If ADD_SLASH is non-zero, allocate one character more than
|
||||
necessary, so that a slash can be appended later. */
|
||||
static int prefix_array(dirname, array, n, add_slash)
|
||||
const char *dirname;
|
||||
char **array;
|
||||
size_t n;
|
||||
int add_slash;
|
||||
{
|
||||
register size_t i;
|
||||
size_t dirlen = strlen(dirname);
|
||||
|
||||
if (dirlen == 1 && dirname[0] == '/')
|
||||
/* DIRNAME is just "/", so normal prepending would get us "//foo".
|
||||
We want "/foo" instead, so don't prepend any chars from DIRNAME. */
|
||||
dirlen = 0;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
size_t eltlen = strlen(array[i]) + 1;
|
||||
char *new =
|
||||
(char *)xmalloc(dirlen + 1 + eltlen + (add_slash ? 1 : 0));
|
||||
|
||||
memcpy(new, dirname, dirlen);
|
||||
new[dirlen] = '/';
|
||||
memcpy(&new[dirlen + 1], array[i], eltlen);
|
||||
free((__ptr_t) array[i]);
|
||||
array[i] = new;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Like `glob', but PATTERN is a final pathname component,
|
||||
and matches are searched for in DIRECTORY.
|
||||
The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
|
||||
The GLOB_APPEND flag is assumed to be set (always appends). */
|
||||
static int glob_in_dir(pattern, directory, flags, errfunc, pglob)
|
||||
const char *pattern;
|
||||
const char *directory;
|
||||
int flags;
|
||||
int (*errfunc) __P((const char *, int));
|
||||
glob_t *pglob;
|
||||
{
|
||||
__ptr_t stream;
|
||||
|
||||
struct globlink {
|
||||
struct globlink *next;
|
||||
char *name;
|
||||
};
|
||||
struct globlink *names = NULL;
|
||||
size_t nfound = 0;
|
||||
int meta;
|
||||
|
||||
stream = opendir(directory);
|
||||
|
||||
if (stream == NULL) {
|
||||
if ((errfunc != NULL && (*errfunc) (directory, errno)) ||
|
||||
(flags & GLOB_ERR))
|
||||
return GLOB_ABORTED;
|
||||
}
|
||||
|
||||
meta = glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE));
|
||||
|
||||
if (meta)
|
||||
flags |= GLOB_MAGCHAR;
|
||||
|
||||
while (1) {
|
||||
const char *name;
|
||||
size_t len;
|
||||
|
||||
struct dirent *d = readdir((DIR *) stream);
|
||||
if (d == NULL)
|
||||
break;
|
||||
// if (! (d->d_ino != 0))
|
||||
// continue;
|
||||
name = d->d_name;
|
||||
|
||||
if ((!meta && strcmp(pattern, name) == 0)
|
||||
|| fnmatch(pattern, name,
|
||||
(!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |
|
||||
((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)) == 0) {
|
||||
struct globlink *new =
|
||||
(struct globlink *)xmalloc(sizeof(struct globlink));
|
||||
len = strlen(name);
|
||||
new->name = xmalloc(len + ((flags & GLOB_MARK) ? 1 : 0) + 1);
|
||||
memcpy((__ptr_t) new->name, name, len);
|
||||
new->name[len] = '\0';
|
||||
new->next = names;
|
||||
names = new;
|
||||
++nfound;
|
||||
if (!meta)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_GLOB_NOCHECK
|
||||
if (nfound == 0 && (flags & GLOB_NOCHECK)) {
|
||||
size_t len = strlen(pattern);
|
||||
nfound = 1;
|
||||
names = (struct globlink *)xmalloc(sizeof(struct globlink));
|
||||
names->next = NULL;
|
||||
names->name =
|
||||
(char *)xmalloc(len + (flags & GLOB_MARK ? 1 : 0) + 1);
|
||||
memcpy(names->name, pattern, len);
|
||||
names->name[len] = '\0';
|
||||
}
|
||||
#endif
|
||||
pglob->gl_pathv
|
||||
= (char **)xrealloc(pglob->gl_pathv,
|
||||
(pglob->gl_pathc +
|
||||
((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) +
|
||||
nfound + 1) * sizeof(char *));
|
||||
|
||||
if (flags & GLOB_DOOFFS)
|
||||
while (pglob->gl_pathc < pglob->gl_offs)
|
||||
pglob->gl_pathv[pglob->gl_pathc++] = NULL;
|
||||
|
||||
while (names) {
|
||||
struct globlink *tmp;
|
||||
|
||||
pglob->gl_pathv[pglob->gl_pathc++] = names->name;
|
||||
tmp = names;
|
||||
names = names->next;
|
||||
free(tmp);
|
||||
}
|
||||
pglob->gl_pathv[pglob->gl_pathc] = NULL;
|
||||
|
||||
pglob->gl_flags = flags;
|
||||
|
||||
{
|
||||
int save = errno;
|
||||
(void)closedir((DIR *) stream);
|
||||
errno = save;
|
||||
}
|
||||
return nfound == 0 ? GLOB_NOMATCH : 0;
|
||||
}
|
||||
#endif /* CONFIG_GLOB */
|
||||
|
||||
#ifdef CONFIG_FAKE_GLOB
|
||||
/* Fake version of glob. We simply put the input string into
|
||||
* the gl_pathv array. Currently we don't need it as hush.c won't
|
||||
* call us if no glob support is available.
|
||||
*/
|
||||
int glob(pattern, flags, errfunc, pglob)
|
||||
const char *pattern;
|
||||
int flags;
|
||||
int (*errfunc) __P((const char *, int));
|
||||
glob_t *pglob;
|
||||
{
|
||||
int elems, i;
|
||||
|
||||
if (!(flags & GLOB_APPEND)) {
|
||||
pglob->gl_pathc = 0;
|
||||
pglob->gl_pathv = NULL;
|
||||
}
|
||||
|
||||
elems = pglob->gl_pathc + 2;
|
||||
if (flags & GLOB_DOOFFS)
|
||||
elems += pglob->gl_offs;
|
||||
|
||||
pglob->gl_pathv = xrealloc(pglob->gl_pathv, elems * sizeof(char *));
|
||||
|
||||
if (flags & GLOB_DOOFFS)
|
||||
for (i = 0; i < pglob->gl_offs; i++)
|
||||
pglob->gl_pathv[i] = NULL;
|
||||
|
||||
pglob->gl_pathv[pglob->gl_pathc] = strdup(pattern);
|
||||
pglob->gl_pathc++;
|
||||
pglob->gl_pathv[pglob->gl_pathc] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_FAKE_GLOB */
|
||||
|
||||
/* Free storage allocated in PGLOB by a previous `glob' call. */
|
||||
void globfree(pglob)
|
||||
register glob_t *pglob;
|
||||
{
|
||||
if (pglob->gl_pathv != NULL) {
|
||||
register int i =
|
||||
pglob->gl_flags & GLOB_DOOFFS ? pglob->gl_offs : 0;
|
||||
for (; i < pglob->gl_pathc; ++i)
|
||||
if (pglob->gl_pathv[i] != NULL)
|
||||
free((__ptr_t) pglob->gl_pathv[i]);
|
||||
free((__ptr_t) pglob->gl_pathv);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue