summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/port/regex/glob.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc/port/regex/glob.c')
-rw-r--r--usr/src/lib/libc/port/regex/glob.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/usr/src/lib/libc/port/regex/glob.c b/usr/src/lib/libc/port/regex/glob.c
new file mode 100644
index 0000000000..d411840dea
--- /dev/null
+++ b/usr/src/lib/libc/port/regex/glob.c
@@ -0,0 +1,319 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This code is MKS code ported to Solaris originally with minimum
+ * modifications so that upgrades from MKS would readily integrate.
+ * The MKS basis for this modification was:
+ *
+ * $Id: glob.c 1.31 1994/04/07 22:50:43 mark
+ *
+ * Additional modifications have been made to this code to make it
+ * 64-bit clean.
+ */
+
+/*
+ * glob, globfree -- POSIX.2 compatible file name expansion routines.
+ *
+ * Copyright 1985, 1991 by Mortice Kern Systems Inc. All rights reserved.
+ *
+ * Written by Eric Gisin.
+ */
+
+#include "lint.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <glob.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#define GLOB__CHECK 0x80 /* stat generated paths */
+
+#define INITIAL 8 /* initial pathv allocation */
+#define NULLCPP ((char **)0) /* Null char ** */
+
+static int globit(size_t, const char *, glob_t *, int,
+ int (*)(const char *, int), char **);
+static int pstrcmp(const void *, const void *);
+static int append(glob_t *, const char *);
+
+/*
+ * Free all space consumed by glob.
+ */
+void
+globfree(glob_t *gp)
+{
+ size_t i;
+
+ if (gp->gl_pathv == 0)
+ return;
+
+ for (i = gp->gl_offs; i < gp->gl_offs + gp->gl_pathc; ++i)
+ free(gp->gl_pathv[i]);
+ free((void *)gp->gl_pathv);
+
+ gp->gl_pathc = 0;
+ gp->gl_pathv = NULLCPP;
+}
+
+/*
+ * Do filename expansion.
+ */
+int
+glob(const char *pattern, int flags,
+ int (*errfn)(const char *, int), glob_t *gp)
+{
+ int rv;
+ size_t i;
+ size_t ipathc;
+ char *path;
+
+ if ((flags & GLOB_DOOFFS) == 0)
+ gp->gl_offs = 0;
+
+ if (!(flags & GLOB_APPEND)) {
+ gp->gl_pathc = 0;
+ gp->gl_pathn = gp->gl_offs + INITIAL;
+ gp->gl_pathv = (char **)malloc(sizeof (char *) * gp->gl_pathn);
+
+ if (gp->gl_pathv == NULLCPP)
+ return (GLOB_NOSPACE);
+ gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
+
+ for (i = 0; i < gp->gl_offs; ++i)
+ gp->gl_pathv[i] = NULL;
+ }
+
+ if ((path = malloc(strlen(pattern)+1)) == NULL)
+ return (GLOB_NOSPACE);
+
+ ipathc = gp->gl_pathc;
+ rv = globit(0, pattern, gp, flags, errfn, &path);
+
+ if (rv == GLOB_ABORTED) {
+ /*
+ * User's error function returned non-zero, or GLOB_ERR was
+ * set, and we encountered a directory we couldn't search.
+ */
+ free(path);
+ return (GLOB_ABORTED);
+ }
+
+ i = gp->gl_pathc - ipathc;
+ if (i >= 1 && !(flags & GLOB_NOSORT)) {
+ qsort((char *)(gp->gl_pathp+ipathc), i, sizeof (char *),
+ pstrcmp);
+ }
+ if (i == 0) {
+ if (flags & GLOB_NOCHECK)
+ (void) append(gp, pattern);
+ else
+ rv = GLOB_NOMATCH;
+ }
+ gp->gl_pathp[gp->gl_pathc] = NULL;
+ free(path);
+
+ return (rv);
+}
+
+
+/*
+ * Recursive routine to match glob pattern, and walk directories.
+ */
+int
+globit(size_t dend, const char *sp, glob_t *gp, int flags,
+ int (*errfn)(const char *, int), char **path)
+{
+ size_t n;
+ size_t m;
+ ssize_t end = 0; /* end of expanded directory */
+ char *pat = (char *)sp; /* pattern component */
+ char *dp = (*path) + dend;
+ int expand = 0; /* path has pattern */
+ char *cp;
+ struct stat64 sb;
+ DIR *dirp;
+ struct dirent64 *d;
+ struct dirent64 *entry = NULL;
+ int namemax;
+ int err;
+
+#define FREE_ENTRY if (entry) free(entry)
+
+ for (;;)
+ switch (*dp++ = *(unsigned char *)sp++) {
+ case '\0': /* end of source path */
+ if (expand)
+ goto Expand;
+ else {
+ if (!(flags & GLOB_NOCHECK) ||
+ flags & (GLOB__CHECK|GLOB_MARK))
+ if (stat64(*path, &sb) < 0) {
+ FREE_ENTRY;
+ return (0);
+ }
+ if (flags & GLOB_MARK && S_ISDIR(sb.st_mode)) {
+ *dp = '\0';
+ *--dp = '/';
+ }
+ if (append(gp, *path) < 0) {
+ FREE_ENTRY;
+ return (GLOB_NOSPACE);
+ }
+ return (0);
+ }
+ /*NOTREACHED*/
+
+ case '*':
+ case '?':
+ case '[':
+ case '\\':
+ ++expand;
+ break;
+
+ case '/':
+ if (expand)
+ goto Expand;
+ end = dp - *path;
+ pat = (char *)sp;
+ break;
+
+ Expand:
+ /* determine directory and open it */
+ (*path)[end] = '\0';
+#ifdef NAME_MAX
+ namemax = NAME_MAX;
+#else
+ namemax = 1024; /* something large */
+#endif
+ if ((entry = (struct dirent64 *)malloc(
+ sizeof (struct dirent64) + namemax + 1))
+ == NULL) {
+ return (GLOB_NOSPACE);
+ }
+
+ dirp = opendir(**path == '\0' ? "." : *path);
+ if (dirp == (DIR *)0 || namemax == -1) {
+ if (errfn != 0 && errfn(*path, errno) != 0 ||
+ flags&GLOB_ERR) {
+ FREE_ENTRY;
+ return (GLOB_ABORTED);
+ }
+ FREE_ENTRY;
+ return (0);
+ }
+
+ /* extract pattern component */
+ n = sp - pat;
+ if ((cp = malloc(n)) == NULL) {
+ (void) closedir(dirp);
+ FREE_ENTRY;
+ return (GLOB_NOSPACE);
+ }
+ pat = memcpy(cp, pat, n);
+ pat[n-1] = '\0';
+ if (*--sp != '\0')
+ flags |= GLOB__CHECK;
+
+ /* expand path to max. expansion */
+ n = dp - *path;
+ *path = realloc(*path,
+ strlen(*path)+namemax+strlen(sp)+1);
+ if (*path == NULL) {
+ (void) closedir(dirp);
+ free(pat);
+ FREE_ENTRY;
+ return (GLOB_NOSPACE);
+ }
+ dp = (*path) + n;
+
+ /* read directory and match entries */
+ err = 0;
+ while (readdir64_r(dirp, entry, &d) == 0) {
+ if (d == NULL)
+ break;
+ cp = d->d_name;
+ if ((flags&GLOB_NOESCAPE)
+ ? fnmatch(pat, cp, FNM_PERIOD|FNM_NOESCAPE)
+ : fnmatch(pat, cp, FNM_PERIOD))
+ continue;
+
+ n = strlen(cp);
+ (void) memcpy((*path) + end, cp, n);
+ m = dp - *path;
+ err = globit(end+n, sp, gp, flags, errfn, path);
+ dp = (*path) + m; /* globit can move path */
+ if (err != 0)
+ break;
+ }
+
+ (void) closedir(dirp);
+ free(pat);
+ FREE_ENTRY;
+ return (err);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Comparison routine for two name arguments, called by qsort.
+ */
+int
+pstrcmp(const void *npp1, const void *npp2)
+{
+ return (strcoll(*(char **)npp1, *(char **)npp2));
+}
+
+/*
+ * Add a new matched filename to the glob_t structure, increasing the
+ * size of that array, as required.
+ */
+int
+append(glob_t *gp, const char *str)
+{
+ char *cp;
+
+ if ((cp = malloc(strlen(str)+1)) == NULL)
+ return (GLOB_NOSPACE);
+ gp->gl_pathp[gp->gl_pathc++] = strcpy(cp, str);
+
+ if ((gp->gl_pathc + gp->gl_offs) >= gp->gl_pathn) {
+ gp->gl_pathn *= 2;
+ gp->gl_pathv = (char **)realloc((void *)gp->gl_pathv,
+ gp->gl_pathn * sizeof (char *));
+ if (gp->gl_pathv == NULLCPP)
+ return (GLOB_NOSPACE);
+ gp->gl_pathp = gp->gl_pathv + gp->gl_offs;
+ }
+ return (0);
+}