aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/config/util/mkshadow
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/config/util/mkshadow')
-rw-r--r--nx-X11/config/util/mkshadow/Imakefile5
-rw-r--r--nx-X11/config/util/mkshadow/README38
-rw-r--r--nx-X11/config/util/mkshadow/mkshadow.c378
-rw-r--r--nx-X11/config/util/mkshadow/savedir.c119
-rw-r--r--nx-X11/config/util/mkshadow/wildmat.c167
5 files changed, 707 insertions, 0 deletions
diff --git a/nx-X11/config/util/mkshadow/Imakefile b/nx-X11/config/util/mkshadow/Imakefile
new file mode 100644
index 000000000..e8a879d97
--- /dev/null
+++ b/nx-X11/config/util/mkshadow/Imakefile
@@ -0,0 +1,5 @@
+XCOMM $Xorg: Imakefile,v 1.3 2000/08/17 19:41:53 cpqbld Exp $
+ SRCS = mkshadow.c savedir.c wildmat.c
+ OBJS = mkshadow.o savedir.o wildmat.o
+
+ComplexProgramTarget(mkshadow)
diff --git a/nx-X11/config/util/mkshadow/README b/nx-X11/config/util/mkshadow/README
new file mode 100644
index 000000000..eea4b8b89
--- /dev/null
+++ b/nx-X11/config/util/mkshadow/README
@@ -0,0 +1,38 @@
+The mkshadow programs makes a "shadow tree" of a directory tree.
+It logically copies all of the "MASTER" directory into ".".
+However, ordinary files, and RCS/SCCS directories are "copied"
+by creating a sybolic link to the corresponding file in MASTER.
+
+The wildmat.c file is by Rich Salz, and from comp.sources.misc, volume 17.
+The savedir.c file is lightly modified from the version written
+by David MacKenzie for GNU fileutils; the Free Software Foundation
+has graciously agreed to waive their usual copyright so this
+program can be distributed by the X Consortium.
+
+If you have problems compiling savedir.c, try setting the DIRENT make
+variable as suggested in the Makefile.
+
+ * Usage: mkshadow [-X exclude_file] [-x exclude_pattern] ... MASTER
+ * Makes the current directory be a "shadow copy" of MASTER.
+ * Sort of like a recursive copy of MASTER to .
+ * However, symbolic links are used instead of actually
+ * copying (non-directory) files.
+ * Also, directories named RCS or SCCS are shared (with a symbolic link).
+ * Warning messages are printed for files (and directories) in .
+ * that don't match a corresponding file in MASTER (though
+ * symbolic links are silently removed).
+ * Also, a warning message is printed for non-directory files
+ * under . that are not symbolic links.
+ *
+ * Files and directories can be excluded from the sharing
+ * with the -X and -x flags. The flag `-x pattern' (or `-xpattern')
+ * means that mkshadow should ignore any file whose name matches
+ * the pattern. The pattern is a "globbing" pattern, i.e. the
+ * characters *?[^-] are interpreted as by the shell.
+ * If the pattern contains a '/' is is matched against the complete
+ * current path (relative to '.'); otherwise, it is matched
+ * against the last component of the path.
+ * A `-X filename' flag means to read a set of exclusion patterns
+ * from the named file, one pattern to a line.
+
+Author: Per Bothner. bothner@cygnus.com. November 1990, 1993.
diff --git a/nx-X11/config/util/mkshadow/mkshadow.c b/nx-X11/config/util/mkshadow/mkshadow.c
new file mode 100644
index 000000000..d9c5eb841
--- /dev/null
+++ b/nx-X11/config/util/mkshadow/mkshadow.c
@@ -0,0 +1,378 @@
+/* $Xorg: mkshadow.c,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ */
+/* mkshadow.c - make a "shadow copy" of a directory tree with symlinks.
+ Copyright 1990, 1993 Free Software Foundation, Inc.
+
+ Permission to use, copy, modify, and distribute this program for
+ any purpose and without fee is hereby granted, provided that this
+ copyright and permission notice appear on all copies, and that
+ notice be given that copying and distribution is by permission of
+ the Free Software Foundation. The Free Software Foundation makes
+ no representations about the suitability of this software for any
+ purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ (The FSF has modified its usual distribution terms, for this file,
+ as a courtesy to the X project.) */
+
+/*
+ * Usage: mkshadow [-X exclude_file] [-x exclude_pattern] ... MASTER [SHADOW]
+ * Makes SHADOW be a "shadow copy" of MASTER. SHADOW defaults to the current
+ * directory. Sort of like a recursive copy of MASTER to SHADOW.
+ * However, symbolic links are used instead of actually
+ * copying (non-directory) files.
+ * Also, directories named RCS or SCCS are shared (with a symbolic link).
+ * Warning messages are printed for files (and directories) in .
+ * that don't match a corresponding file in MASTER (though
+ * symbolic links are silently removed).
+ * Also, a warning message is printed for non-directory files
+ * under SHADOW that are not symbolic links.
+ *
+ * Files and directories can be excluded from the sharing
+ * with the -X and -x flags. The flag `-x pattern' (or `-xpattern')
+ * means that mkshadow should ignore any file whose name matches
+ * the pattern. The pattern is a "globbing" pattern, i.e. the
+ * characters *?[^-] are interpreted as by the shell.
+ * If the pattern contains a '/' is is matched against the complete
+ * current path (relative to '.'); otherwise, it is matched
+ * against the last component of the path.
+ * A `-X filename' flag means to read a set of exclusion patterns
+ * from the named file, one pattern to a line.
+ *
+ * Originally written by Per Bothner at University of Wisconsin-Madison,
+ * inspired by the lndir script distributed with X11.
+ * Modified by Per Bothner <bothner@cygnus.com> November 1993
+ * to more-or-less follow Posix.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#ifdef BSD
+#include <strings.h>
+#define strchr index
+#else
+#include <string.h>
+#endif
+#include <sys/stat.h>
+#if defined(S_IFDIR) && !defined(S_ISDIR)
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if defined(S_IFLNK) && !defined(S_ISLNK)
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+extern char * savedir();
+
+fatal(msg)
+ char *msg;
+{
+ if (errno) perror(msg ? msg : "");
+ else if (msg) fprintf(stderr, "mkshadow: %s\n", msg);
+ exit(-1);
+}
+
+/* When handling symbolic links to relative directories,
+ * we need to prepend "../" to the "source".
+ * We preallocate MAX_DEPTH repetations of "../" using a simple trick.
+ */
+#define MAX_DEPTH 20
+#define PREPEND_BUFFER_SIZE (MAX_DEPTH*3)
+char master_buffer[MAXPATHLEN+PREPEND_BUFFER_SIZE] =
+ "../../../../../../../../../../../../../../../../../../../../";
+/* The logical start of the master_buffer is defined by
+ * master_start, which skips the fixed prepend area.
+ */
+#define master_start (master_buffer+PREPEND_BUFFER_SIZE)
+char shadow_buffer[MAXPATHLEN];
+
+void bad_args(msg)
+{
+ if (msg) fprintf(stderr, "%s\n", msg);
+ fprintf (stderr, "usage: mkshadow [-X exclude_file] [-x exclude_pattern]");
+ fprintf (stderr, " master [shadow]\n");
+ exit(-1);
+}
+
+int exclude_count = 0;
+char **exclude_patterns = NULL;
+int exclude_limit = 0;
+
+void add_exclude(pattern)
+ char *pattern;
+{
+ if (exclude_limit == 0) {
+ exclude_limit = 100;
+ exclude_patterns = (char**)malloc(exclude_limit * sizeof(char*));
+ } else if (exclude_count + 1 >= exclude_limit) {
+ exclude_limit += 100;
+ exclude_patterns = (char**)realloc(exclude_patterns,
+ exclude_limit * sizeof(char*));
+ }
+ exclude_patterns[exclude_count] = pattern;
+ exclude_count++;
+}
+
+void add_exclude_file(name)
+ char *name;
+{
+ char buf[MAXPATHLEN];
+ FILE *file = fopen(name, "r");
+ if (file == NULL) fatal("failed to find -X (exclude) file");
+ for (;;) {
+ int len;
+ char *str = fgets(buf, MAXPATHLEN, file);
+ if (str == NULL) break;
+ len = strlen(str);
+ if (len && str[len-1] == '\n') str[--len] = 0;
+ if (!len) continue;
+ str = (char*)malloc(len+1);
+ strcpy(str, buf);
+ add_exclude(str);
+ }
+ fclose(file);
+}
+
+main(argc, argv)
+ char **argv;
+{
+ char *master_name = NULL;
+ char *shadow_name = NULL;
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ switch(argv[i][1]) {
+ case 'X':
+ if (argv[i][2]) add_exclude_file(&argv[i][2]);
+ else if (++i >= argc) bad_args(NULL);
+ else add_exclude_file(argv[i]);
+ break;
+ case 'x':
+ if (argv[i][2]) add_exclude(&argv[i][2]);
+ else if (++i >= argc) bad_args(NULL);
+ else add_exclude(argv[i]);
+ break;
+ default:
+ bad_args(NULL);
+ }
+ } else if (master_name == NULL)
+ master_name = argv[i];
+ else if (shadow_name == NULL)
+ shadow_name = argv[i];
+ else bad_args (NULL);
+ }
+
+ if (master_name == NULL) bad_args(NULL);
+ if (shadow_name == NULL)
+ shadow_name = ".";
+ else if ((shadow_name[0] != '.' || shadow_name[1])
+ && master_name[0] != '/') {
+ fprintf(stderr, "Shadowing a relative directory pathname to a \n");
+ fprintf(stderr, "shadow other than '.' is not supported!\n");
+ exit(-1);
+ }
+ strcpy(shadow_buffer, shadow_name);
+ strcpy(master_start, master_name);
+ DoCopy(master_start, shadow_buffer, 0);
+ return 0;
+}
+
+int compare_strings(ptr1, ptr2)
+ char **ptr1, **ptr2;
+{
+ return strcmp(*ptr1, *ptr2);
+}
+
+void MakeLink(master, current, depth)
+ char *master;
+ char *current;
+ int depth;
+{
+ if (master[0] != '/') {
+ /* Source directory was specified with a relative pathname. */
+ if (master != master_start) {
+ fatal("Internal bug: bad string buffer use");
+ }
+ /* Pre-pend "../" depth times. This compensates for
+ * the directories we've entered. */
+ master -= 3 * depth;
+ }
+ if (symlink(master, current)) {
+ fprintf(stderr, "Failed to create symbolic link %s->%s\n",
+ current, master);
+ exit (-1);
+ }
+}
+
+
+/* Get a sorted NULL_terminator array of (char*) using 'names'
+ * (created by save_dir) as data.
+ */
+char ** get_name_pointers(names)
+ char *names;
+{
+ int n_names = 0;
+ int names_buf_size = 64;
+ char *namep;
+ char ** pointers = (char**)malloc(names_buf_size * sizeof(char*));
+ if (!names || !pointers) fatal("virtual memory exhausted");
+
+ for (namep = names; *namep; namep += strlen(namep) + 1) {
+ if (n_names + 1 >= names_buf_size) {
+ names_buf_size *= 2;
+ pointers = (char**)realloc(pointers,
+ names_buf_size * sizeof(char*));
+ if (!pointers) fatal("virtual memory exhausted");
+ }
+ pointers[n_names++] = namep;
+ }
+ pointers[n_names] = 0;
+ qsort(pointers, n_names, sizeof(char*), compare_strings);
+ return pointers;
+}
+
+/* Recursively shadow the directory whose name is in MASTER
+ * (which is == MASTER_START) into the destination directory named CURRENT.
+ */
+
+DoCopy(master, current, depth)
+ char *master; /* The source directory. */
+ char *current; /* The destination directory. */
+ int depth;
+{
+ struct stat stat_master, stat_current;
+ char **master_pointer, **current_pointer;
+ char **master_names, **current_names;
+ char *master_end, *current_end;
+ char *master_name_buf, *current_name_buf;
+ master_end = master + strlen(master);
+ current_end = current + strlen(current);
+
+ /* Get rid of terminal '/' */
+ if (master_end[-1] == '/' && master != master_end - 1)
+ *--master_end = 0;
+ if (current_end[-1] == '/' && current != current_end - 1)
+ *--current_end = 0;
+
+ if (depth >= MAX_DEPTH) {
+ fprintf(stderr,
+ "Nesting too deep (depth %d at %s). Probable circularity.\n",
+ depth, master);
+ exit(-1);
+ }
+
+ master_name_buf = savedir(master, 500);
+ if (master_name_buf == NULL) {
+ fprintf(stderr, "Not enough memory or no such directory: %s\n",
+ master);
+ exit(-1);
+ }
+ current_name_buf = savedir(current, 500);
+ if (current_name_buf == NULL) {
+ fprintf(stderr, "Not enough memory or no such directory: %s\n",
+ current);
+ exit(-1);
+ }
+
+ master_names = get_name_pointers(master_name_buf);
+ current_names = get_name_pointers(current_name_buf);
+
+ master_pointer = master_names;
+ current_pointer = current_names;
+ for (;;) {
+ int cmp, ipat;
+ int in_master, in_current;
+ char *cur_name;
+ if (*master_pointer == NULL && *current_pointer == NULL)
+ break;
+ if (*master_pointer == NULL) cmp = 1;
+ else if (*current_pointer == NULL) cmp = -1;
+ else cmp = strcmp(*master_pointer, *current_pointer);
+ if (cmp < 0) { /* file only exists in master directory */
+ in_master = 1; in_current = 0;
+ } else if (cmp == 0) { /* file exists in both directories */
+ in_master = 1; in_current = 1;
+ } else { /* file only exists in current directory */
+ in_current = 1; in_master = 0;
+ }
+ cur_name = in_master ? *master_pointer : *current_pointer;
+ sprintf(master_end, "/%s", cur_name);
+ sprintf(current_end, "/%s", cur_name);
+ for (ipat = 0; ipat < exclude_count; ipat++) {
+ char *pat = exclude_patterns[ipat];
+ char *cur;
+ if (strchr(pat, '/')) cur = current + 2; /* Skip initial "./" */
+ else cur = cur_name;
+ if (wildmat(cur, pat)) goto skip;
+ }
+ if (in_master)
+ if (lstat(master, &stat_master) != 0) fatal("stat failed");
+ if (in_current)
+ if (lstat(current, &stat_current) != 0) fatal("stat failed");
+ if (in_current && !in_master) {
+ if (S_ISLNK(stat_current.st_mode))
+ if (unlink(current)) {
+ fprintf(stderr, "Failed to remove symbolic link %s.\n",
+ current);
+ }
+ else
+ fprintf(stderr, "Removed symbolic link %s.\n",
+ current);
+ else {
+ fprintf(stderr,
+ "The file %s does not exist in the master tree.\n",
+ current);
+ }
+ }
+ else if (S_ISDIR(stat_master.st_mode)
+ && strcmp(cur_name, "RCS") != 0
+ && strcmp(cur_name, "SCCS") != 0) {
+ if (!in_current) {
+ if (mkdir(current, 0775)) fatal("mkdir failed");
+ }
+ else if (stat(current, &stat_current)) fatal("stat failed");
+ if (!in_current || stat_current.st_dev != stat_master.st_dev
+ || stat_current.st_ino != stat_master.st_ino)
+ DoCopy(master, current, depth+1);
+ else
+ fprintf(stderr, "Link %s is the same as directory %s.\n",
+ current, master);
+ }
+ else {
+ if (!in_current)
+ MakeLink(master, current, depth);
+ else if (!S_ISLNK(stat_current.st_mode)) {
+ fprintf(stderr, "Existing file %s is not a symbolic link.\n",
+ current);
+ } else {
+ if (stat(current, &stat_current) || stat(master, &stat_master))
+ fatal("stat failed");
+ if (stat_current.st_dev != stat_master.st_dev
+ || stat_current.st_ino != stat_master.st_ino) {
+ fprintf(stderr, "Fixing incorrect symbolic link %s.\n",
+ current);
+ if (unlink(current)) {
+ fprintf(stderr, "Failed to remove symbolic link %s.\n",
+ current);
+ }
+ else
+ MakeLink(master, current, depth);
+ }
+ }
+ }
+ skip:
+ if (in_master) master_pointer++;
+ if (in_current) current_pointer++;
+ }
+
+ free(master_names); free(current_names);
+ free(master_name_buf); free(current_name_buf);
+}
diff --git a/nx-X11/config/util/mkshadow/savedir.c b/nx-X11/config/util/mkshadow/savedir.c
new file mode 100644
index 000000000..6629f5a8d
--- /dev/null
+++ b/nx-X11/config/util/mkshadow/savedir.c
@@ -0,0 +1,119 @@
+/* $Xorg: savedir.c,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ */
+/* savedir.c -- save the list of files in a directory in a string
+ Copyright 1990, 1993 Free Software Foundation, Inc.
+
+ Permission to use, copy, modify, and distribute this program for
+ any purpose and without fee is hereby granted, provided that this
+ copyright and permission notice appear on all copies, and that
+ notice be given that copying and distribution is by permission of
+ the Free Software Foundation. The Free Software Foundation makes
+ no representations about the suitability of this software for any
+ purpose. It is provided "as is" without expressed or implied
+ warranty.
+
+ (The FSF has modified its usual distribution terms, for this file,
+ as a courtesy to the X project.) */
+
+/* $XFree86$ */
+
+/* Written by David MacKenzie <djm@ai.mit.edu>.
+ Modified to use <dirent.h> by default. Per Bothner <bothner@cygnus.com>. */
+
+#include <sys/types.h>
+#if !defined(DIRECT) && !defined(BSD)
+#include <dirent.h>
+#define NLENGTH(direct) (strlen((direct)->d_name))
+#else
+#undef dirent
+#define dirent direct
+#define NLENGTH(direct) ((direct)->d_namlen)
+#ifdef BSD
+#include <sys/dir.h>
+#else
+#ifdef SYSNDIR
+#include <sys/ndir.h>
+#else
+#include <ndir.h>
+#endif
+#endif
+#endif
+
+#if defined(VOID_CLOSEDIR) || defined(BSD)
+/* Fake a return value. */
+#define CLOSEDIR(d) (closedir (d), 0)
+#else
+#define CLOSEDIR(d) closedir (d)
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+char *stpcpy ();
+
+/* Return a freshly allocated string containing the filenames
+ in directory DIR, separated by '\0' characters;
+ the end is marked by two '\0' characters in a row.
+ NAME_SIZE is the number of bytes to initially allocate
+ for the string; it will be enlarged as needed.
+ Return NULL if DIR cannot be opened or if out of memory. */
+
+char *
+savedir (dir, name_size)
+ char *dir;
+ unsigned name_size;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char *name_space;
+ char *namep;
+
+ dirp = opendir (dir);
+ if (dirp == NULL)
+ return NULL;
+
+ name_space = (char *) malloc (name_size);
+ if (name_space == NULL)
+ {
+ closedir (dirp);
+ return NULL;
+ }
+ namep = name_space;
+
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ /* Skip "." and ".." (some NFS filesystems' directories lack them). */
+ if (dp->d_name[0] != '.'
+ || (dp->d_name[1] != '\0'
+ && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
+ {
+ unsigned size_needed = (namep - name_space) + NLENGTH (dp) + 2;
+
+ if (size_needed > name_size)
+ {
+ char *new_name_space;
+
+ while (size_needed > name_size)
+ name_size += 1024;
+
+ new_name_space = realloc (name_space, name_size);
+ if (new_name_space == NULL)
+ {
+ closedir (dirp);
+ return NULL;
+ }
+ namep += new_name_space - name_space;
+ name_space = new_name_space;
+ }
+ strcpy (namep, dp->d_name);
+ namep += strlen (namep) + 1;
+ }
+ }
+ *namep = '\0';
+ if (CLOSEDIR (dirp))
+ {
+ free (name_space);
+ return NULL;
+ }
+ return name_space;
+}
diff --git a/nx-X11/config/util/mkshadow/wildmat.c b/nx-X11/config/util/mkshadow/wildmat.c
new file mode 100644
index 000000000..8e0c179eb
--- /dev/null
+++ b/nx-X11/config/util/mkshadow/wildmat.c
@@ -0,0 +1,167 @@
+/* $Xorg: wildmat.c,v 1.3 2000/08/17 19:41:53 cpqbld Exp $ */
+/*
+**
+** Do shell-style pattern matching for ?, \, [], and * characters.
+** Might not be robust in face of malformed patterns; e.g., "foo[a-"
+** could cause a segmentation violation. It is 8bit clean.
+**
+** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+** Rich $alz is now <rsalz@bbn.com>.
+** April, 1991: Replaced mutually-recursive calls with in-line code
+** for the star character.
+**
+** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
+** This can greatly speed up failing wildcard patterns. For example:
+** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
+** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
+** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
+** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without
+** the ABORT, then it takes 22310 calls to fail. Ugh. The following
+** explanation is from Lars:
+** The precondition that must be fulfilled is that DoMatch will consume
+** at least one character in text. This is true if *p is neither '*' nor
+** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic
+** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With
+** FALSE, each star-loop has to run to the end of the text; with ABORT
+** only the last one does.
+**
+** Once the control of one instance of DoMatch enters the star-loop, that
+** instance will return either TRUE or ABORT, and any calling instance
+** will therefore return immediately after (without calling recursively
+** again). In effect, only one star-loop is ever active. It would be
+** possible to modify the code to maintain this context explicitly,
+** eliminating all recursive calls at the cost of some complication and
+** loss of clarity (and the ABORT stuff seems to be unclear enough by
+** itself). I think it would be unwise to try to get this into a
+** released version unless you have a good test data base to try it out
+** on.
+*/
+
+#define TRUE 1
+#define FALSE 0
+#define ABORT -1
+
+
+ /* What character marks an inverted character class? */
+#define NEGATE_CLASS '^'
+ /* Is "*" a common pattern? */
+#define OPTIMIZE_JUST_STAR
+ /* Do tar(1) matching rules, which ignore a trailing slash? */
+#undef MATCH_TAR_PATTERN
+
+
+/*
+** Match text and p, return TRUE, FALSE, or ABORT.
+*/
+static int
+DoMatch(text, p)
+ register char *text;
+ register char *p;
+{
+ register int last;
+ register int matched;
+ register int reverse;
+
+ for ( ; *p; text++, p++) {
+ if (*text == '\0' && *p != '*')
+ return ABORT;
+ switch (*p) {
+ case '\\':
+ /* Literal match with following character. */
+ p++;
+ /* FALLTHROUGH */
+ default:
+ if (*text != *p)
+ return FALSE;
+ continue;
+ case '?':
+ /* Match anything. */
+ continue;
+ case '*':
+ while (*++p == '*')
+ /* Consecutive stars act just like one. */
+ continue;
+ if (*p == '\0')
+ /* Trailing star matches everything. */
+ return TRUE;
+ while (*text)
+ if ((matched = DoMatch(text++, p)) != FALSE)
+ return matched;
+ return ABORT;
+ case '[':
+ reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
+ if (reverse)
+ /* Inverted character class. */
+ p++;
+ for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
+ /* This next line requires a good C compiler. */
+ if (*p == '-' ? *text <= *++p && *text >= last : *text == *p)
+ matched = TRUE;
+ if (matched == reverse)
+ return FALSE;
+ continue;
+ }
+ }
+
+#ifdef MATCH_TAR_PATTERN
+ if (*text == '/')
+ return TRUE;
+#endif /* MATCH_TAR_ATTERN */
+ return *text == '\0';
+}
+
+
+/*
+** User-level routine. Returns TRUE or FALSE.
+*/
+int
+wildmat(text, p)
+ char *text;
+ char *p;
+{
+#ifdef OPTIMIZE_JUST_STAR
+ if (p[0] == '*' && p[1] == '\0')
+ return TRUE;
+#endif /* OPTIMIZE_JUST_STAR */
+ return DoMatch(text, p) == TRUE;
+}
+
+
+
+#ifdef TEST
+#include <stdio.h>
+
+/* Yes, we use gets not fgets. Sue me. */
+extern char *gets();
+
+
+main()
+{
+ char p[80];
+ char text[80];
+
+ printf("Wildmat tester. Enter pattern, then strings to test.\n");
+ printf("A blank line gets prompts for a new pattern; a blank pattern\n");
+ printf("exits the program.\n");
+
+ for ( ; ; ) {
+ printf("\nEnter pattern: ");
+ (void)fflush(stdout);
+ if (gets(p) == NULL || p[0] == '\0')
+ break;
+ for ( ; ; ) {
+ printf("Enter text: ");
+ (void)fflush(stdout);
+ if (gets(text) == NULL)
+ exit(0);
+ if (text[0] == '\0')
+ /* Blank line; go back and get a new pattern. */
+ break;
+ printf(" %s\n", wildmat(text, p) ? "YES" : "NO");
+ }
+ }
+
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* TEST */