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.
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.
25 The expargs code is a modification of wildcard expansion code
26 written for Turbo C 1.0 by
28 Texas Instruments, Inc.
29 P.O. Box 869305, m/s 8473
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. */
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 **);
68 main (int argc
, char **argv
, char **envp
)
70 argv
= expargs (&argc
, argv
);
71 return _main (argc
, argv
, envp
);
75 expargs (int *pargc
, char **argv
)
77 char path
[MAXPATH
+ 1];
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];
94 for (argind
= 1; argind
< *pargc
; ++argind
)
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
))
109 /* Only match "." and ".." explicitly. */
110 if (*block
.ff_name
== '.' && *arg_base
!= '.')
112 path_length
= stpcpy (path_base
, block
.ff_name
) - path
+ 1;
114 if (wild_match (path
, argv
[argind
]))
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
));
127 new_argv
[new_argc
++] = argv
[argind
];
128 new_argv
= grow_argv (new_argv
, new_argc
);
132 new_argv
[new_argc
] = NULL
;
136 /* Return a pointer to the last element of PATH. */
139 basename (char *path
)
143 for (tail
= path
; *path
; ++path
)
144 if (*path
== ':' || *path
== '\\')
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");
163 fatal_error (const char *message
)
166 if (program_name
&& *program_name
)
168 fputs (program_name
, stderr
);
169 fputs (": ", stderr
);
171 fputs (message
, stderr
);
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 '^'. */
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
++)
200 /* Literal match with following character; fall through. */
203 if (*string
!= *pattern
)
207 /* Match anything. */
212 /* Trailing star matches everything. */
213 return *++pattern
? star (string
, pattern
) : 1;
215 /* Check for inverse character class. */
216 reverse
= pattern
[1] == INVERT
;
219 for (prev
= 256, matched
= 0; *++pattern
&& *pattern
!= ']';
222 ? *string
<= *++pattern
&& *string
>= prev
223 : *string
== *pattern
)
225 if (matched
== reverse
)
230 return *string
== '\0';
234 star (char *string
, char *pattern
)
236 while (wild_match (string
, pattern
) == 0)
237 if (*++string
== '\0')