]> Dogcows Code - chaz/tar/blob - src/tcexparg.c
Fix Solaris bug where chmod fails if we don't have PRIV_SYS_LINKDIR
[chaz/tar] / src / tcexparg.c
1 /* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0
2
3 This file is in the public domain.
4
5 Compile your main program with -Dmain=_main and link with this file.
6
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.
10
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'.
19
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.
23
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.
33
34 The wild_match code was written by Rich Salz, rsalz@bbn.com,
35 posted to net.sources in November, 1986.
36
37 The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
38 posted to comp.sys.ibm.pc in November, 1988.
39
40 Major performance enhancements and bug fixes, and source cleanup,
41 by David MacKenzie, djm@gnu.ai.mit.edu. */
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <dos.h>
47 #include <dir.h>
48
49 /* Number of new arguments to allocate space for at a time. */
50 #define ARGS_INCREMENT 10
51
52 /* The name this program was run with, for error messages. */
53 static char *program_name;
54
55 static char **grow_argv (char **new_argv, int new_argc);
56 static void fatal_error (const char *message);
57
58 int wild_match (char *string, char *pattern);
59 char *basename (char *path);
60
61 char **expargs (int *, char **);
62
63 #ifdef main
64 #undef main
65 #endif
66
67 int
68 main (int argc, char **argv, char **envp)
69 {
70 argv = expargs (&argc, argv);
71 return _main (argc, argv, envp);
72 }
73
74 char **
75 expargs (int *pargc, char **argv)
76 {
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;
86
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;
93
94 for (argind = 1; argind < *pargc; ++argind)
95 {
96 matched = 0;
97 if (strpbrk (argv[argind], "?*[") != NULL)
98 {
99 strncpy (path, argv[argind], MAXPATH - 3);
100 path_base = basename (path);
101 strcpy (path_base, "*.*");
102 arg_base = argv[argind] + (path_base - path);
103
104 if (!findfirst (path, &block, FA_DIREC))
105 {
106 strlwr (path);
107 do
108 {
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]))
115 {
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);
122 }
123 } while (!findnext (&block));
124 }
125 }
126 if (matched == 0)
127 new_argv[new_argc++] = argv[argind];
128 new_argv = grow_argv (new_argv, new_argc);
129 }
130
131 *pargc = new_argc;
132 new_argv[new_argc] = NULL;
133 return &new_argv[0];
134 }
135
136 /* Return a pointer to the last element of PATH. */
137
138 char *
139 basename (char *path)
140 {
141 char *tail;
142
143 for (tail = path; *path; ++path)
144 if (*path == ':' || *path == '\\')
145 tail = path + 1;
146 return tail;
147 }
148
149 static char **
150 grow_argv (char **new_argv, int new_argc)
151 {
152 if (new_argc % ARGS_INCREMENT == 0)
153 {
154 new_argv = (char **) realloc
155 (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT));
156 if (new_argv == NULL)
157 fatal_error ("memory exhausted");
158 }
159 return new_argv;
160 }
161
162 static void
163 fatal_error (const char *message)
164 {
165 putc ('\n', stderr);
166 if (program_name && *program_name)
167 {
168 fputs (program_name, stderr);
169 fputs (": ", stderr);
170 }
171 fputs (message, stderr);
172 putc ('\n', stderr);
173 exit (1);
174 }
175
176 /* Shell-style pattern matching for ?, \, [], and * characters.
177 I'm putting this replacement in the public domain.
178
179 Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */
180
181 /* The character that inverts a character class; '!' or '^'. */
182 #define INVERT '!'
183
184 static int star (char *string, char *pattern);
185
186 /* Return nonzero if `string' matches Unix-style wildcard pattern
187 `pattern'; zero if not. */
188
189 int
190 wild_match (char *string, char *pattern)
191 {
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. */
195
196 for (; *pattern; string++, pattern++)
197 switch (*pattern)
198 {
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;
228 }
229
230 return *string == '\0';
231 }
232
233 static int
234 star (char *string, char *pattern)
235 {
236 while (wild_match (string, pattern) == 0)
237 if (*++string == '\0')
238 return 0;
239 return 1;
240 }
This page took 0.045471 seconds and 4 git commands to generate.