Fix a typo
[tar/ericb.git] / src / tcexparg.c
blobc5d88f069bf5ad39258079b455bc8272aeebe5f5
1 /* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0
3 This file is in the public domain.
5 Compile your main program with -Dmain=_main and link with this file.
7 After that, it is just as if the operating system had expanded the
8 arguments, except that they are not sorted. The program name and all
9 arguments that are expanded from wildcards are lowercased.
11 Syntax for wildcards:
12 * Matches zero or more of any character (except a '.' at
13 the beginning of a name).
14 ? Matches any single character.
15 [r3z] Matches 'r', '3', or 'z'.
16 [a-d] Matches a single character in the range 'a' through 'd'.
17 [!a-d] Matches any single character except a character in the
18 range 'a' through 'd'.
20 The period between the filename root and its extension need not be
21 given explicitly. Thus, the pattern `a*e' will match 'abacus.exe'
22 and 'axyz.e' as well as 'apple'. Comparisons are not case sensitive.
24 Authors:
25 The expargs code is a modification of wildcard expansion code
26 written for Turbo C 1.0 by
27 Richard Hargrove
28 Texas Instruments, Inc.
29 P.O. Box 869305, m/s 8473
30 Plano, Texas 75086
31 214/575-4128
32 and posted to USENET in September, 1987.
34 The wild_match code was written by Rich Salz, rsalz@bbn.com,
35 posted to net.sources in November, 1986.
37 The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
38 posted to comp.sys.ibm.pc in November, 1988.
40 Major performance enhancements and bug fixes, and source cleanup,
41 by David MacKenzie, djm@gnu.ai.mit.edu. */
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <dos.h>
47 #include <dir.h>
49 /* Number of new arguments to allocate space for at a time. */
50 #define ARGS_INCREMENT 10
52 /* The name this program was run with, for error messages. */
53 static char *program_name;
55 static char **grow_argv (char **new_argv, int new_argc);
56 static void fatal_error (const char *message);
58 int wild_match (char *string, char *pattern);
59 char *basename (char *path);
61 char **expargs (int *, char **);
63 #ifdef main
64 #undef main
65 #endif
67 int
68 main (int argc, char **argv, char **envp)
70 argv = expargs (&argc, argv);
71 return _main (argc, argv, envp);
74 char **
75 expargs (int *pargc, char **argv)
77 char path[MAXPATH + 1];
78 char **new_argv;
79 struct ffblk block;
80 char *path_base;
81 char *arg_base;
82 int argind;
83 int new_argc;
84 int path_length;
85 int matched;
87 program_name = argv[0];
88 if (program_name && *program_name)
89 strlwr (program_name);
90 new_argv = grow_argv (NULL, 0);
91 new_argv[0] = argv[0];
92 new_argc = 1;
94 for (argind = 1; argind < *pargc; ++argind)
96 matched = 0;
97 if (strpbrk (argv[argind], "?*[") != NULL)
99 strncpy (path, argv[argind], MAXPATH - 3);
100 path_base = basename (path);
101 strcpy (path_base, "*.*");
102 arg_base = argv[argind] + (path_base - path);
104 if (!findfirst (path, &block, FA_DIREC))
106 strlwr (path);
109 /* Only match "." and ".." explicitly. */
110 if (*block.ff_name == '.' && *arg_base != '.')
111 continue;
112 path_length = stpcpy (path_base, block.ff_name) - path + 1;
113 strlwr (path_base);
114 if (wild_match (path, argv[argind]))
116 matched = 1;
117 new_argv[new_argc] = (char *) malloc (path_length);
118 if (new_argv[new_argc] == NULL)
119 fatal_error ("memory exhausted");
120 strcpy (new_argv[new_argc++], path);
121 new_argv = grow_argv (new_argv, new_argc);
123 } while (!findnext (&block));
126 if (matched == 0)
127 new_argv[new_argc++] = argv[argind];
128 new_argv = grow_argv (new_argv, new_argc);
131 *pargc = new_argc;
132 new_argv[new_argc] = NULL;
133 return &new_argv[0];
136 /* Return a pointer to the last element of PATH. */
138 char *
139 basename (char *path)
141 char *tail;
143 for (tail = path; *path; ++path)
144 if (*path == ':' || *path == '\\')
145 tail = path + 1;
146 return tail;
149 static char **
150 grow_argv (char **new_argv, int new_argc)
152 if (new_argc % ARGS_INCREMENT == 0)
154 new_argv = (char **) realloc
155 (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT));
156 if (new_argv == NULL)
157 fatal_error ("memory exhausted");
159 return new_argv;
162 static void
163 fatal_error (const char *message)
165 putc ('\n', stderr);
166 if (program_name && *program_name)
168 fputs (program_name, stderr);
169 fputs (": ", stderr);
171 fputs (message, stderr);
172 putc ('\n', stderr);
173 exit (1);
176 /* Shell-style pattern matching for ?, \, [], and * characters.
177 I'm putting this replacement in the public domain.
179 Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */
181 /* The character that inverts a character class; '!' or '^'. */
182 #define INVERT '!'
184 static int star (char *string, char *pattern);
186 /* Return nonzero if `string' matches Unix-style wildcard pattern
187 `pattern'; zero if not. */
190 wild_match (char *string, char *pattern)
192 int prev; /* Previous character in character class. */
193 int matched; /* If 1, character class has been matched. */
194 int reverse; /* If 1, character class is inverted. */
196 for (; *pattern; string++, pattern++)
197 switch (*pattern)
199 case '\\':
200 /* Literal match with following character; fall through. */
201 pattern++;
202 default:
203 if (*string != *pattern)
204 return 0;
205 continue;
206 case '?':
207 /* Match anything. */
208 if (*string == '\0')
209 return 0;
210 continue;
211 case '*':
212 /* Trailing star matches everything. */
213 return *++pattern ? star (string, pattern) : 1;
214 case '[':
215 /* Check for inverse character class. */
216 reverse = pattern[1] == INVERT;
217 if (reverse)
218 pattern++;
219 for (prev = 256, matched = 0; *++pattern && *pattern != ']';
220 prev = *pattern)
221 if (*pattern == '-'
222 ? *string <= *++pattern && *string >= prev
223 : *string == *pattern)
224 matched = 1;
225 if (matched == reverse)
226 return 0;
227 continue;
230 return *string == '\0';
233 static int
234 star (char *string, char *pattern)
236 while (wild_match (string, pattern) == 0)
237 if (*++string == '\0')
238 return 0;
239 return 1;