diff options
-rw-r--r-- | archival/ar.c | 4 | ||||
-rw-r--r-- | archival/libarchive/Kbuild.src | 1 | ||||
-rw-r--r-- | archival/libarchive/unpack_ar_archive.c | 8 | ||||
-rw-r--r-- | configs/mingw32_defconfig | 4 | ||||
-rw-r--r-- | configs/mingw64_defconfig | 4 | ||||
-rw-r--r-- | miscutils/make.c | 2621 | ||||
-rwxr-xr-x | testsuite/make.tests | 413 | ||||
-rw-r--r-- | win32/Kbuild | 1 | ||||
-rw-r--r-- | win32/glob.c | 343 | ||||
-rw-r--r-- | win32/glob.h | 89 |
10 files changed, 3482 insertions, 6 deletions
diff --git a/archival/ar.c b/archival/ar.c index beccab217..b5565c936 100644 --- a/archival/ar.c +++ b/archival/ar.c | |||
@@ -30,12 +30,12 @@ | |||
30 | //config:config FEATURE_AR_LONG_FILENAMES | 30 | //config:config FEATURE_AR_LONG_FILENAMES |
31 | //config: bool "Support long filenames (not needed for debs)" | 31 | //config: bool "Support long filenames (not needed for debs)" |
32 | //config: default y | 32 | //config: default y |
33 | //config: depends on AR | 33 | //config: depends on AR || MAKE |
34 | //config: help | 34 | //config: help |
35 | //config: By default the ar format can only store the first 15 characters | 35 | //config: By default the ar format can only store the first 15 characters |
36 | //config: of the filename, this option removes that limitation. | 36 | //config: of the filename, this option removes that limitation. |
37 | //config: It supports the GNU ar long filename method which moves multiple long | 37 | //config: It supports the GNU ar long filename method which moves multiple long |
38 | //config: filenames into a the data section of a new ar entry. | 38 | //config: filenames into the data section of a new ar entry. |
39 | //config: | 39 | //config: |
40 | //config:config FEATURE_AR_CREATE | 40 | //config:config FEATURE_AR_CREATE |
41 | //config: bool "Support archive creation" | 41 | //config: bool "Support archive creation" |
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src index d2f284b08..1c74250a2 100644 --- a/archival/libarchive/Kbuild.src +++ b/archival/libarchive/Kbuild.src | |||
@@ -47,6 +47,7 @@ lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) | |||
47 | 47 | ||
48 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o | 48 | lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o |
49 | lib-$(CONFIG_CPIO) += get_header_cpio.o | 49 | lib-$(CONFIG_CPIO) += get_header_cpio.o |
50 | lib-$(CONFIG_MAKE) += get_header_ar.o unpack_ar_archive.o | ||
50 | lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o | 51 | lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o |
51 | lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o | 52 | lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o |
52 | lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o | 53 | lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o |
diff --git a/archival/libarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c index 125d424c9..923a0b2ab 100644 --- a/archival/libarchive/unpack_ar_archive.c +++ b/archival/libarchive/unpack_ar_archive.c | |||
@@ -16,6 +16,10 @@ void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) | |||
16 | } | 16 | } |
17 | ar_archive->offset += AR_MAGIC_LEN; | 17 | ar_archive->offset += AR_MAGIC_LEN; |
18 | 18 | ||
19 | while (get_header_ar(ar_archive) == EXIT_SUCCESS) | 19 | while (get_header_ar(ar_archive) == EXIT_SUCCESS) { |
20 | continue; | 20 | #if ENABLE_MAKE |
21 | free(ar_archive->file_header->name); | ||
22 | ar_archive->file_header->name = NULL; | ||
23 | #endif | ||
24 | } | ||
21 | } | 25 | } |
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index 78e359500..81bbda4dd 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.36.0.git | 3 | # Busybox version: 1.36.0.git |
4 | # Thu May 12 08:13:00 2022 | 4 | # Thu Jul 7 08:08:14 2022 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -831,6 +831,8 @@ CONFIG_FEATURE_LESS_LINENUMS=y | |||
831 | CONFIG_FEATURE_LESS_RAW=y | 831 | CONFIG_FEATURE_LESS_RAW=y |
832 | CONFIG_FEATURE_LESS_ENV=y | 832 | CONFIG_FEATURE_LESS_ENV=y |
833 | # CONFIG_LSSCSI is not set | 833 | # CONFIG_LSSCSI is not set |
834 | CONFIG_MAKE=y | ||
835 | CONFIG_FEATURE_MAKE_POSIX=y | ||
834 | # CONFIG_MAKEDEVS is not set | 836 | # CONFIG_MAKEDEVS is not set |
835 | # CONFIG_FEATURE_MAKEDEVS_LEAF is not set | 837 | # CONFIG_FEATURE_MAKEDEVS_LEAF is not set |
836 | # CONFIG_FEATURE_MAKEDEVS_TABLE is not set | 838 | # CONFIG_FEATURE_MAKEDEVS_TABLE is not set |
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index c88da8007..0e54eb78d 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.36.0.git | 3 | # Busybox version: 1.36.0.git |
4 | # Thu May 12 08:13:00 2022 | 4 | # Thu Jul 7 08:08:14 2022 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -831,6 +831,8 @@ CONFIG_FEATURE_LESS_LINENUMS=y | |||
831 | CONFIG_FEATURE_LESS_RAW=y | 831 | CONFIG_FEATURE_LESS_RAW=y |
832 | CONFIG_FEATURE_LESS_ENV=y | 832 | CONFIG_FEATURE_LESS_ENV=y |
833 | # CONFIG_LSSCSI is not set | 833 | # CONFIG_LSSCSI is not set |
834 | CONFIG_MAKE=y | ||
835 | CONFIG_FEATURE_MAKE_POSIX=y | ||
834 | # CONFIG_MAKEDEVS is not set | 836 | # CONFIG_MAKEDEVS is not set |
835 | # CONFIG_FEATURE_MAKEDEVS_LEAF is not set | 837 | # CONFIG_FEATURE_MAKEDEVS_LEAF is not set |
836 | # CONFIG_FEATURE_MAKEDEVS_TABLE is not set | 838 | # CONFIG_FEATURE_MAKEDEVS_TABLE is not set |
diff --git a/miscutils/make.c b/miscutils/make.c new file mode 100644 index 000000000..b92819266 --- /dev/null +++ b/miscutils/make.c | |||
@@ -0,0 +1,2621 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * make implementation for BusyBox | ||
4 | * | ||
5 | * Based on public domain POSIX make: https://frippery.org/make | ||
6 | */ | ||
7 | //config:config MAKE | ||
8 | //config: bool "make (18 kb)" | ||
9 | //config: default n | ||
10 | //config: help | ||
11 | //config: The make command can be used to maintain files that depend on | ||
12 | //config: other files. Normally it's used to build programs from source | ||
13 | //config: code but it can be used in other situations too. | ||
14 | //config: | ||
15 | //config:config FEATURE_MAKE_POSIX | ||
16 | //config: bool "Runtime enforcement of POSIX" | ||
17 | //config: default n | ||
18 | //config: depends on MAKE | ||
19 | //config: help | ||
20 | //config: Allow strict enforcement of POSIX mode at runtime by: | ||
21 | //config: - .POSIX special target in makefile | ||
22 | //config: - '--posix' command line option | ||
23 | //config: - PDPMAKE_POSIXLY_CORRECT environment variable | ||
24 | //config: Enable this if you want to check whether your makefiles are | ||
25 | //config: POSIX compliant. This adds about 500 bytes. | ||
26 | |||
27 | //applet:IF_MAKE(APPLET(make, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
28 | |||
29 | //kbuild:lib-$(CONFIG_MAKE) += make.o | ||
30 | |||
31 | //usage:#define make_trivial_usage | ||
32 | //usage: IF_FEATURE_MAKE_POSIX( | ||
33 | //usage: "[--posix] [-C DIR] [-f FILE] [j NUM] [-eiknpqrsSt] [MACRO[::]=VAL]... [TARGET]..." | ||
34 | //usage: ) | ||
35 | //usage: IF_NOT_FEATURE_MAKE_POSIX( | ||
36 | //usage: "[-C DIR] [-f FILE] [j NUM] [-eiknpqrsSt] [MACRO[::]=VAL]... [TARGET]..." | ||
37 | //usage: ) | ||
38 | //usage:#define make_full_usage "\n\n" | ||
39 | //usage: "Maintain files based on their dependencies\n" | ||
40 | //usage: IF_FEATURE_MAKE_POSIX( | ||
41 | //usage: "\n --posix Enforce POSIX mode" | ||
42 | //usage: ) | ||
43 | //usage: "\n -C DIR Change to DIR" | ||
44 | //usage: "\n -f FILE Makefile" | ||
45 | //usage: "\n -j NUM Jobs to run in parallel (not implemented)" | ||
46 | //usage: "\n -e Environment variables override macros in makefiles" | ||
47 | //usage: "\n -i Ignore exit status" | ||
48 | //usage: "\n -k Continue on error" | ||
49 | //usage: "\n -n Dry run" | ||
50 | //usage: "\n -p Print macros and targets" | ||
51 | //usage: "\n -q Query target; exit status 1 if not up to date" | ||
52 | //usage: "\n -r Don't use built-in rules" | ||
53 | //usage: "\n -s Make silently" | ||
54 | //usage: "\n -S Stop on error" | ||
55 | //usage: "\n -t Touch files instead of making them" | ||
56 | |||
57 | #include "libbb.h" | ||
58 | #include "bb_archive.h" | ||
59 | #include "common_bufsiz.h" | ||
60 | #include <glob.h> | ||
61 | |||
62 | #define OPTSTR1 "eij:+knqrsSt" | ||
63 | #define OPTSTR2 "pf:*C:*" | ||
64 | |||
65 | enum { | ||
66 | OPT_e = (1 << 0), | ||
67 | OPT_i = (1 << 1), | ||
68 | OPT_j = (1 << 2), | ||
69 | OPT_k = (1 << 3), | ||
70 | OPT_n = (1 << 4), | ||
71 | OPT_q = (1 << 5), | ||
72 | OPT_r = (1 << 6), | ||
73 | OPT_s = (1 << 7), | ||
74 | OPT_S = (1 << 8), | ||
75 | OPT_t = (1 << 9), | ||
76 | // These options aren't allowed in MAKEFLAGS | ||
77 | OPT_p = (1 << 10), | ||
78 | OPT_f = (1 << 11), | ||
79 | OPT_C = (1 << 12), | ||
80 | // The following aren't command line options and must be last | ||
81 | OPT_precious = (1 << 13), | ||
82 | OPT_phony = (1 << 14), | ||
83 | OPT_include = (1 << 15), | ||
84 | OPT_make = (1 << 16), | ||
85 | }; | ||
86 | |||
87 | // Options in OPTSTR1 that aren't included in MAKEFLAGS | ||
88 | #define OPT_MASK (~OPT_S) | ||
89 | |||
90 | #define useenv (opts & OPT_e) | ||
91 | #define ignore (opts & OPT_i) | ||
92 | #define errcont (opts & OPT_k) | ||
93 | #define dryrun (opts & OPT_n) | ||
94 | #define print (opts & OPT_p) | ||
95 | #define quest (opts & OPT_q) | ||
96 | #define norules (opts & OPT_r) | ||
97 | #define silent (opts & OPT_s) | ||
98 | #define dotouch (opts & OPT_t) | ||
99 | #define precious (opts & OPT_precious) | ||
100 | #define doinclude (opts & OPT_include) | ||
101 | #define domake (opts & OPT_make) | ||
102 | |||
103 | // A name. This represents a file, either to be made, or pre-existing. | ||
104 | struct name { | ||
105 | struct name *n_next; // Next in the list of names | ||
106 | char *n_name; // Called | ||
107 | struct rule *n_rule; // Rules to build this (prerequisites/commands) | ||
108 | struct timespec n_tim; // Modification time of this name | ||
109 | uint16_t n_flag; // Info about the name | ||
110 | }; | ||
111 | |||
112 | #define N_DOING 0x01 // Name in process of being built | ||
113 | #define N_DONE 0x02 // Name looked at | ||
114 | #define N_TARGET 0x04 // Name is a target | ||
115 | #define N_PRECIOUS 0x08 // Target is precious | ||
116 | #define N_DOUBLE 0x10 // Double-colon target | ||
117 | #define N_SILENT 0x20 // Build target silently | ||
118 | #define N_IGNORE 0x40 // Ignore build errors | ||
119 | #define N_SPECIAL 0x80 // Special target | ||
120 | #define N_MARK 0x100 // Mark for deduplication | ||
121 | #define N_PHONY 0x200 // Name is a phony target | ||
122 | |||
123 | // List of rules to build a target | ||
124 | struct rule { | ||
125 | struct rule *r_next; // Next rule | ||
126 | struct depend *r_dep; // Prerequisites for this rule | ||
127 | struct cmd *r_cmd; // Commands for this rule | ||
128 | }; | ||
129 | |||
130 | // NOTE: the layout of the following two structures must be compatible. | ||
131 | // Also, their first two members must be compatible with llist_t. | ||
132 | |||
133 | // List of prerequisites for a rule | ||
134 | struct depend { | ||
135 | struct depend *d_next; // Next prerequisite | ||
136 | struct name *d_name; // Name of prerequisite | ||
137 | int d_refcnt; // Reference count | ||
138 | }; | ||
139 | |||
140 | // List of commands for a rule | ||
141 | struct cmd { | ||
142 | struct cmd *c_next; // Next command line | ||
143 | char *c_cmd; // Text of command line | ||
144 | int c_refcnt; // Reference count | ||
145 | }; | ||
146 | |||
147 | // Macro storage | ||
148 | struct macro { | ||
149 | struct macro *m_next; // Next variable | ||
150 | char *m_name; // Its name | ||
151 | char *m_val; // Its value | ||
152 | bool m_immediate; // Immediate-expansion macro set using ::= | ||
153 | bool m_flag; // Infinite loop check | ||
154 | uint8_t m_level; // Level at which macro was created | ||
155 | }; | ||
156 | |||
157 | // Flags passed to setmacro() | ||
158 | #define M_IMMEDIATE 8 // immediate-expansion macro is being defined | ||
159 | #define M_VALID 16 // assert macro name is valid | ||
160 | |||
161 | #define HTABSIZE 39 | ||
162 | |||
163 | struct globals { | ||
164 | uint32_t opts; | ||
165 | const char *makefile; | ||
166 | llist_t *makefiles; | ||
167 | llist_t *dirs; | ||
168 | struct name *namehead[HTABSIZE]; | ||
169 | struct macro *macrohead[HTABSIZE]; | ||
170 | struct name *firstname; | ||
171 | struct name *target; | ||
172 | time_t ar_mtime; | ||
173 | int lineno; // Physical line number in file | ||
174 | int dispno; // Line number for display purposes | ||
175 | const char *rulepos; | ||
176 | #define IF_MAX 10 | ||
177 | uint8_t clevel; | ||
178 | uint8_t cstate[IF_MAX + 1]; | ||
179 | #if ENABLE_FEATURE_MAKE_POSIX | ||
180 | bool posix; | ||
181 | bool seen_first; | ||
182 | #endif | ||
183 | int numjobs; | ||
184 | } FIX_ALIASING; | ||
185 | |||
186 | #define G (*(struct globals*)bb_common_bufsiz1) | ||
187 | #define INIT_G() do { \ | ||
188 | setup_common_bufsiz(); \ | ||
189 | } while (0) | ||
190 | |||
191 | #define opts (G.opts) | ||
192 | #define makefile (G.makefile) | ||
193 | #define makefiles (G.makefiles) | ||
194 | #define dirs (G.dirs) | ||
195 | #define namehead (G.namehead) | ||
196 | #define macrohead (G.macrohead) | ||
197 | #define firstname (G.firstname) | ||
198 | #define target (G.target) | ||
199 | #define ar_mtime (G.ar_mtime) | ||
200 | #define lineno (G.lineno) | ||
201 | #define dispno (G.dispno) | ||
202 | #define rulepos (G.rulepos) | ||
203 | #define clevel (G.clevel) | ||
204 | #define cstate (G.cstate) | ||
205 | #if ENABLE_FEATURE_MAKE_POSIX | ||
206 | #define posix (G.posix) | ||
207 | #define seen_first (G.seen_first) | ||
208 | #else | ||
209 | #define posix 0 | ||
210 | #endif | ||
211 | #define numjobs (G.numjobs) | ||
212 | |||
213 | static int make(struct name *np, int level); | ||
214 | |||
215 | // Return TRUE if c is allowed in a POSIX 2017 macro or target name | ||
216 | #define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_') | ||
217 | // Return TRUE if c is in the POSIX 'portable filename character set' | ||
218 | #define isfname(c) (ispname(c) || c == '-') | ||
219 | |||
220 | /* | ||
221 | * Utility functions. | ||
222 | */ | ||
223 | |||
224 | /* | ||
225 | * Error handler. Print message, with line number, and exit. | ||
226 | */ | ||
227 | static void error(const char *msg, ...) NORETURN; | ||
228 | static void | ||
229 | error(const char *msg, ...) | ||
230 | { | ||
231 | va_list list; | ||
232 | |||
233 | if (makefile) { | ||
234 | const char *num = itoa(dispno); | ||
235 | char *s = malloc(strlen(makefile) + strlen(num) + 2); | ||
236 | if (s) { | ||
237 | sprintf(s, "%s:%s", makefile, num); | ||
238 | applet_name = s; | ||
239 | } | ||
240 | } | ||
241 | va_start(list, msg); | ||
242 | bb_verror_msg(msg, list, NULL); | ||
243 | va_end(list); | ||
244 | exit(2); | ||
245 | } | ||
246 | |||
247 | static void error_unexpected(const char *s) NORETURN; | ||
248 | static void | ||
249 | error_unexpected(const char *s) | ||
250 | { | ||
251 | error("unexpected %s", s); | ||
252 | } | ||
253 | |||
254 | static void error_in_inference_rule(const char *s) NORETURN; | ||
255 | static void | ||
256 | error_in_inference_rule(const char *s) | ||
257 | { | ||
258 | error("%s in inference rule", s); | ||
259 | } | ||
260 | |||
261 | static char * | ||
262 | auto_concat(const char *s1, const char *s2) | ||
263 | { | ||
264 | return auto_string(xasprintf("%s%s", s1, s2)); | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Append a word to a space-separated string of words. The first | ||
269 | * call should use a NULL pointer for str, subsequent calls should | ||
270 | * pass an allocated string which will be freed. | ||
271 | */ | ||
272 | static char * | ||
273 | xappendword(const char *str, const char *word) | ||
274 | { | ||
275 | char *newstr = str ? xasprintf("%s %s", str, word) : xstrdup(word); | ||
276 | free((void *)str); | ||
277 | return newstr; | ||
278 | } | ||
279 | |||
280 | static unsigned int | ||
281 | getbucket(const char *name) | ||
282 | { | ||
283 | unsigned int hashval = 0; | ||
284 | const unsigned char *p = (unsigned char *)name; | ||
285 | |||
286 | while (*p) | ||
287 | hashval ^= (hashval << 5) + (hashval >> 2) + *p++; | ||
288 | return hashval % HTABSIZE; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * Add a prerequisite to the end of the supplied list. | ||
293 | */ | ||
294 | static void | ||
295 | newdep(struct depend **dphead, struct name *np) | ||
296 | { | ||
297 | while (*dphead) | ||
298 | dphead = &(*dphead)->d_next; | ||
299 | *dphead = xzalloc(sizeof(struct depend)); | ||
300 | /*(*dphead)->d_next = NULL; - xzalloc did it */ | ||
301 | (*dphead)->d_name = np; | ||
302 | /*(*dphead)->d_refcnt = 0; */ | ||
303 | } | ||
304 | |||
305 | static void | ||
306 | freedeps(struct depend *dp) | ||
307 | { | ||
308 | if (dp && --dp->d_refcnt <= 0) | ||
309 | llist_free((llist_t *)dp, NULL); | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Add a command to the end of the supplied list of commands. | ||
314 | */ | ||
315 | static void | ||
316 | newcmd(struct cmd **cphead, char *str) | ||
317 | { | ||
318 | while (isspace(*str)) | ||
319 | str++; | ||
320 | |||
321 | if (*str == '\0') // No command, leave current head unchanged | ||
322 | return; | ||
323 | |||
324 | while (*cphead) | ||
325 | cphead = &(*cphead)->c_next; | ||
326 | *cphead = xzalloc(sizeof(struct cmd)); | ||
327 | /*(*cphead)->c_next = NULL; - xzalloc did it */ | ||
328 | (*cphead)->c_cmd = xstrdup(str); | ||
329 | /*(*cphead)->c_refcnt = 0; */ | ||
330 | } | ||
331 | |||
332 | static void | ||
333 | freecmds(struct cmd *cp) | ||
334 | { | ||
335 | if (cp && --cp->c_refcnt <= 0) | ||
336 | llist_free((llist_t *)cp, free); | ||
337 | } | ||
338 | |||
339 | static struct name * | ||
340 | findname(const char *name) | ||
341 | { | ||
342 | struct name *np = namehead[getbucket(name)]; | ||
343 | return (struct name *)llist_find_str((llist_t *)np, name); | ||
344 | } | ||
345 | |||
346 | static int | ||
347 | is_valid_target(const char *name) | ||
348 | { | ||
349 | const char *s; | ||
350 | for (s = name; *s; ++s) { | ||
351 | if (posix && !ispname(*s)) | ||
352 | return FALSE; | ||
353 | } | ||
354 | return TRUE; | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | * Intern a name. Return a pointer to the name struct | ||
359 | */ | ||
360 | static struct name * | ||
361 | newname(const char *name) | ||
362 | { | ||
363 | struct name *np = findname(name); | ||
364 | |||
365 | if (np == NULL) { | ||
366 | unsigned int bucket; | ||
367 | |||
368 | if (!is_valid_target(name)) | ||
369 | error("invalid target name '%s'", name); | ||
370 | |||
371 | bucket = getbucket(name); | ||
372 | np = xzalloc(sizeof(struct name)); | ||
373 | np->n_next = namehead[bucket]; | ||
374 | namehead[bucket] = np; | ||
375 | np->n_name = xstrdup(name); | ||
376 | /*np->n_rule = NULL; - xzalloc did it */ | ||
377 | /*np->n_tim = (struct timespec){0, 0}; */ | ||
378 | /*np->n_flag = 0; */ | ||
379 | } | ||
380 | return np; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * Return the commands on the first rule that has them or NULL. | ||
385 | */ | ||
386 | static struct cmd * | ||
387 | getcmd(struct name *np) | ||
388 | { | ||
389 | struct rule *rp; | ||
390 | |||
391 | if (np == NULL) | ||
392 | return NULL; | ||
393 | |||
394 | for (rp = np->n_rule; rp; rp = rp->r_next) | ||
395 | if (rp->r_cmd) | ||
396 | return rp->r_cmd; | ||
397 | return NULL; | ||
398 | } | ||
399 | |||
400 | #if ENABLE_FEATURE_CLEAN_UP | ||
401 | static void | ||
402 | freenames(void) | ||
403 | { | ||
404 | int i; | ||
405 | struct name *np, *nextnp; | ||
406 | |||
407 | for (i = 0; i < HTABSIZE; i++) { | ||
408 | for (np = namehead[i]; np; np = nextnp) { | ||
409 | nextnp = np->n_next; | ||
410 | free(np->n_name); | ||
411 | freerules(np->n_rule); | ||
412 | free(np); | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | #endif | ||
417 | |||
418 | static void | ||
419 | freerules(struct rule *rp) | ||
420 | { | ||
421 | struct rule *nextrp; | ||
422 | |||
423 | for (; rp; rp = nextrp) { | ||
424 | nextrp = rp->r_next; | ||
425 | freedeps(rp->r_dep); | ||
426 | freecmds(rp->r_cmd); | ||
427 | free(rp); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | static void * | ||
432 | inc_ref(void *vp) | ||
433 | { | ||
434 | if (vp) { | ||
435 | struct depend *dp = vp; | ||
436 | if (dp->d_refcnt == INT_MAX) | ||
437 | bb_die_memory_exhausted(); | ||
438 | dp->d_refcnt++; | ||
439 | } | ||
440 | return vp; | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * Add a new rule to a target. This checks to see if commands already | ||
445 | * exist for the target. If flag is TRUE the target can have multiple | ||
446 | * rules with commands (double-colon rules). | ||
447 | * | ||
448 | * i) If the name is a special target and there are no prerequisites | ||
449 | * or commands to be added remove all prerequisites and commands. | ||
450 | * This is necessary when clearing a built-in inference rule. | ||
451 | * ii) If name is a special target and has commands, replace them. | ||
452 | * This is for redefining commands for an inference rule. | ||
453 | */ | ||
454 | static void | ||
455 | addrule(struct name *np, struct depend *dp, struct cmd *cp, int flag) | ||
456 | { | ||
457 | struct rule *rp; | ||
458 | struct rule **rpp; | ||
459 | |||
460 | // Can't mix single-colon and double-colon rules | ||
461 | if (!posix && (np->n_flag & N_TARGET)) { | ||
462 | if (!(np->n_flag & N_DOUBLE) != !flag) // like xor | ||
463 | error("inconsistent rules for target %s", np->n_name); | ||
464 | } | ||
465 | |||
466 | // Clear out prerequisites and commands | ||
467 | if ((np->n_flag & N_SPECIAL) && !dp && !cp) { | ||
468 | if (strcmp(np->n_name, ".PHONY") == 0) | ||
469 | return; | ||
470 | freerules(np->n_rule); | ||
471 | np->n_rule = NULL; | ||
472 | return; | ||
473 | } | ||
474 | |||
475 | if (cp && !(np->n_flag & N_DOUBLE) && getcmd(np)) { | ||
476 | // Handle the inference rule redefinition case | ||
477 | if ((np->n_flag & N_SPECIAL) && !dp) { | ||
478 | freerules(np->n_rule); | ||
479 | np->n_rule = NULL; | ||
480 | } else { | ||
481 | error("commands defined twice for target %s", np->n_name); | ||
482 | } | ||
483 | } | ||
484 | |||
485 | rpp = &np->n_rule; | ||
486 | while (*rpp) | ||
487 | rpp = &(*rpp)->r_next; | ||
488 | |||
489 | *rpp = rp = xzalloc(sizeof(struct rule)); | ||
490 | /*rp->r_next = NULL; - xzalloc did it */ | ||
491 | rp->r_dep = inc_ref(dp); | ||
492 | rp->r_cmd = inc_ref(cp); | ||
493 | |||
494 | np->n_flag |= N_TARGET; | ||
495 | if (flag) | ||
496 | np->n_flag |= N_DOUBLE; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * Macro control for make | ||
501 | */ | ||
502 | static struct macro * | ||
503 | getmp(const char *name) | ||
504 | { | ||
505 | struct macro *mp = macrohead[getbucket(name)]; | ||
506 | return (struct macro *)llist_find_str((llist_t *)mp, name); | ||
507 | } | ||
508 | |||
509 | static int | ||
510 | is_valid_macro(const char *name) | ||
511 | { | ||
512 | const char *s; | ||
513 | for (s = name; *s; ++s) { | ||
514 | // In POSIX mode only a limited set of characters are guaranteed | ||
515 | // to be allowed in macro names. | ||
516 | if (posix && !isfname(*s)) | ||
517 | return FALSE; | ||
518 | // As an extension allow anything that can get through the | ||
519 | // input parser, apart from the following. | ||
520 | if (*s == '=' || isblank(*s) || iscntrl(*s)) | ||
521 | return FALSE; | ||
522 | } | ||
523 | return TRUE; | ||
524 | } | ||
525 | |||
526 | static void | ||
527 | setmacro(const char *name, const char *val, int level) | ||
528 | { | ||
529 | struct macro *mp; | ||
530 | bool valid = level & M_VALID; | ||
531 | bool immediate = level & M_IMMEDIATE; | ||
532 | |||
533 | level &= ~(M_IMMEDIATE | M_VALID); | ||
534 | mp = getmp(name); | ||
535 | if (mp) { | ||
536 | // Don't replace existing macro from a lower level | ||
537 | if (level > mp->m_level) | ||
538 | return; | ||
539 | |||
540 | // Replace existing macro | ||
541 | free(mp->m_val); | ||
542 | } else { | ||
543 | // If not defined, allocate space for new | ||
544 | unsigned int bucket; | ||
545 | |||
546 | if (!valid && !is_valid_macro(name)) | ||
547 | error("invalid macro name '%s'", name); | ||
548 | |||
549 | bucket = getbucket(name); | ||
550 | mp = xzalloc(sizeof(struct macro)); | ||
551 | mp->m_next = macrohead[bucket]; | ||
552 | macrohead[bucket] = mp; | ||
553 | /* mp->m_flag = FALSE; - xzalloc did it */ | ||
554 | mp->m_name = xstrdup(name); | ||
555 | } | ||
556 | mp->m_immediate = immediate; | ||
557 | mp->m_level = level; | ||
558 | mp->m_val = xstrdup(val ? val : ""); | ||
559 | } | ||
560 | |||
561 | #if ENABLE_FEATURE_CLEAN_UP | ||
562 | static void | ||
563 | freemacros(void) | ||
564 | { | ||
565 | int i; | ||
566 | struct macro *mp, *nextmp; | ||
567 | |||
568 | for (i = 0; i < HTABSIZE; i++) { | ||
569 | for (mp = macrohead[i]; mp; mp = nextmp) { | ||
570 | nextmp = mp->m_next; | ||
571 | free(mp->m_name); | ||
572 | free(mp->m_val); | ||
573 | free(mp); | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | #endif | ||
578 | |||
579 | /* | ||
580 | * Get modification time of file or archive member | ||
581 | */ | ||
582 | static void FAST_FUNC | ||
583 | record_mtime(const file_header_t *file_header) | ||
584 | { | ||
585 | ar_mtime = file_header->mtime; | ||
586 | } | ||
587 | |||
588 | static time_t | ||
589 | artime(const char *archive, const char *member) | ||
590 | { | ||
591 | archive_handle_t *archive_handle; | ||
592 | |||
593 | ar_mtime = 0; | ||
594 | archive_handle = init_handle(); | ||
595 | archive_handle->src_fd = open(archive, O_RDONLY); | ||
596 | if (archive_handle->src_fd != -1) { | ||
597 | archive_handle->action_header = record_mtime; | ||
598 | archive_handle->filter = filter_accept_list; | ||
599 | llist_add_to_end(&archive_handle->accept, (void *)member); | ||
600 | unpack_ar_archive(archive_handle); | ||
601 | close(archive_handle->src_fd); | ||
602 | } | ||
603 | |||
604 | #if ENABLE_FEATURE_AR_LONG_FILENAMES | ||
605 | free(archive_handle->ar__long_names); | ||
606 | #endif | ||
607 | llist_free(archive_handle->accept, NULL); | ||
608 | free(archive_handle->file_header); | ||
609 | free(archive_handle); | ||
610 | |||
611 | return ar_mtime; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * If the name is of the form 'libname(member.o)' split it into its | ||
616 | * name and member parts and set the member pointer to point to the | ||
617 | * latter. Otherwise just take a copy of the name and don't alter | ||
618 | * the member pointer. | ||
619 | * | ||
620 | * In either case the return value is an allocated string which must | ||
621 | * be freed by the caller. | ||
622 | */ | ||
623 | static char * | ||
624 | splitlib(const char *name, char **member) | ||
625 | { | ||
626 | char *s, *t; | ||
627 | size_t len; | ||
628 | |||
629 | t = xstrdup(name); | ||
630 | s = strchr(t, '('); | ||
631 | if (s) { | ||
632 | // We have 'libname(member.o)' | ||
633 | *s++ = '\0'; | ||
634 | len = strlen(s); | ||
635 | if (len <= 1 || s[len - 1] != ')' || *t == '\0') | ||
636 | error("invalid name '%s'", name); | ||
637 | s[len - 1] = '\0'; | ||
638 | *member = s; | ||
639 | } | ||
640 | return t; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Get the modification time of a file. Set it to 0 if the file | ||
645 | * doesn't exist. | ||
646 | */ | ||
647 | static void | ||
648 | modtime(struct name *np) | ||
649 | { | ||
650 | char *name, *member = NULL; | ||
651 | struct stat info; | ||
652 | |||
653 | name = splitlib(np->n_name, &member); | ||
654 | if (member) { | ||
655 | // Looks like library(member) | ||
656 | np->n_tim.tv_sec = artime(name, member); | ||
657 | np->n_tim.tv_nsec = 0; | ||
658 | } else if (stat(name, &info) < 0) { | ||
659 | if (errno != ENOENT) | ||
660 | bb_perror_msg("can't open %s", name); | ||
661 | np->n_tim.tv_sec = 0; | ||
662 | np->n_tim.tv_nsec = 0; | ||
663 | } else { | ||
664 | np->n_tim.tv_sec = info.st_mtim.tv_sec; | ||
665 | np->n_tim.tv_nsec = info.st_mtim.tv_nsec; | ||
666 | } | ||
667 | free(name); | ||
668 | } | ||
669 | |||
670 | /* | ||
671 | * Control of the implicit suffix rules | ||
672 | */ | ||
673 | |||
674 | /* | ||
675 | * Return a pointer to the suffix of a name (which may be the | ||
676 | * terminating NUL if there's no suffix). | ||
677 | */ | ||
678 | static char * | ||
679 | suffix(const char *name) | ||
680 | { | ||
681 | char *p = strrchr(name, '.'); | ||
682 | return p ? p : (char *)name + strlen(name); | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Dynamic dependency. This routine applies the suffix rules | ||
687 | * to try and find a source and a set of rules for a missing | ||
688 | * target. NULL is returned on failure. On success the name of | ||
689 | * the implicit prerequisite is returned and the details are | ||
690 | * placed in the imprule structure provided by the caller. | ||
691 | */ | ||
692 | static struct name * | ||
693 | dyndep(struct name *np, struct rule *imprule) | ||
694 | { | ||
695 | char *suff, *newsuff; | ||
696 | char *base, *name, *member; | ||
697 | struct name *xp; // Suffixes | ||
698 | struct name *sp; // Suffix rule | ||
699 | struct name *pp = NULL; // Implicit prerequisite | ||
700 | struct rule *rp; | ||
701 | struct depend *dp; | ||
702 | bool chain = FALSE; | ||
703 | |||
704 | member = NULL; | ||
705 | name = splitlib(np->n_name, &member); | ||
706 | |||
707 | suff = xstrdup(suffix(name)); | ||
708 | base = member ? member : name; | ||
709 | *suffix(base) = '\0'; | ||
710 | |||
711 | xp = newname(".SUFFIXES"); | ||
712 | retry: | ||
713 | for (rp = xp->n_rule; rp; rp = rp->r_next) { | ||
714 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | ||
715 | // Generate new suffix rule to try | ||
716 | newsuff = dp->d_name->n_name; | ||
717 | sp = findname(auto_concat(newsuff, suff)); | ||
718 | if (sp && sp->n_rule) { | ||
719 | // Generate a name for an implicit prerequisite | ||
720 | pp = newname(auto_concat(base, newsuff)); | ||
721 | if (!pp->n_tim.tv_sec) | ||
722 | modtime(pp); | ||
723 | if ((!chain && (pp->n_tim.tv_sec || getcmd(pp))) || | ||
724 | (chain && dyndep(pp, NULL))) { | ||
725 | // Prerequisite exists or we know how to make it | ||
726 | if (imprule) { | ||
727 | dp = NULL; | ||
728 | newdep(&dp, pp); | ||
729 | imprule->r_dep = dp; | ||
730 | imprule->r_cmd = sp->n_rule->r_cmd; | ||
731 | } | ||
732 | goto finish; | ||
733 | } | ||
734 | pp = NULL; | ||
735 | } | ||
736 | } | ||
737 | } | ||
738 | // If we didn't find an existing file or an explicit rule try | ||
739 | // again, this time looking for a chained inference rule. | ||
740 | if (!posix && !chain) { | ||
741 | chain = TRUE; | ||
742 | goto retry; | ||
743 | } | ||
744 | finish: | ||
745 | free(suff); | ||
746 | free(name); | ||
747 | return pp; | ||
748 | } | ||
749 | |||
750 | #define RULES \ | ||
751 | ".SUFFIXES:.o .c .y .l .a .sh .f\n" \ | ||
752 | ".c.o:\n" \ | ||
753 | " $(CC) $(CFLAGS) -c $<\n" \ | ||
754 | ".f.o:\n" \ | ||
755 | " $(FC) $(FFLAGS) -c $<\n" \ | ||
756 | ".y.o:\n" \ | ||
757 | " $(YACC) $(YFLAGS) $<\n" \ | ||
758 | " $(CC) $(CFLAGS) -c y.tab.c\n" \ | ||
759 | " rm -f y.tab.c\n" \ | ||
760 | " mv y.tab.o $@\n" \ | ||
761 | ".y.c:\n" \ | ||
762 | " $(YACC) $(YFLAGS) $<\n" \ | ||
763 | " mv y.tab.c $@\n" \ | ||
764 | ".l.o:\n" \ | ||
765 | " $(LEX) $(LFLAGS) $<\n" \ | ||
766 | " $(CC) $(CFLAGS) -c lex.yy.c\n" \ | ||
767 | " rm -f lex.yy.c\n" \ | ||
768 | " mv lex.yy.o $@\n" \ | ||
769 | ".l.c:\n" \ | ||
770 | " $(LEX) $(LFLAGS) $<\n" \ | ||
771 | " mv lex.yy.c $@\n" \ | ||
772 | ".c.a:\n" \ | ||
773 | " $(CC) -c $(CFLAGS) $<\n" \ | ||
774 | " $(AR) $(ARFLAGS) $@ $*.o\n" \ | ||
775 | " rm -f $*.o\n" \ | ||
776 | ".f.a:\n" \ | ||
777 | " $(FC) -c $(FFLAGS) $<\n" \ | ||
778 | " $(AR) $(ARFLAGS) $@ $*.o\n" \ | ||
779 | " rm -f $*.o\n" \ | ||
780 | ".c:\n" \ | ||
781 | " $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<\n" \ | ||
782 | ".f:\n" \ | ||
783 | " $(FC) $(FFLAGS) $(LDFLAGS) -o $@ $<\n" \ | ||
784 | ".sh:\n" \ | ||
785 | " cp $< $@\n" \ | ||
786 | " chmod a+x $@\n" | ||
787 | |||
788 | #define MACROS \ | ||
789 | "CC=c99\n" \ | ||
790 | "CFLAGS=-O1\n" \ | ||
791 | "FC=fort77\n" \ | ||
792 | "FFLAGS=-O1\n" \ | ||
793 | "YACC=yacc\n" \ | ||
794 | "YFLAGS=\n" \ | ||
795 | "LEX=lex\n" \ | ||
796 | "LFLAGS=\n" \ | ||
797 | "AR=ar\n" \ | ||
798 | "ARFLAGS=-rv\n" \ | ||
799 | "LDFLAGS=\n" | ||
800 | |||
801 | /* | ||
802 | * Read the built-in rules using a fake fgets-like interface. | ||
803 | */ | ||
804 | static char * | ||
805 | getrules(char *s, int size) | ||
806 | { | ||
807 | char *r = s; | ||
808 | |||
809 | if (rulepos == NULL) | ||
810 | rulepos = (RULES MACROS) + (norules ? sizeof(RULES) - 1 : 0); | ||
811 | |||
812 | if (*rulepos == '\0') | ||
813 | return NULL; | ||
814 | |||
815 | while (--size) { | ||
816 | if ((*r++ = *rulepos++) == '\n') | ||
817 | break; | ||
818 | } | ||
819 | *r = '\0'; | ||
820 | return s; | ||
821 | } | ||
822 | |||
823 | /* | ||
824 | * Parse a makefile | ||
825 | */ | ||
826 | |||
827 | /* | ||
828 | * Return a pointer to the next blank-delimited word or NULL if | ||
829 | * there are none left. | ||
830 | */ | ||
831 | static char * | ||
832 | gettok(char **ptr) | ||
833 | { | ||
834 | char *p; | ||
835 | |||
836 | while (isblank(**ptr)) // Skip blanks | ||
837 | (*ptr)++; | ||
838 | |||
839 | if (**ptr == '\0') // Nothing after blanks | ||
840 | return NULL; | ||
841 | |||
842 | p = *ptr; // Word starts here | ||
843 | |||
844 | while (**ptr != '\0' && !isblank(**ptr)) | ||
845 | (*ptr)++; // Find end of word | ||
846 | |||
847 | // Terminate token and move on unless already at end of string | ||
848 | if (**ptr != '\0') | ||
849 | *(*ptr)++ = '\0'; | ||
850 | |||
851 | return(p); | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * Skip over (possibly adjacent or nested) macro expansions. | ||
856 | */ | ||
857 | static char * | ||
858 | skip_macro(const char *s) | ||
859 | { | ||
860 | while (*s && s[0] == '$') { | ||
861 | if (s[1] == '(' || s[1] == '{') { | ||
862 | char end = *++s == '(' ? ')' : '}'; | ||
863 | while (*s && *s != end) | ||
864 | s = skip_macro(s + 1); | ||
865 | if (*s == end) | ||
866 | ++s; | ||
867 | } else if (s[1] != '\0') { | ||
868 | s += 2; | ||
869 | } else { | ||
870 | break; | ||
871 | } | ||
872 | } | ||
873 | return (char *)s; | ||
874 | } | ||
875 | |||
876 | /* | ||
877 | * Process each whitespace-separated word in the input string: | ||
878 | * | ||
879 | * - replace paths with their directory or filename part | ||
880 | * - replace prefixes and suffixes | ||
881 | * | ||
882 | * Returns an allocated string or NULL if the input is unmodified. | ||
883 | */ | ||
884 | static char * | ||
885 | modify_words(const char *val, int modifier, size_t lenf, | ||
886 | const char *find_pref, const char *repl_pref, | ||
887 | const char *find_suff, const char *repl_suff) | ||
888 | { | ||
889 | char *s, *copy, *word, *sep, *buf = NULL; | ||
890 | size_t find_pref_len = 0, find_suff_len = 0; | ||
891 | |||
892 | if (!modifier && !lenf) | ||
893 | return buf; | ||
894 | |||
895 | if (find_pref) { | ||
896 | // get length of find prefix, e.g: src/ | ||
897 | find_pref_len = strlen(find_pref); | ||
898 | // get length of find suffix, e.g: .c | ||
899 | find_suff_len = lenf - find_pref_len - 1; | ||
900 | } | ||
901 | |||
902 | s = copy = xstrdup(val); | ||
903 | while ((word = gettok(&s)) != NULL) { | ||
904 | if (modifier) { | ||
905 | sep = strrchr(word, '/'); | ||
906 | if (modifier == 'D') { | ||
907 | if (!sep) { | ||
908 | word[0] = '.'; // no '/', return "." | ||
909 | sep = word + 1; | ||
910 | } else if (sep == word) { | ||
911 | // '/' at start of word, return "/" | ||
912 | sep = word + 1; | ||
913 | } | ||
914 | // else terminate at separator | ||
915 | *sep = '\0'; | ||
916 | } else if (/* modifier == 'F' && */ sep) { | ||
917 | word = sep + 1; | ||
918 | } | ||
919 | } | ||
920 | if (lenf) { | ||
921 | size_t lenw = strlen(word); | ||
922 | // This code implements pattern macro expansions: | ||
923 | // https://austingroupbugs.net/view.php?id=519 | ||
924 | // | ||
925 | // find: <prefix>%<suffix> | ||
926 | // example: src/%.c | ||
927 | if (lenw >= lenf - 1 && find_pref) { | ||
928 | // If prefix and suffix of word match find_pref and | ||
929 | // find_suff, then do substitution. | ||
930 | if (strncmp(word, find_pref, find_pref_len) == 0 && | ||
931 | strcmp(word + lenw - find_suff_len, find_suff) == 0) { | ||
932 | // replace: <prefix>[%<suffix>] | ||
933 | // example: build/%.o or build/all.o (notice no %) | ||
934 | // If repl_suff is NULL, replace whole word with repl_pref. | ||
935 | if (!repl_suff) { | ||
936 | word = xstrdup(repl_pref); | ||
937 | } else { | ||
938 | word[lenw - find_suff_len] = '\0'; | ||
939 | word = xasprintf("%s%s%s", repl_pref, | ||
940 | word + find_pref_len, repl_suff); | ||
941 | } | ||
942 | word = auto_string(word); | ||
943 | } | ||
944 | } else if (lenw >= lenf && | ||
945 | strcmp(word + lenw - lenf, find_suff) == 0) { | ||
946 | word[lenw - lenf] = '\0'; | ||
947 | word = auto_concat(word, repl_suff); | ||
948 | } | ||
949 | } | ||
950 | buf = xappendword(buf, word); | ||
951 | } | ||
952 | free(copy); | ||
953 | return buf; | ||
954 | } | ||
955 | |||
956 | /* | ||
957 | * Return a pointer to the next instance of a given character. Macro | ||
958 | * expansions are skipped so the ':' and '=' in $(VAR:.s1=.s2) aren't | ||
959 | * detected as separators for rules or macro definitions. | ||
960 | */ | ||
961 | static char * | ||
962 | find_char(const char *str, int c) | ||
963 | { | ||
964 | const char *s; | ||
965 | |||
966 | for (s = skip_macro(str); *s; s = skip_macro(s + 1)) { | ||
967 | if (*s == c) | ||
968 | return (char *)s; | ||
969 | } | ||
970 | return NULL; | ||
971 | } | ||
972 | |||
973 | /* | ||
974 | * Recursively expand any macros in str to an allocated string. | ||
975 | */ | ||
976 | static char * | ||
977 | expand_macros(const char *str, int except_dollar) | ||
978 | { | ||
979 | char *exp, *newexp, *s, *t, *p, *q, *name; | ||
980 | char *find, *replace, *modified; | ||
981 | char *expval, *expfind, *find_suff, *repl_suff; | ||
982 | char *find_pref = NULL, *repl_pref = NULL; | ||
983 | size_t lenf; | ||
984 | char modifier; | ||
985 | struct macro *mp; | ||
986 | |||
987 | exp = xstrdup(str); | ||
988 | for (t = exp; *t; t++) { | ||
989 | if (*t == '$') { | ||
990 | if (t[1] == '\0') { | ||
991 | break; | ||
992 | } | ||
993 | if (t[1] == '$' && except_dollar) { | ||
994 | t++; | ||
995 | continue; | ||
996 | } | ||
997 | // Need to expand a macro. Find its extent (s to t inclusive) | ||
998 | // and take a copy of its content. | ||
999 | s = t; | ||
1000 | t++; | ||
1001 | if (*t == '{' || *t == '(') { | ||
1002 | t = find_char(t, *t == '{' ? '}' : ')'); | ||
1003 | if (t == NULL) | ||
1004 | error("unterminated variable '%s'", s); | ||
1005 | name = xstrndup(s + 2, t - s - 2); | ||
1006 | } else { | ||
1007 | name = xzalloc(2); | ||
1008 | name[0] = *t; | ||
1009 | /*name[1] = '\0'; - xzalloc did it */ | ||
1010 | } | ||
1011 | |||
1012 | // Only do suffix replacement or pattern macro expansion | ||
1013 | // if both ':' and '=' are found. This is indicated by | ||
1014 | // lenf != 0. | ||
1015 | expfind = NULL; | ||
1016 | find_suff = repl_suff = NULL; | ||
1017 | lenf = 0; | ||
1018 | if ((find = find_char(name, ':'))) { | ||
1019 | *find++ = '\0'; | ||
1020 | expfind = expand_macros(find, FALSE); | ||
1021 | if ((replace = find_char(expfind, '='))) { | ||
1022 | *replace++ = '\0'; | ||
1023 | lenf = strlen(expfind); | ||
1024 | if (!posix && (find_suff = strchr(expfind, '%'))) { | ||
1025 | find_pref = expfind; | ||
1026 | repl_pref = replace; | ||
1027 | *find_suff++ = '\0'; | ||
1028 | if ((repl_suff = strchr(replace, '%'))) | ||
1029 | *repl_suff++ = '\0'; | ||
1030 | } else { | ||
1031 | find_suff = expfind; | ||
1032 | repl_suff = replace; | ||
1033 | } | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | p = q = name; | ||
1038 | // If not in POSIX mode expand macros in the name. | ||
1039 | if (!posix) { | ||
1040 | char *expname = expand_macros(name, FALSE); | ||
1041 | free(name); | ||
1042 | name = expname; | ||
1043 | } else { | ||
1044 | // Skip over nested expansions in name | ||
1045 | do { | ||
1046 | *q++ = *p; | ||
1047 | } while ((p = skip_macro(p + 1)) && *p); | ||
1048 | } | ||
1049 | |||
1050 | // The internal macros support 'D' and 'F' modifiers | ||
1051 | modifier = '\0'; | ||
1052 | switch (name[0]) { | ||
1053 | case '^': | ||
1054 | if (posix) | ||
1055 | break; | ||
1056 | // fall through | ||
1057 | case '@': case '%': case '?': case '<': case '*': | ||
1058 | if ((name[1] == 'D' || name[1] == 'F') && name[2] == '\0') { | ||
1059 | modifier = name[1]; | ||
1060 | name[1] = '\0'; | ||
1061 | } | ||
1062 | break; | ||
1063 | } | ||
1064 | |||
1065 | modified = NULL; | ||
1066 | if ((mp = getmp(name))) { | ||
1067 | // Recursive expansion | ||
1068 | if (mp->m_flag) | ||
1069 | error("recursive macro %s", name); | ||
1070 | // Note if we've expanded $(MAKE) | ||
1071 | if (strcmp(name, "MAKE") == 0) | ||
1072 | opts |= OPT_make; | ||
1073 | mp->m_flag = TRUE; | ||
1074 | expval = expand_macros(mp->m_val, FALSE); | ||
1075 | mp->m_flag = FALSE; | ||
1076 | modified = modify_words(expval, modifier, lenf, | ||
1077 | find_pref, repl_pref, find_suff, repl_suff); | ||
1078 | if (modified) | ||
1079 | free(expval); | ||
1080 | else | ||
1081 | modified = expval; | ||
1082 | } | ||
1083 | free(name); | ||
1084 | free(expfind); | ||
1085 | |||
1086 | if (modified && *modified) { | ||
1087 | // The text to be replaced by the macro expansion is | ||
1088 | // from s to t inclusive. | ||
1089 | *s = '\0'; | ||
1090 | newexp = xasprintf("%s%s%s", exp, modified, t + 1); | ||
1091 | t = newexp + (s - exp) + strlen(modified) - 1; | ||
1092 | free(exp); | ||
1093 | exp = newexp; | ||
1094 | } else { | ||
1095 | // Macro wasn't expanded or expanded to nothing. | ||
1096 | // Close the space occupied by the macro reference. | ||
1097 | q = t + 1; | ||
1098 | t = s - 1; | ||
1099 | while ((*s++ = *q++)) | ||
1100 | continue; | ||
1101 | } | ||
1102 | free(modified); | ||
1103 | } | ||
1104 | } | ||
1105 | return exp; | ||
1106 | } | ||
1107 | |||
1108 | /* | ||
1109 | * Process a non-command line | ||
1110 | */ | ||
1111 | static char * | ||
1112 | process_line(char *s) | ||
1113 | { | ||
1114 | char *r, *t; | ||
1115 | |||
1116 | // Skip leading blanks | ||
1117 | while (isblank(*s)) | ||
1118 | s++; | ||
1119 | r = s; | ||
1120 | |||
1121 | // Strip comment | ||
1122 | t = strchr(s, '#'); | ||
1123 | if (t) | ||
1124 | *t = '\0'; | ||
1125 | |||
1126 | // Replace escaped newline and any leading white space on the | ||
1127 | // following line with a single space. Stop processing at a | ||
1128 | // non-escaped newline. | ||
1129 | for (t = s; *s && *s != '\n'; ) { | ||
1130 | if (s[0] == '\\' && s[1] == '\n') { | ||
1131 | s += 2; | ||
1132 | while (isspace(*s)) | ||
1133 | ++s; | ||
1134 | *t++ = ' '; | ||
1135 | } else { | ||
1136 | *t++ = *s++; | ||
1137 | } | ||
1138 | } | ||
1139 | *t = '\0'; | ||
1140 | |||
1141 | return r; | ||
1142 | } | ||
1143 | |||
1144 | enum { | ||
1145 | INITIAL = 0, | ||
1146 | SKIP_LINE = 1 << 0, | ||
1147 | EXPECT_ELSE = 1 << 1, | ||
1148 | GOT_MATCH = 1 << 2 | ||
1149 | }; | ||
1150 | |||
1151 | #define IFDEF 0 | ||
1152 | #define IFNDEF 1 | ||
1153 | #define ELSE 0 | ||
1154 | #define ENDIF 1 | ||
1155 | |||
1156 | /* | ||
1157 | * Process conditional directives and return TRUE if the current line | ||
1158 | * should be skipped. | ||
1159 | */ | ||
1160 | static int | ||
1161 | skip_line(const char *str1) | ||
1162 | { | ||
1163 | char *copy, *q, *token, *next_token; | ||
1164 | bool new_level = TRUE; | ||
1165 | // Default is to return skip flag for current level | ||
1166 | int ret = cstate[clevel] & SKIP_LINE; | ||
1167 | int key; | ||
1168 | |||
1169 | if (*str1 == '\t') | ||
1170 | return ret; | ||
1171 | |||
1172 | copy = xstrdup(str1); | ||
1173 | q = process_line(copy); | ||
1174 | if ((token = gettok(&q)) != NULL) { | ||
1175 | next_token = gettok(&q); | ||
1176 | |||
1177 | switch (index_in_strings("else\0endif\0", token)) { | ||
1178 | case ENDIF: | ||
1179 | if (next_token != NULL) | ||
1180 | error_unexpected("text"); | ||
1181 | if (clevel == 0) | ||
1182 | error_unexpected(token); | ||
1183 | --clevel; | ||
1184 | ret = TRUE; | ||
1185 | goto end; | ||
1186 | case ELSE: | ||
1187 | if (!(cstate[clevel] & EXPECT_ELSE)) | ||
1188 | error_unexpected(token); | ||
1189 | |||
1190 | // If an earlier condition matched we'll now skip lines. | ||
1191 | // If not we don't, though an 'else if' may override this. | ||
1192 | if ((cstate[clevel] & GOT_MATCH)) | ||
1193 | cstate[clevel] |= SKIP_LINE; | ||
1194 | else | ||
1195 | cstate[clevel] &= ~SKIP_LINE; | ||
1196 | |||
1197 | if (next_token == NULL) { | ||
1198 | // Simple else with no conditional directive | ||
1199 | cstate[clevel] &= ~EXPECT_ELSE; | ||
1200 | ret = TRUE; | ||
1201 | goto end; | ||
1202 | } else { | ||
1203 | // A conditional directive is now required ('else if'). | ||
1204 | token = next_token; | ||
1205 | next_token = gettok(&q); | ||
1206 | new_level = FALSE; | ||
1207 | } | ||
1208 | break; | ||
1209 | } | ||
1210 | |||
1211 | key = index_in_strings("ifdef\0ifndef\0", token); | ||
1212 | if (key != -1) { | ||
1213 | if (next_token != NULL && gettok(&q) == NULL) { | ||
1214 | if (new_level) { | ||
1215 | // Start a new level. | ||
1216 | if (clevel == IF_MAX) | ||
1217 | error("nesting too deep"); | ||
1218 | ++clevel; | ||
1219 | cstate[clevel] = EXPECT_ELSE | SKIP_LINE; | ||
1220 | // If we were skipping lines at the previous level | ||
1221 | // we need to continue doing that unconditionally | ||
1222 | // at the new level. | ||
1223 | if ((cstate[clevel - 1] & SKIP_LINE)) | ||
1224 | cstate[clevel] |= GOT_MATCH; | ||
1225 | } | ||
1226 | |||
1227 | if (!(cstate[clevel] & GOT_MATCH)) { | ||
1228 | char *t = expand_macros(next_token, FALSE); | ||
1229 | struct macro *mp = getmp(t); | ||
1230 | int match = mp != NULL && mp->m_val[0] != '\0'; | ||
1231 | |||
1232 | if (key == IFNDEF) | ||
1233 | match = !match; | ||
1234 | if (match) { | ||
1235 | cstate[clevel] &= ~SKIP_LINE; | ||
1236 | cstate[clevel] |= GOT_MATCH; | ||
1237 | } | ||
1238 | free(t); | ||
1239 | } | ||
1240 | } else { | ||
1241 | error("invalid condition"); | ||
1242 | } | ||
1243 | ret = TRUE; | ||
1244 | } else if (!new_level) { | ||
1245 | error("missing conditional"); | ||
1246 | } | ||
1247 | } | ||
1248 | end: | ||
1249 | free(copy); | ||
1250 | return ret; | ||
1251 | } | ||
1252 | |||
1253 | /* | ||
1254 | * If fd is NULL read the built-in rules. Otherwise read from the | ||
1255 | * specified file descriptor. | ||
1256 | */ | ||
1257 | static char * | ||
1258 | make_fgets(char *s, int size, FILE *fd) | ||
1259 | { | ||
1260 | return fd ? fgets(s, size, fd) : getrules(s, size); | ||
1261 | } | ||
1262 | |||
1263 | /* | ||
1264 | * Read a newline-terminated line into an allocated string. | ||
1265 | * Backslash-escaped newlines don't terminate the line. | ||
1266 | * Ignore comment lines. Return NULL on EOF. | ||
1267 | */ | ||
1268 | static char * | ||
1269 | readline(FILE *fd) | ||
1270 | { | ||
1271 | char *p, *str; | ||
1272 | int pos = 0; | ||
1273 | int len = 256; | ||
1274 | |||
1275 | str = xmalloc(len); | ||
1276 | |||
1277 | for (;;) { | ||
1278 | if (make_fgets(str + pos, len - pos, fd) == NULL) { | ||
1279 | if (pos) | ||
1280 | return str; | ||
1281 | free(str); | ||
1282 | return NULL; // EOF | ||
1283 | } | ||
1284 | |||
1285 | if ((p = strchr(str + pos, '\n')) == NULL) { | ||
1286 | // Need more room | ||
1287 | pos = len - 1; | ||
1288 | len += 256; | ||
1289 | str = xrealloc(str, len); | ||
1290 | continue; | ||
1291 | } | ||
1292 | lineno++; | ||
1293 | |||
1294 | #if ENABLE_PLATFORM_MINGW32 | ||
1295 | // Remove CR before LF | ||
1296 | if (p != str && p[-1] == '\r') { | ||
1297 | p[-1] = '\n'; | ||
1298 | *p-- = '\0'; | ||
1299 | } | ||
1300 | #endif | ||
1301 | // Keep going if newline has been escaped | ||
1302 | if (p != str && p[-1] == '\\') { | ||
1303 | pos = p - str + 1; | ||
1304 | continue; | ||
1305 | } | ||
1306 | dispno = lineno; | ||
1307 | |||
1308 | // Check for comment lines and lines that are conditionally skipped. | ||
1309 | p = str; | ||
1310 | while (isblank(*p)) | ||
1311 | p++; | ||
1312 | |||
1313 | if (*p != '\n' && *str != '#' && (posix || !skip_line(str))) | ||
1314 | return str; | ||
1315 | |||
1316 | pos = 0; | ||
1317 | } | ||
1318 | } | ||
1319 | |||
1320 | /* | ||
1321 | * Return TRUE if the argument is a known suffix. | ||
1322 | */ | ||
1323 | static int | ||
1324 | is_suffix(const char *s) | ||
1325 | { | ||
1326 | struct name *np; | ||
1327 | struct rule *rp; | ||
1328 | struct depend *dp; | ||
1329 | |||
1330 | np = newname(".SUFFIXES"); | ||
1331 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
1332 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | ||
1333 | if (strcmp(s, dp->d_name->n_name) == 0) { | ||
1334 | return TRUE; | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | return FALSE; | ||
1339 | } | ||
1340 | |||
1341 | #define T_NORMAL 0 | ||
1342 | #define T_SPECIAL 1 | ||
1343 | #define T_INFERENCE 2 | ||
1344 | /* | ||
1345 | * Determine if the argument is a special target and return a set | ||
1346 | * of flags indicating its properties. | ||
1347 | */ | ||
1348 | static int | ||
1349 | target_type(char *s) | ||
1350 | { | ||
1351 | char *sfx; | ||
1352 | int ret; | ||
1353 | static const char *s_name[] = { | ||
1354 | ".DEFAULT", | ||
1355 | ".POSIX", | ||
1356 | ".IGNORE", | ||
1357 | ".PRECIOUS", | ||
1358 | ".SILENT", | ||
1359 | ".SUFFIXES", | ||
1360 | ".PHONY", | ||
1361 | }; | ||
1362 | |||
1363 | if (*s != '.') | ||
1364 | return T_NORMAL; | ||
1365 | |||
1366 | // Check for one of the known special targets | ||
1367 | for (ret = 0; ret < ARRAY_SIZE(s_name); ret++) | ||
1368 | if (strcmp(s_name[ret], s) == 0) | ||
1369 | return T_SPECIAL; | ||
1370 | |||
1371 | // Check for an inference rule | ||
1372 | ret = T_NORMAL; | ||
1373 | sfx = suffix(s); | ||
1374 | if (is_suffix(sfx)) { | ||
1375 | if (s == sfx) { // Single suffix rule | ||
1376 | ret = T_INFERENCE; | ||
1377 | } else { | ||
1378 | // Suffix is valid, check that prefix is too | ||
1379 | *sfx = '\0'; | ||
1380 | if (is_suffix(s)) | ||
1381 | ret = T_INFERENCE; | ||
1382 | *sfx = '.'; | ||
1383 | } | ||
1384 | } | ||
1385 | return ret; | ||
1386 | } | ||
1387 | |||
1388 | static int | ||
1389 | ends_with_bracket(const char *s) | ||
1390 | { | ||
1391 | return last_char_is(s, ')') != NULL; | ||
1392 | } | ||
1393 | |||
1394 | /* | ||
1395 | * Process a command line | ||
1396 | */ | ||
1397 | static char * | ||
1398 | process_command(char *s) | ||
1399 | { | ||
1400 | char *t, *u; | ||
1401 | |||
1402 | // Remove tab following escaped newline. Stop processing at a | ||
1403 | // non-escaped newline. | ||
1404 | for (t = u = s; *u && *u != '\n'; u++) { | ||
1405 | if (u[0] == '\\' && u[1] == '\n' && u[2] == '\t') { | ||
1406 | *t++ = *u++; | ||
1407 | *t++ = *u++; | ||
1408 | } else { | ||
1409 | *t++ = *u; | ||
1410 | } | ||
1411 | } | ||
1412 | *t = '\0'; | ||
1413 | return s; | ||
1414 | } | ||
1415 | |||
1416 | static char * | ||
1417 | run_command(const char *cmd) | ||
1418 | { | ||
1419 | FILE *fd; | ||
1420 | char *s, *val = NULL; | ||
1421 | char buf[256]; | ||
1422 | size_t len = 0, nread; | ||
1423 | |||
1424 | if ((fd = popen(cmd, "r")) == NULL) | ||
1425 | return val; | ||
1426 | |||
1427 | for (;;) { | ||
1428 | nread = fread(buf, 1, sizeof(buf), fd); | ||
1429 | if (nread == 0) | ||
1430 | break; | ||
1431 | |||
1432 | val = xrealloc(val, len + nread + 1); | ||
1433 | memcpy(val + len, buf, nread); | ||
1434 | len += nread; | ||
1435 | val[len] = '\0'; | ||
1436 | } | ||
1437 | pclose(fd); | ||
1438 | |||
1439 | if (val) { | ||
1440 | #if ENABLE_PLATFORM_MINGW32 | ||
1441 | len = remove_cr(val, len + 1) - 1; | ||
1442 | if (len == 0) { | ||
1443 | free(val); | ||
1444 | return NULL; | ||
1445 | } | ||
1446 | #endif | ||
1447 | // Remove one newline from the end (BSD compatibility) | ||
1448 | if (val[len - 1] == '\n') | ||
1449 | val[len - 1] = '\0'; | ||
1450 | // Other newlines are changed to spaces | ||
1451 | for (s = val; *s; ++s) { | ||
1452 | if (*s == '\n') | ||
1453 | *s = ' '; | ||
1454 | } | ||
1455 | } | ||
1456 | return val; | ||
1457 | } | ||
1458 | |||
1459 | /* | ||
1460 | * Check for an unescaped wildcard character | ||
1461 | */ | ||
1462 | static int wildchar(const char *p) | ||
1463 | { | ||
1464 | while (*p) { | ||
1465 | switch (*p) { | ||
1466 | case '?': | ||
1467 | case '*': | ||
1468 | case '[': | ||
1469 | return 1; | ||
1470 | case '\\': | ||
1471 | if (p[1] != '\0') | ||
1472 | ++p; | ||
1473 | break; | ||
1474 | } | ||
1475 | ++p; | ||
1476 | } | ||
1477 | return 0; | ||
1478 | } | ||
1479 | |||
1480 | /* | ||
1481 | * Expand any wildcards in a pattern. Return TRUE if a match is | ||
1482 | * found, in which case the caller should call globfree() on the | ||
1483 | * glob_t structure. | ||
1484 | */ | ||
1485 | static int | ||
1486 | wildcard(char *p, glob_t *gd) | ||
1487 | { | ||
1488 | int ret; | ||
1489 | char *s; | ||
1490 | |||
1491 | // Don't call glob() if there are no wildcards. | ||
1492 | if (!wildchar(p)) { | ||
1493 | nomatch: | ||
1494 | // Remove backslashes from the name. | ||
1495 | for (s = p; *p; ++p) { | ||
1496 | if (*p == '\\' && p[1] != '\0') | ||
1497 | continue; | ||
1498 | *s++ = *p; | ||
1499 | } | ||
1500 | *s = '\0'; | ||
1501 | return 0; | ||
1502 | } | ||
1503 | |||
1504 | memset(gd, 0, sizeof(*gd)); | ||
1505 | ret = glob(p, GLOB_NOSORT, NULL, gd); | ||
1506 | if (ret == GLOB_NOMATCH) { | ||
1507 | globfree(gd); | ||
1508 | goto nomatch; | ||
1509 | } else if (ret != 0) { | ||
1510 | error("glob error for '%s'", p); | ||
1511 | } | ||
1512 | return 1; | ||
1513 | } | ||
1514 | |||
1515 | /* | ||
1516 | * Parse input from the makefile and construct a tree structure of it. | ||
1517 | */ | ||
1518 | static void | ||
1519 | input(FILE *fd, int ilevel) | ||
1520 | { | ||
1521 | char *p, *q, *s, *a, *str, *expanded, *copy; | ||
1522 | char *str1, *str2; | ||
1523 | struct name *np; | ||
1524 | struct depend *dp; | ||
1525 | struct cmd *cp; | ||
1526 | int startno, count; | ||
1527 | bool semicolon_cmd, seen_inference; | ||
1528 | uint8_t old_clevel = clevel; | ||
1529 | bool dbl; | ||
1530 | char *lib = NULL; | ||
1531 | glob_t gd; | ||
1532 | int nfile, i; | ||
1533 | char **files; | ||
1534 | bool minus; | ||
1535 | |||
1536 | lineno = 0; | ||
1537 | str1 = readline(fd); | ||
1538 | while (str1) { | ||
1539 | str2 = NULL; | ||
1540 | if (*str1 == '\t') // Command without target | ||
1541 | error("command not allowed here"); | ||
1542 | |||
1543 | // Newlines and comments are handled differently in command lines | ||
1544 | // and other types of line. Take a copy of the current line before | ||
1545 | // processing it as a non-command line in case it contains a | ||
1546 | // rule with a command line. That is, a line of the form: | ||
1547 | // | ||
1548 | // target: prereq; command | ||
1549 | // | ||
1550 | copy = xstrdup(str1); | ||
1551 | str = process_line(str1); | ||
1552 | |||
1553 | // Check for an include line | ||
1554 | minus = !posix && *str == '-'; | ||
1555 | p = str + minus; | ||
1556 | if (strncmp(p, "include", 7) == 0 && isblank(p[7])) { | ||
1557 | const char *old_makefile = makefile; | ||
1558 | int old_lineno = lineno; | ||
1559 | |||
1560 | if (ilevel > 16) | ||
1561 | error("too many includes"); | ||
1562 | |||
1563 | q = expanded = expand_macros(p + 7, FALSE); | ||
1564 | while ((p = gettok(&q)) != NULL) { | ||
1565 | FILE *ifd; | ||
1566 | |||
1567 | if (!posix) { | ||
1568 | // Try to create include file or bring it up-to-date | ||
1569 | opts |= OPT_include; | ||
1570 | make(newname(p), 1); | ||
1571 | opts &= ~OPT_include; | ||
1572 | } | ||
1573 | if ((ifd = fopen(p, "r")) == NULL) { | ||
1574 | if (!minus) | ||
1575 | error("can't open include file '%s'", p); | ||
1576 | } else { | ||
1577 | makefile = p; | ||
1578 | input(ifd, ilevel + 1); | ||
1579 | fclose(ifd); | ||
1580 | } | ||
1581 | if (posix) | ||
1582 | break; | ||
1583 | } | ||
1584 | if (posix && (p == NULL || gettok(&q))) | ||
1585 | error("one include file per line"); | ||
1586 | |||
1587 | makefile = old_makefile; | ||
1588 | lineno = old_lineno; | ||
1589 | goto end_loop; | ||
1590 | } | ||
1591 | |||
1592 | // Check for a macro definition | ||
1593 | q = find_char(str, '='); | ||
1594 | if (q != NULL) { | ||
1595 | int level = (useenv || fd == NULL) ? 4 : 3; | ||
1596 | char *newq = NULL; | ||
1597 | char eq = '\0'; | ||
1598 | |||
1599 | if (q - 1 > str) { | ||
1600 | switch (q[-1]) { | ||
1601 | case ':': | ||
1602 | // '::=' and ':::=' are from POSIX 202X. | ||
1603 | if (!posix && q - 2 > str && q[-2] == ':') { | ||
1604 | if (q - 3 > str && q[-3] == ':') { | ||
1605 | eq = 'B'; // BSD-style ':=' | ||
1606 | q[-3] = '\0'; | ||
1607 | } else { | ||
1608 | eq = ':'; // GNU-style ':=' | ||
1609 | q[-2] = '\0'; | ||
1610 | } | ||
1611 | break; | ||
1612 | } | ||
1613 | case '!': | ||
1614 | // ':=' and '!=' are non-POSIX extensions. | ||
1615 | case '+': | ||
1616 | case '?': | ||
1617 | // '+=' and '?=' are from POSIX 202X. | ||
1618 | if (posix) | ||
1619 | break; | ||
1620 | eq = q[-1]; | ||
1621 | q[-1] = '\0'; | ||
1622 | break; | ||
1623 | } | ||
1624 | } | ||
1625 | *q++ = '\0'; // Separate name and value | ||
1626 | while (isblank(*q)) | ||
1627 | q++; | ||
1628 | if ((p = strrchr(q, '\n')) != NULL) | ||
1629 | *p = '\0'; | ||
1630 | |||
1631 | // Expand left-hand side of assignment | ||
1632 | p = expanded = expand_macros(str, FALSE); | ||
1633 | if ((a = gettok(&p)) == NULL || gettok(&p)) | ||
1634 | error("invalid macro assignment"); | ||
1635 | |||
1636 | if (eq == ':') { | ||
1637 | // GNU-style ':='. Expand right-hand side of assignment. | ||
1638 | // Macro is of type immediate-expansion. | ||
1639 | q = newq = expand_macros(q, FALSE); | ||
1640 | level |= M_IMMEDIATE; | ||
1641 | } | ||
1642 | else if (eq == 'B') { | ||
1643 | // BSD-style ':='. Expand right-hand side of assignment, | ||
1644 | // though not '$$'. Macro is of type delayed-expansion. | ||
1645 | q = newq = expand_macros(q, TRUE); | ||
1646 | } else if (eq == '?' && getmp(a) != NULL) { | ||
1647 | // Skip assignment if macro is already set | ||
1648 | goto end_loop; | ||
1649 | } else if (eq == '+') { | ||
1650 | // Append to current value | ||
1651 | struct macro *mp = getmp(a); | ||
1652 | char *rhs; | ||
1653 | newq = mp && mp->m_val[0] ? xstrdup(mp->m_val) : NULL; | ||
1654 | if (mp && mp->m_immediate) { | ||
1655 | // Expand right-hand side of assignment (GNU make | ||
1656 | // compatibility) | ||
1657 | rhs = expand_macros(q, FALSE); | ||
1658 | level |= M_IMMEDIATE; | ||
1659 | } else { | ||
1660 | rhs = q; | ||
1661 | } | ||
1662 | newq = xappendword(newq, rhs); | ||
1663 | if (rhs != q) | ||
1664 | free(rhs); | ||
1665 | q = newq; | ||
1666 | } | ||
1667 | else if (eq == '!') { | ||
1668 | char *cmd = expand_macros(q, FALSE); | ||
1669 | q = newq = run_command(cmd); | ||
1670 | free(cmd); | ||
1671 | } | ||
1672 | setmacro(a, q, level); | ||
1673 | free(newq); | ||
1674 | goto end_loop; | ||
1675 | } | ||
1676 | |||
1677 | // If we get here it must be a target rule | ||
1678 | p = expanded = expand_macros(str, FALSE); | ||
1679 | |||
1680 | // Look for colon separator | ||
1681 | q = find_char(p, ':'); | ||
1682 | if (q == NULL) | ||
1683 | error("expected separator"); | ||
1684 | |||
1685 | *q++ = '\0'; // Separate targets and prerequisites | ||
1686 | |||
1687 | // Double colon | ||
1688 | dbl = !posix && *q == ':'; | ||
1689 | if (dbl) | ||
1690 | q++; | ||
1691 | |||
1692 | // Look for semicolon separator | ||
1693 | cp = NULL; | ||
1694 | s = strchr(q, ';'); | ||
1695 | if (s) { | ||
1696 | *s = '\0'; | ||
1697 | // Retrieve command from copy of line | ||
1698 | if ((p = find_char(copy, ':')) && (p = strchr(p, ';'))) | ||
1699 | newcmd(&cp, process_command(p + 1)); | ||
1700 | } | ||
1701 | semicolon_cmd = cp != NULL; | ||
1702 | |||
1703 | // Create list of prerequisites | ||
1704 | dp = NULL; | ||
1705 | while (((p = gettok(&q)) != NULL)) { | ||
1706 | char *newp = NULL; | ||
1707 | |||
1708 | if (!posix) { | ||
1709 | // Allow prerequisites of form library(member1 member2). | ||
1710 | // Leading and trailing spaces in the brackets are skipped. | ||
1711 | if (!lib) { | ||
1712 | s = strchr(p, '('); | ||
1713 | if (s && !ends_with_bracket(s) && strchr(q, ')')) { | ||
1714 | // Looks like an unterminated archive member | ||
1715 | // with a terminator later on the line. | ||
1716 | lib = p; | ||
1717 | if (s[1] != '\0') { | ||
1718 | p = newp = auto_concat(lib, ")"); | ||
1719 | s[1] = '\0'; | ||
1720 | } else { | ||
1721 | continue; | ||
1722 | } | ||
1723 | } | ||
1724 | } else if (ends_with_bracket(p)) { | ||
1725 | if (*p != ')') | ||
1726 | p = newp = auto_concat(lib, p); | ||
1727 | lib = NULL; | ||
1728 | if (newp == NULL) | ||
1729 | continue; | ||
1730 | } else { | ||
1731 | p = newp = auto_string(xasprintf("%s%s)", lib, p)); | ||
1732 | } | ||
1733 | } | ||
1734 | |||
1735 | // If not in POSIX mode expand wildcards in the name. | ||
1736 | nfile = 1; | ||
1737 | files = &p; | ||
1738 | if (!posix && wildcard(p, &gd)) { | ||
1739 | nfile = gd.gl_pathc; | ||
1740 | files = gd.gl_pathv; | ||
1741 | } | ||
1742 | for (i = 0; i < nfile; ++i) { | ||
1743 | np = newname(files[i]); | ||
1744 | newdep(&dp, np); | ||
1745 | } | ||
1746 | if (files != &p) | ||
1747 | globfree(&gd); | ||
1748 | free(newp); | ||
1749 | } | ||
1750 | lib = NULL; | ||
1751 | |||
1752 | // Create list of commands | ||
1753 | startno = dispno; | ||
1754 | while ((str2 = readline(fd)) && *str2 == '\t') { | ||
1755 | newcmd(&cp, process_command(str2)); | ||
1756 | free(str2); | ||
1757 | } | ||
1758 | dispno = startno; | ||
1759 | |||
1760 | // Create target names and attach rule to them | ||
1761 | q = expanded; | ||
1762 | count = 0; | ||
1763 | seen_inference = FALSE; | ||
1764 | while ((p = gettok(&q)) != NULL) { | ||
1765 | // If not in POSIX mode expand wildcards in the name. | ||
1766 | nfile = 1; | ||
1767 | files = &p; | ||
1768 | if (!posix && wildcard(p, &gd)) { | ||
1769 | nfile = gd.gl_pathc; | ||
1770 | files = gd.gl_pathv; | ||
1771 | } | ||
1772 | for (i = 0; i < nfile; ++i) { | ||
1773 | int ttype = target_type(files[i]); | ||
1774 | |||
1775 | np = newname(files[i]); | ||
1776 | if (ttype != T_NORMAL) { | ||
1777 | if (ttype == T_INFERENCE && posix) { | ||
1778 | if (semicolon_cmd) | ||
1779 | error_in_inference_rule("'; command'"); | ||
1780 | seen_inference = TRUE; | ||
1781 | } | ||
1782 | np->n_flag |= N_SPECIAL; | ||
1783 | } else if (!firstname) { | ||
1784 | firstname = np; | ||
1785 | } | ||
1786 | addrule(np, dp, cp, dbl); | ||
1787 | count++; | ||
1788 | } | ||
1789 | if (files != &p) | ||
1790 | globfree(&gd); | ||
1791 | } | ||
1792 | if (seen_inference && count != 1) | ||
1793 | error_in_inference_rule("multiple targets"); | ||
1794 | |||
1795 | // Prerequisites and commands will be unused if there were | ||
1796 | // no targets. Avoid leaking memory. | ||
1797 | if (count == 0) { | ||
1798 | freedeps(dp); | ||
1799 | freecmds(cp); | ||
1800 | } | ||
1801 | end_loop: | ||
1802 | free(str1); | ||
1803 | dispno = lineno; | ||
1804 | str1 = str2 ? str2 : readline(fd); | ||
1805 | free(copy); | ||
1806 | free(expanded); | ||
1807 | #if ENABLE_FEATURE_MAKE_POSIX | ||
1808 | if (!seen_first && fd) { | ||
1809 | if (findname(".POSIX")) { | ||
1810 | // The first non-comment line from a real makefile | ||
1811 | // defined the .POSIX special target. | ||
1812 | setenv("PDPMAKE_POSIXLY_CORRECT", "", 1); | ||
1813 | posix = TRUE; | ||
1814 | } | ||
1815 | seen_first = TRUE; | ||
1816 | } | ||
1817 | #endif | ||
1818 | } | ||
1819 | // Conditionals aren't allowed to span files | ||
1820 | if (clevel != old_clevel) | ||
1821 | error("invalid conditional"); | ||
1822 | } | ||
1823 | |||
1824 | static void | ||
1825 | remove_target(void) | ||
1826 | { | ||
1827 | if (!dryrun && !print && !precious && | ||
1828 | target && !(target->n_flag & (N_PRECIOUS | N_PHONY)) && | ||
1829 | unlink(target->n_name) == 0) { | ||
1830 | bb_error_msg("'%s' removed", target->n_name); | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1834 | /* | ||
1835 | * Do commands to make a target | ||
1836 | */ | ||
1837 | static int | ||
1838 | docmds(struct name *np, struct cmd *cp) | ||
1839 | { | ||
1840 | int estat = 0; // 0 exit status is success | ||
1841 | char *q, *command; | ||
1842 | |||
1843 | for (; cp; cp = cp->c_next) { | ||
1844 | uint8_t ssilent, signore, sdomake; | ||
1845 | |||
1846 | opts &= ~OPT_make; // We want to know if $(MAKE) is expanded | ||
1847 | q = command = expand_macros(cp->c_cmd, FALSE); | ||
1848 | ssilent = silent || (np->n_flag & N_SILENT) || dotouch; | ||
1849 | signore = ignore || (np->n_flag & N_IGNORE); | ||
1850 | sdomake = (!dryrun || doinclude || domake) && !dotouch; | ||
1851 | for (;;) { | ||
1852 | if (*q == '@') // Specific silent | ||
1853 | ssilent = TRUE + 1; | ||
1854 | else if (*q == '-') // Specific ignore | ||
1855 | signore = TRUE; | ||
1856 | else if (*q == '+') // Specific domake | ||
1857 | sdomake = TRUE + 1; | ||
1858 | else | ||
1859 | break; | ||
1860 | q++; | ||
1861 | } | ||
1862 | |||
1863 | if (sdomake > TRUE) { | ||
1864 | // '+' must not override '@' or .SILENT | ||
1865 | if (ssilent != TRUE + 1 && !(np->n_flag & N_SILENT)) | ||
1866 | ssilent = FALSE; | ||
1867 | } else if (!sdomake) | ||
1868 | ssilent = dotouch; | ||
1869 | |||
1870 | if (!ssilent) | ||
1871 | puts(q); | ||
1872 | |||
1873 | if (sdomake) { | ||
1874 | // Get the shell to execute it | ||
1875 | int status; | ||
1876 | char *cmd = !signore ? auto_concat("set -e;", q) : q; | ||
1877 | |||
1878 | target = np; | ||
1879 | status = system(cmd); | ||
1880 | target = NULL; | ||
1881 | // If this command was being run to create an include file | ||
1882 | // or bring it up-to-date errors should be ignored and a | ||
1883 | // failure status returned. | ||
1884 | if (status == -1 && !doinclude) { | ||
1885 | error("couldn't execute '%s'", q); | ||
1886 | } else if (status != 0 && !signore) { | ||
1887 | if (!doinclude) | ||
1888 | bb_error_msg("failed to build '%s'", np->n_name); | ||
1889 | #if !ENABLE_PLATFORM_MINGW32 | ||
1890 | if (status == SIGINT || status == SIGQUIT) | ||
1891 | #endif | ||
1892 | remove_target(); | ||
1893 | if (errcont || doinclude) | ||
1894 | estat = 1; // 1 exit status is failure | ||
1895 | else | ||
1896 | exit(status); | ||
1897 | } | ||
1898 | } | ||
1899 | free(command); | ||
1900 | } | ||
1901 | return estat; | ||
1902 | } | ||
1903 | |||
1904 | /* | ||
1905 | * Update the modification time of a file to now. | ||
1906 | */ | ||
1907 | static void | ||
1908 | touch(struct name *np) | ||
1909 | { | ||
1910 | if (dryrun || !silent) | ||
1911 | printf("touch %s\n", np->n_name); | ||
1912 | |||
1913 | if (!dryrun) { | ||
1914 | const struct timespec timebuf[2] = {{0, UTIME_NOW}, {0, UTIME_NOW}}; | ||
1915 | |||
1916 | if (utimensat(AT_FDCWD, np->n_name, timebuf, 0) < 0) { | ||
1917 | if (errno == ENOENT) { | ||
1918 | int fd = open(np->n_name, O_RDWR | O_CREAT, 0666); | ||
1919 | if (fd >= 0) { | ||
1920 | close(fd); | ||
1921 | return; | ||
1922 | } | ||
1923 | } | ||
1924 | bb_perror_msg("touch %s failed", np->n_name); | ||
1925 | } | ||
1926 | } | ||
1927 | } | ||
1928 | |||
1929 | static int | ||
1930 | make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, | ||
1931 | struct name *implicit) | ||
1932 | { | ||
1933 | int estat = 0; // 0 exit status is success | ||
1934 | char *name, *member = NULL, *base; | ||
1935 | |||
1936 | name = splitlib(np->n_name, &member); | ||
1937 | setmacro("?", oodate, 0 | M_VALID); | ||
1938 | if (!posix) | ||
1939 | setmacro("^", allsrc, 0 | M_VALID); | ||
1940 | setmacro("%", member, 0 | M_VALID); | ||
1941 | setmacro("@", name, 0 | M_VALID); | ||
1942 | if (implicit) { | ||
1943 | setmacro("<", implicit->n_name, 0 | M_VALID); | ||
1944 | base = member ? member : name; | ||
1945 | *suffix(base) = '\0'; | ||
1946 | setmacro("*", base, 0 | M_VALID); | ||
1947 | } | ||
1948 | free(name); | ||
1949 | |||
1950 | estat = docmds(np, cp); | ||
1951 | if (dotouch && !(np->n_flag & N_PHONY)) | ||
1952 | touch(np); | ||
1953 | |||
1954 | return estat; | ||
1955 | } | ||
1956 | |||
1957 | /* | ||
1958 | * Determine if the modification time of a target, t, is less than | ||
1959 | * that of a prerequisite, p. If the tv_nsec member of either is | ||
1960 | * exactly 0 we assume (possibly incorrectly) that the time resolution | ||
1961 | * is 1 second and only compare tv_sec values. | ||
1962 | */ | ||
1963 | static int | ||
1964 | timespec_le(const struct timespec *t, const struct timespec *p) | ||
1965 | { | ||
1966 | if (t->tv_nsec == 0 || p->tv_nsec == 0) | ||
1967 | return t->tv_sec <= p->tv_sec; | ||
1968 | else if (t->tv_sec < p->tv_sec) | ||
1969 | return TRUE; | ||
1970 | else if (t->tv_sec == p->tv_sec) | ||
1971 | return t->tv_nsec <= p->tv_nsec; | ||
1972 | return FALSE; | ||
1973 | } | ||
1974 | |||
1975 | /* | ||
1976 | * Return the greater of two struct timespecs | ||
1977 | */ | ||
1978 | static const struct timespec * | ||
1979 | timespec_max(const struct timespec *t, const struct timespec *p) | ||
1980 | { | ||
1981 | return timespec_le(t, p) ? p : t; | ||
1982 | } | ||
1983 | |||
1984 | /* | ||
1985 | * Recursive routine to make a target. | ||
1986 | */ | ||
1987 | static int | ||
1988 | make(struct name *np, int level) | ||
1989 | { | ||
1990 | struct depend *dp; | ||
1991 | struct rule *rp; | ||
1992 | struct name *impdep = NULL; // implicit prerequisite | ||
1993 | struct rule imprule; | ||
1994 | struct cmd *sc_cmd = NULL; // commands for single-colon rule | ||
1995 | char *oodate = NULL; | ||
1996 | char *allsrc = NULL; | ||
1997 | struct timespec dtim = {1, 0}; | ||
1998 | bool didsomething = 0; | ||
1999 | bool estat = 0; // 0 exit status is success | ||
2000 | |||
2001 | if (np->n_flag & N_DONE) | ||
2002 | return 0; | ||
2003 | if (np->n_flag & N_DOING) | ||
2004 | error("circular dependency for %s", np->n_name); | ||
2005 | np->n_flag |= N_DOING; | ||
2006 | |||
2007 | if (!np->n_tim.tv_sec) | ||
2008 | modtime(np); // Get modtime of this file | ||
2009 | |||
2010 | if (!(np->n_flag & N_DOUBLE)) { | ||
2011 | // Find the commands needed for a single-colon rule, using | ||
2012 | // an inference rule or .DEFAULT rule if necessary | ||
2013 | sc_cmd = getcmd(np); | ||
2014 | if (!sc_cmd) { | ||
2015 | impdep = dyndep(np, &imprule); | ||
2016 | if (impdep) { | ||
2017 | sc_cmd = imprule.r_cmd; | ||
2018 | addrule(np, imprule.r_dep, NULL, FALSE); | ||
2019 | } | ||
2020 | } | ||
2021 | |||
2022 | // As a last resort check for a default rule | ||
2023 | if (!(np->n_flag & N_TARGET) && np->n_tim.tv_sec == 0) { | ||
2024 | sc_cmd = getcmd(findname(".DEFAULT")); | ||
2025 | if (!sc_cmd) { | ||
2026 | if (doinclude) | ||
2027 | return 1; | ||
2028 | error("don't know how to make %s", np->n_name); | ||
2029 | } | ||
2030 | impdep = np; | ||
2031 | } | ||
2032 | } | ||
2033 | else { | ||
2034 | // If any double-colon rule has no commands we need | ||
2035 | // an inference rule | ||
2036 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2037 | if (!rp->r_cmd) { | ||
2038 | impdep = dyndep(np, &imprule); | ||
2039 | if (!impdep) { | ||
2040 | if (doinclude) | ||
2041 | return 1; | ||
2042 | error("don't know how to make %s", np->n_name); | ||
2043 | } | ||
2044 | break; | ||
2045 | } | ||
2046 | } | ||
2047 | } | ||
2048 | |||
2049 | // Reset flag to detect duplicate prerequisites | ||
2050 | if (!quest && !(np->n_flag & N_DOUBLE)) { | ||
2051 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2052 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | ||
2053 | dp->d_name->n_flag &= ~N_MARK; | ||
2054 | } | ||
2055 | } | ||
2056 | } | ||
2057 | |||
2058 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2059 | struct name *locdep = NULL; | ||
2060 | |||
2061 | // Each double-colon rule is handled separately. | ||
2062 | if ((np->n_flag & N_DOUBLE)) { | ||
2063 | // If the rule has no commands use the inference rule. | ||
2064 | if (!rp->r_cmd) { | ||
2065 | locdep = impdep; | ||
2066 | imprule.r_dep->d_next = rp->r_dep; | ||
2067 | rp->r_dep = imprule.r_dep; | ||
2068 | rp->r_cmd = imprule.r_cmd; | ||
2069 | } | ||
2070 | // A rule with no prerequisities is executed unconditionally. | ||
2071 | if (!rp->r_dep) | ||
2072 | dtim = np->n_tim; | ||
2073 | // Reset flag to detect duplicate prerequisites | ||
2074 | if (!quest) { | ||
2075 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | ||
2076 | dp->d_name->n_flag &= ~N_MARK; | ||
2077 | } | ||
2078 | } | ||
2079 | } | ||
2080 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | ||
2081 | // Make prerequisite | ||
2082 | estat |= make(dp->d_name, level + 1); | ||
2083 | |||
2084 | // Make strings of out-of-date prerequisites (for $?) | ||
2085 | // and all prerequisites (for $^). But not if we were | ||
2086 | // invoked with -q. | ||
2087 | if (!quest | ||
2088 | // Skip duplicate entries. | ||
2089 | && (posix || !(dp->d_name->n_flag & N_MARK)) | ||
2090 | ) { | ||
2091 | if (timespec_le(&np->n_tim, &dp->d_name->n_tim)) { | ||
2092 | oodate = xappendword(oodate, dp->d_name->n_name); | ||
2093 | } | ||
2094 | allsrc = xappendword(allsrc, dp->d_name->n_name); | ||
2095 | dp->d_name->n_flag |= N_MARK; | ||
2096 | } | ||
2097 | dtim = *timespec_max(&dtim, &dp->d_name->n_tim); | ||
2098 | } | ||
2099 | if ((np->n_flag & N_DOUBLE)) { | ||
2100 | if (!quest && ((np->n_flag & N_PHONY) || | ||
2101 | timespec_le(&np->n_tim, &dtim))) { | ||
2102 | if (estat == 0) { | ||
2103 | estat = make1(np, rp->r_cmd, oodate, allsrc, locdep); | ||
2104 | dtim = (struct timespec){1, 0}; | ||
2105 | didsomething = 1; | ||
2106 | } | ||
2107 | free(oodate); | ||
2108 | oodate = NULL; | ||
2109 | } | ||
2110 | free(allsrc); | ||
2111 | allsrc = NULL; | ||
2112 | if (locdep) { | ||
2113 | rp->r_dep = rp->r_dep->d_next; | ||
2114 | rp->r_cmd = NULL; | ||
2115 | } | ||
2116 | } | ||
2117 | } | ||
2118 | if ((np->n_flag & N_DOUBLE) && impdep) | ||
2119 | free(imprule.r_dep); | ||
2120 | |||
2121 | np->n_flag |= N_DONE; | ||
2122 | np->n_flag &= ~N_DOING; | ||
2123 | |||
2124 | if (quest) { | ||
2125 | if (timespec_le(&np->n_tim, &dtim)) { | ||
2126 | clock_gettime(CLOCK_REALTIME, &np->n_tim); | ||
2127 | return 1; // 1 means rebuild is needed | ||
2128 | } | ||
2129 | } else if (!(np->n_flag & N_DOUBLE) && | ||
2130 | ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) { | ||
2131 | if (estat == 0) { | ||
2132 | if (!sc_cmd) { | ||
2133 | if (!doinclude) | ||
2134 | bb_error_msg("nothing to be done for %s", np->n_name); | ||
2135 | } else { | ||
2136 | estat = make1(np, sc_cmd, oodate, allsrc, impdep); | ||
2137 | clock_gettime(CLOCK_REALTIME, &np->n_tim); | ||
2138 | } | ||
2139 | } else if (!doinclude) { | ||
2140 | bb_error_msg("'%s' not built due to errors", np->n_name); | ||
2141 | } | ||
2142 | free(oodate); | ||
2143 | } else if (didsomething) { | ||
2144 | clock_gettime(CLOCK_REALTIME, &np->n_tim); | ||
2145 | } else if (level == 0) { | ||
2146 | printf("%s: '%s' is up to date\n", applet_name, np->n_name); | ||
2147 | } | ||
2148 | free(allsrc); | ||
2149 | return estat; | ||
2150 | } | ||
2151 | |||
2152 | /* | ||
2153 | * Check structures for make. | ||
2154 | */ | ||
2155 | |||
2156 | static void | ||
2157 | print_name(struct name *np) | ||
2158 | { | ||
2159 | if (np == firstname) | ||
2160 | printf("# default target\n"); | ||
2161 | printf("%s:", np->n_name); | ||
2162 | if ((np->n_flag & N_DOUBLE)) | ||
2163 | putchar(':'); | ||
2164 | } | ||
2165 | |||
2166 | static void | ||
2167 | print_prerequisites(struct rule *rp) | ||
2168 | { | ||
2169 | struct depend *dp; | ||
2170 | |||
2171 | for (dp = rp->r_dep; dp; dp = dp->d_next) | ||
2172 | printf(" %s", dp->d_name->n_name); | ||
2173 | } | ||
2174 | |||
2175 | static void | ||
2176 | print_commands(struct rule *rp) | ||
2177 | { | ||
2178 | struct cmd *cp; | ||
2179 | |||
2180 | for (cp = rp->r_cmd; cp; cp = cp->c_next) | ||
2181 | printf("\t%s\n", cp->c_cmd); | ||
2182 | } | ||
2183 | |||
2184 | static void | ||
2185 | print_details(void) | ||
2186 | { | ||
2187 | int i; | ||
2188 | struct macro *mp; | ||
2189 | struct name *np; | ||
2190 | struct rule *rp; | ||
2191 | |||
2192 | for (i = 0; i < HTABSIZE; i++) | ||
2193 | for (mp = macrohead[i]; mp; mp = mp->m_next) | ||
2194 | printf("%s = %s\n", mp->m_name, mp->m_val); | ||
2195 | putchar('\n'); | ||
2196 | |||
2197 | for (i = 0; i < HTABSIZE; i++) { | ||
2198 | for (np = namehead[i]; np; np = np->n_next) { | ||
2199 | if (!(np->n_flag & N_DOUBLE)) { | ||
2200 | print_name(np); | ||
2201 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2202 | print_prerequisites(rp); | ||
2203 | } | ||
2204 | putchar('\n'); | ||
2205 | |||
2206 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2207 | print_commands(rp); | ||
2208 | } | ||
2209 | putchar('\n'); | ||
2210 | } else { | ||
2211 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2212 | print_name(np); | ||
2213 | print_prerequisites(rp); | ||
2214 | putchar('\n'); | ||
2215 | |||
2216 | print_commands(rp); | ||
2217 | putchar('\n'); | ||
2218 | } | ||
2219 | } | ||
2220 | } | ||
2221 | } | ||
2222 | } | ||
2223 | |||
2224 | /* | ||
2225 | * Process options from an argv array. If from_env is non-zero we're | ||
2226 | * handling options from MAKEFLAGS so skip '-C', '-f' and '-p'. | ||
2227 | */ | ||
2228 | static uint32_t | ||
2229 | process_options(char **argv, int from_env) | ||
2230 | { | ||
2231 | uint32_t flags; | ||
2232 | |||
2233 | flags = getopt32(argv, "^" OPTSTR1 OPTSTR2 "\0k-S:S-k", | ||
2234 | &numjobs, &makefiles, &dirs); | ||
2235 | if (from_env && (flags & (OPT_C | OPT_f | OPT_p))) | ||
2236 | error("invalid MAKEFLAGS"); | ||
2237 | if (posix && (flags & OPT_C)) | ||
2238 | error("-C not allowed"); | ||
2239 | |||
2240 | return flags; | ||
2241 | } | ||
2242 | |||
2243 | /* | ||
2244 | * Split the contents of MAKEFLAGS into an argv array. If the return | ||
2245 | * value (call it fargv) isn't NULL the caller should free fargv[1] and | ||
2246 | * fargv. | ||
2247 | */ | ||
2248 | static char ** | ||
2249 | expand_makeflags(void) | ||
2250 | { | ||
2251 | const char *m, *makeflags = getenv("MAKEFLAGS"); | ||
2252 | char *p, *argstr; | ||
2253 | int argc; | ||
2254 | char **argv; | ||
2255 | |||
2256 | if (makeflags == NULL) | ||
2257 | return NULL; | ||
2258 | |||
2259 | while (isblank(*makeflags)) | ||
2260 | makeflags++; | ||
2261 | |||
2262 | if (*makeflags == '\0') | ||
2263 | return NULL; | ||
2264 | |||
2265 | p = argstr = xzalloc(strlen(makeflags) + 2); | ||
2266 | |||
2267 | // If MAKEFLAGS doesn't start with a hyphen, doesn't look like | ||
2268 | // a macro definition and only contains valid option characters, | ||
2269 | // add a hyphen. | ||
2270 | argc = 3; | ||
2271 | if (makeflags[0] != '-' && strchr(makeflags, '=') == NULL) { | ||
2272 | if (strspn(makeflags, OPTSTR1) != strlen(makeflags)) | ||
2273 | error("invalid MAKEFLAGS"); | ||
2274 | *p++ = '-'; | ||
2275 | } else { | ||
2276 | // MAKEFLAGS may need to be split, estimate size of argv array. | ||
2277 | for (m = makeflags; *m; ++m) { | ||
2278 | if (isblank(*m)) | ||
2279 | argc++; | ||
2280 | } | ||
2281 | } | ||
2282 | |||
2283 | argv = xzalloc(argc * sizeof(char *)); | ||
2284 | argc = 0; | ||
2285 | argv[argc++] = (char *)applet_name; | ||
2286 | argv[argc++] = argstr; | ||
2287 | |||
2288 | // Copy MAKEFLAGS into argstr, splitting at non-escaped blanks. | ||
2289 | m = makeflags; | ||
2290 | do { | ||
2291 | if (*m == '\\' && m[1] != '\0') | ||
2292 | m++; // Skip backslash, copy next character unconditionally. | ||
2293 | else if (isblank(*m)) { | ||
2294 | // Terminate current argument and start a new one. | ||
2295 | /* *p = '\0'; - xzalloc did it */ | ||
2296 | argv[argc++] = ++p; | ||
2297 | do { | ||
2298 | m++; | ||
2299 | } while (isblank(*m)); | ||
2300 | continue; | ||
2301 | } | ||
2302 | *p++ = *m++; | ||
2303 | } while (*m != '\0'); | ||
2304 | /* *p = '\0'; - xzalloc did it */ | ||
2305 | /* argv[argc] = NULL; - and this */ | ||
2306 | |||
2307 | return argv; | ||
2308 | } | ||
2309 | |||
2310 | // These macros require special treatment | ||
2311 | #define MAKEFLAGS_SHELL "MAKEFLAGS\0SHELL\0" | ||
2312 | #define MAKEFLAGS 0 | ||
2313 | #define SHELL 1 | ||
2314 | |||
2315 | /* | ||
2316 | * Instantiate all macros in an argv-style array of pointers. Stop | ||
2317 | * processing at the first string that doesn't contain an equal sign. | ||
2318 | */ | ||
2319 | static char ** | ||
2320 | process_macros(char **argv, int level) | ||
2321 | { | ||
2322 | char *p; | ||
2323 | |||
2324 | while (*argv && (p = strchr(*argv, '=')) != NULL) { | ||
2325 | int immediate = 0; | ||
2326 | |||
2327 | if (p - 2 > *argv && p[-1] == ':' && p[-2] == ':') { | ||
2328 | if (posix) | ||
2329 | error("invalid macro assignment"); | ||
2330 | immediate = M_IMMEDIATE; | ||
2331 | p[-2] = '\0'; | ||
2332 | } else | ||
2333 | *p = '\0'; | ||
2334 | if (level != 3 || index_in_strings(MAKEFLAGS_SHELL, *argv) < 0) { | ||
2335 | if (immediate) { | ||
2336 | char *exp = expand_macros(p + 1, FALSE); | ||
2337 | setmacro(*argv, exp, level | immediate); | ||
2338 | free(exp); | ||
2339 | } else { | ||
2340 | setmacro(*argv, p + 1, level); | ||
2341 | } | ||
2342 | } | ||
2343 | *p = '='; | ||
2344 | if (immediate) | ||
2345 | p[-2] = ':'; | ||
2346 | |||
2347 | argv++; | ||
2348 | } | ||
2349 | return argv; | ||
2350 | } | ||
2351 | |||
2352 | /* | ||
2353 | * Update the MAKEFLAGS macro and environment variable to include any | ||
2354 | * command line options that don't have their default value (apart from | ||
2355 | * -f, -p and -S). Also add any macros defined on the command line or | ||
2356 | * by the MAKEFLAGS environment variable (apart from MAKEFLAGS itself). | ||
2357 | * Add macros that were defined on the command line to the environment. | ||
2358 | */ | ||
2359 | static void | ||
2360 | update_makeflags(void) | ||
2361 | { | ||
2362 | int i; | ||
2363 | char optbuf[] = "-?"; | ||
2364 | char *makeflags = NULL; | ||
2365 | char *macro, *s; | ||
2366 | const char *t; | ||
2367 | struct macro *mp; | ||
2368 | |||
2369 | t = OPTSTR1; | ||
2370 | for (i = 0; *t; t++) { | ||
2371 | if (*t == ':' || *t == '+') | ||
2372 | continue; | ||
2373 | if ((opts & OPT_MASK & (1 << i))) { | ||
2374 | optbuf[1] = *t; | ||
2375 | makeflags = xappendword(makeflags, optbuf); | ||
2376 | if (*t == 'j') { | ||
2377 | s = auto_string(xasprintf("%d", numjobs)); | ||
2378 | makeflags = xappendword(makeflags, s); | ||
2379 | } | ||
2380 | } | ||
2381 | i++; | ||
2382 | } | ||
2383 | |||
2384 | for (i = 0; i < HTABSIZE; ++i) { | ||
2385 | for (mp = macrohead[i]; mp; mp = mp->m_next) { | ||
2386 | if (mp->m_level == 1 || mp->m_level == 2) { | ||
2387 | int idx = index_in_strings(MAKEFLAGS_SHELL, mp->m_name); | ||
2388 | if (idx == MAKEFLAGS) | ||
2389 | continue; | ||
2390 | macro = xzalloc(strlen(mp->m_name) + 2 * strlen(mp->m_val) + 1); | ||
2391 | s = stpcpy(macro, mp->m_name); | ||
2392 | *s++ = '='; | ||
2393 | for (t = mp->m_val; *t; t++) { | ||
2394 | if (*t == '\\' || isblank(*t)) | ||
2395 | *s++ = '\\'; | ||
2396 | *s++ = *t; | ||
2397 | } | ||
2398 | /* *s = '\0'; - xzalloc did it */ | ||
2399 | |||
2400 | makeflags = xappendword(makeflags, macro); | ||
2401 | free(macro); | ||
2402 | |||
2403 | // Add command line macro definitions to the environment | ||
2404 | if (mp->m_level == 1 && idx != SHELL) | ||
2405 | setenv(mp->m_name, mp->m_val, 1); | ||
2406 | } | ||
2407 | } | ||
2408 | } | ||
2409 | |||
2410 | if (makeflags) { | ||
2411 | setmacro("MAKEFLAGS", makeflags, 0); | ||
2412 | setenv("MAKEFLAGS", makeflags, 1); | ||
2413 | free(makeflags); | ||
2414 | } | ||
2415 | } | ||
2416 | |||
2417 | #if !ENABLE_PLATFORM_MINGW32 | ||
2418 | static void | ||
2419 | make_handler(int sig) | ||
2420 | { | ||
2421 | signal(sig, SIG_DFL); | ||
2422 | remove_target(); | ||
2423 | kill(getpid(), sig); | ||
2424 | } | ||
2425 | |||
2426 | static void | ||
2427 | init_signal(int sig) | ||
2428 | { | ||
2429 | struct sigaction sa, new_action; | ||
2430 | |||
2431 | sigemptyset(&new_action.sa_mask); | ||
2432 | new_action.sa_flags = 0; | ||
2433 | new_action.sa_handler = make_handler; | ||
2434 | |||
2435 | sigaction(sig, NULL, &sa); | ||
2436 | if (sa.sa_handler != SIG_IGN) | ||
2437 | sigaction_set(sig, &new_action); | ||
2438 | } | ||
2439 | #endif | ||
2440 | |||
2441 | /* | ||
2442 | * If the global option flag associated with a special target hasn't | ||
2443 | * been set mark all prerequisites of the target with a flag. If the | ||
2444 | * target had no prerequisites set the global option flag. | ||
2445 | */ | ||
2446 | static void | ||
2447 | mark_special(const char *special, uint32_t oflag, uint16_t nflag) | ||
2448 | { | ||
2449 | struct name *np; | ||
2450 | struct rule *rp; | ||
2451 | struct depend *dp; | ||
2452 | int marked = FALSE; | ||
2453 | |||
2454 | if (!(opts & oflag) && (np = findname(special))) { | ||
2455 | for (rp = np->n_rule; rp; rp = rp->r_next) { | ||
2456 | for (dp = rp->r_dep; dp; dp = dp->d_next) { | ||
2457 | dp->d_name->n_flag |= nflag; | ||
2458 | marked = TRUE; | ||
2459 | } | ||
2460 | } | ||
2461 | |||
2462 | if (!marked) | ||
2463 | opts |= oflag; | ||
2464 | } | ||
2465 | } | ||
2466 | |||
2467 | int make_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
2468 | int make_main(int argc UNUSED_PARAM, char **argv) | ||
2469 | { | ||
2470 | const char *path, *newpath = NULL; | ||
2471 | char **fargv, **fargv0; | ||
2472 | const char *dir, *file; | ||
2473 | char def_make[] = "makefile"; | ||
2474 | int estat; | ||
2475 | FILE *ifd; | ||
2476 | |||
2477 | INIT_G(); | ||
2478 | |||
2479 | #if ENABLE_FEATURE_MAKE_POSIX | ||
2480 | if (argv[1] && strcmp(argv[1], "--posix") == 0) { | ||
2481 | argv[1] = argv[0]; | ||
2482 | ++argv; | ||
2483 | --argc; | ||
2484 | setenv("PDPMAKE_POSIXLY_CORRECT", "", 1); | ||
2485 | posix = TRUE; | ||
2486 | } else { | ||
2487 | posix = getenv("PDPMAKE_POSIXLY_CORRECT") != NULL; | ||
2488 | } | ||
2489 | #endif | ||
2490 | |||
2491 | if (!posix) { | ||
2492 | path = argv[0]; | ||
2493 | #if ENABLE_PLATFORM_MINGW32 | ||
2494 | if (has_path(argv[0])) { | ||
2495 | // Add extension if necessary, else realpath() will fail | ||
2496 | char *p = xmalloc(strlen(argv[0]) + 5); | ||
2497 | add_win32_extension(strcpy(p, argv[0])); | ||
2498 | path = newpath = xmalloc_realpath(p); | ||
2499 | free(p); | ||
2500 | if (!path) { | ||
2501 | bb_perror_msg("can't resolve path for %s", argv[0]); | ||
2502 | } | ||
2503 | } | ||
2504 | #else | ||
2505 | if (argv[0][0] != '/' && strchr(argv[0], '/')) { | ||
2506 | // Make relative path absolute | ||
2507 | path = newpath = realpath(argv[0], NULL); | ||
2508 | if (!path) { | ||
2509 | bb_perror_msg("can't resolve path for %s", argv[0]); | ||
2510 | } | ||
2511 | } | ||
2512 | #endif | ||
2513 | } else { | ||
2514 | path = "make"; | ||
2515 | } | ||
2516 | |||
2517 | // Process options from MAKEFLAGS | ||
2518 | fargv = fargv0 = expand_makeflags(); | ||
2519 | if (fargv0) { | ||
2520 | opts = process_options(fargv, TRUE); | ||
2521 | fargv = fargv0 + optind; | ||
2522 | } | ||
2523 | // Reset getopt(3) so we can call it again | ||
2524 | GETOPT_RESET(); | ||
2525 | |||
2526 | // Process options from the command line | ||
2527 | opts |= process_options(argv, FALSE); | ||
2528 | argv += optind; | ||
2529 | |||
2530 | while ((dir = llist_pop(&dirs))) { | ||
2531 | if (chdir(dir) == -1) { | ||
2532 | bb_perror_msg("can't chdir to %s", dir); | ||
2533 | } | ||
2534 | } | ||
2535 | |||
2536 | #if !ENABLE_PLATFORM_MINGW32 | ||
2537 | init_signal(SIGHUP); | ||
2538 | init_signal(SIGTERM); | ||
2539 | #endif | ||
2540 | |||
2541 | setmacro("$", "$", 0 | M_VALID); | ||
2542 | |||
2543 | // Process macro definitions from the command line | ||
2544 | argv = process_macros(argv, 1); | ||
2545 | |||
2546 | // Process macro definitions from MAKEFLAGS | ||
2547 | if (fargv) { | ||
2548 | process_macros(fargv, 2); | ||
2549 | free(fargv0[1]); | ||
2550 | free(fargv0); | ||
2551 | } | ||
2552 | |||
2553 | // Process macro definitions from the environment | ||
2554 | process_macros(environ, 3 | M_VALID); | ||
2555 | |||
2556 | // Update MAKEFLAGS and environment | ||
2557 | update_makeflags(); | ||
2558 | |||
2559 | // Read built-in rules | ||
2560 | input(NULL, 0); | ||
2561 | |||
2562 | setmacro("SHELL", "/bin/sh", 4); | ||
2563 | setmacro("MAKE", path, 4); | ||
2564 | free((void *)newpath); | ||
2565 | |||
2566 | if (!makefiles) { // Look for a default Makefile | ||
2567 | #if !ENABLE_PLATFORM_MINGW32 | ||
2568 | for (; def_make[0] >= 'M'; def_make[0] -= 0x20) { | ||
2569 | #else | ||
2570 | { | ||
2571 | #endif | ||
2572 | if ((ifd = fopen(def_make, "r")) != NULL) { | ||
2573 | makefile = def_make; | ||
2574 | goto read_makefile; | ||
2575 | } | ||
2576 | } | ||
2577 | error("no makefile found"); | ||
2578 | } | ||
2579 | |||
2580 | while ((file = llist_pop(&makefiles))) { | ||
2581 | if (strcmp(file, "-") == 0) { // Can use stdin as makefile | ||
2582 | ifd = stdin; | ||
2583 | makefile = "stdin"; | ||
2584 | } else { | ||
2585 | ifd = xfopen_for_read(file); | ||
2586 | makefile = file; | ||
2587 | } | ||
2588 | read_makefile: | ||
2589 | input(ifd, 0); | ||
2590 | fclose(ifd); | ||
2591 | makefile = NULL; | ||
2592 | } | ||
2593 | |||
2594 | if (print) | ||
2595 | print_details(); | ||
2596 | |||
2597 | mark_special(".SILENT", OPT_s, N_SILENT); | ||
2598 | mark_special(".IGNORE", OPT_i, N_IGNORE); | ||
2599 | mark_special(".PRECIOUS", OPT_precious, N_PRECIOUS); | ||
2600 | if (!posix) | ||
2601 | mark_special(".PHONY", OPT_phony, N_PHONY); | ||
2602 | |||
2603 | estat = 0; | ||
2604 | if (*argv == NULL) { | ||
2605 | if (!firstname) | ||
2606 | error("no targets defined"); | ||
2607 | estat = make(firstname, 0); | ||
2608 | } else { | ||
2609 | while (*argv != NULL) | ||
2610 | estat |= make(newname(*argv++), 0); | ||
2611 | } | ||
2612 | |||
2613 | #if ENABLE_FEATURE_CLEAN_UP | ||
2614 | freenames(); | ||
2615 | freemacros(); | ||
2616 | llist_free(makefiles, NULL); | ||
2617 | llist_free(dirs, NULL); | ||
2618 | #endif | ||
2619 | |||
2620 | return estat; | ||
2621 | } | ||
diff --git a/testsuite/make.tests b/testsuite/make.tests new file mode 100755 index 000000000..75091b0f7 --- /dev/null +++ b/testsuite/make.tests | |||
@@ -0,0 +1,413 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | . ./testing.sh | ||
4 | |||
5 | # testing "test name" "command" "expected result" "file input" "stdin" | ||
6 | |||
7 | testing "Basic makefile" \ | ||
8 | "make -f -" "target\n" "" ' | ||
9 | target: | ||
10 | @echo target | ||
11 | ' | ||
12 | |||
13 | # .DEFAULT rules with no commands or some prerequisites are ignored. | ||
14 | # .DEFAULT rules with commands can be redefined. | ||
15 | testing ".DEFAULT rule" \ | ||
16 | "make -f - default" "default2\n" "" ' | ||
17 | .DEFAULT: ignored | ||
18 | .DEFAULT: | ||
19 | @echo default1 | ||
20 | .DEFAULT: | ||
21 | @echo default2 | ||
22 | target: | ||
23 | ' | ||
24 | |||
25 | # Macros should be expanded before suffix substitution. The suffixes | ||
26 | # can be obtained by macro expansion. | ||
27 | testing "Macro expansion and suffix substitution" \ | ||
28 | "make -f -" "src1.o src2.o\n" "" ' | ||
29 | DOTC = .c | ||
30 | DOTO = .o | ||
31 | SRC1 = src1.c | ||
32 | SRCS = $(SRC1) src2.c | ||
33 | target: | ||
34 | @echo $(SRCS:$(DOTC)=$(DOTO)) | ||
35 | ' | ||
36 | |||
37 | # Indeed, everything after the <colon> can be obtained by macro | ||
38 | # macro expansion. | ||
39 | testing "Macro expansion and suffix substitution 2" \ | ||
40 | "make -f -" "src1.o src2.o\n" "" ' | ||
41 | DOTS = .c=.o | ||
42 | SRC1 = src1.c | ||
43 | SRCS = $(SRC1) src2.c | ||
44 | target: | ||
45 | @echo $(SRCS:$(DOTS)) | ||
46 | ' | ||
47 | |||
48 | # It should be possible for an inference rule to determine that a | ||
49 | # prerequisite can be created using an explicit rule. | ||
50 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
51 | testing "Inference rule with explicit rule for prerequisite" \ | ||
52 | "make -f -" "touch x.p\ncat x.p >x.q\n" "" ' | ||
53 | .SUFFIXES: .p .q | ||
54 | x.q: | ||
55 | x.p: | ||
56 | touch $@ | ||
57 | .p.q: | ||
58 | cat $< >$@ | ||
59 | ' | ||
60 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
61 | |||
62 | # A macro created using ::= remembers it's of type immediate-expansion. | ||
63 | # Immediate expansion also occurs when += is used to append to such a macro. | ||
64 | testing "Appending to immediate-expansion macro" \ | ||
65 | "make -f -" \ | ||
66 | "hello 1 2 3\nhello 4 4\n" "" ' | ||
67 | world = 1 | ||
68 | hello ::= hello $(world) | ||
69 | world = 2 | ||
70 | hello += $(world) | ||
71 | world = 3 | ||
72 | hello += $(world) | ||
73 | world = 4 | ||
74 | |||
75 | world = 1 | ||
76 | reset ::= hello $(world) | ||
77 | world = 2 | ||
78 | # No longer immediate-expansion | ||
79 | reset = hello $(world) | ||
80 | world = 3 | ||
81 | reset += $(world) | ||
82 | world = 4 | ||
83 | |||
84 | target: | ||
85 | @echo $(hello) | ||
86 | @echo $(reset) | ||
87 | ' | ||
88 | |||
89 | # basic pattern macro expansion | ||
90 | testing "Basic pattern macro expansion" \ | ||
91 | "make -f -" \ | ||
92 | "obj/util.o obj/main.o\n" "" ' | ||
93 | SRC = src/util.c src/main.c | ||
94 | OBJ = $(SRC:src/%.c=obj/%.o) | ||
95 | |||
96 | target: | ||
97 | @echo $(OBJ) | ||
98 | ' | ||
99 | |||
100 | # pattern macro expansion; match any value | ||
101 | testing "Pattern macro expansion; match any value" \ | ||
102 | "make -f -" \ | ||
103 | "any_value.o\n" "" ' | ||
104 | SRC = any_value | ||
105 | OBJ = $(SRC:%=%.o) | ||
106 | |||
107 | target: | ||
108 | @echo $(OBJ) | ||
109 | ' | ||
110 | |||
111 | # pattern macro expansion with empty rvalue | ||
112 | testing "Pattern macro expansion with empty rvalue" \ | ||
113 | "make -f -" \ | ||
114 | "\n" "" ' | ||
115 | SRC = util.c main.c | ||
116 | OBJ = $(SRC:%.c=) | ||
117 | |||
118 | target: | ||
119 | @echo $(OBJ) | ||
120 | ' | ||
121 | |||
122 | # pattern macro expansion with multiple <percent> in rvalue | ||
123 | # POSIX requires the first <percent> to be expanded, others | ||
124 | # may or may not be expanded. Permit either case. | ||
125 | testing "Pattern macro expansion with multiple <percent> in rvalue" \ | ||
126 | "make -f - | sed 's/mainmainmain/main%%/'" \ | ||
127 | "main%%\n" "" ' | ||
128 | SRC = main.c | ||
129 | OBJ = $(SRC:%.c=%%%) | ||
130 | |||
131 | target: | ||
132 | @echo $(OBJ) | ||
133 | ' | ||
134 | |||
135 | # pattern macro expansion; zero match | ||
136 | testing "Pattern macro expansion; zero match" \ | ||
137 | "make -f -" \ | ||
138 | "nsnp\n" "" ' | ||
139 | WORD = osop | ||
140 | REPL = $(WORD:os%op=ns%np) | ||
141 | |||
142 | target: | ||
143 | @echo $(REPL) | ||
144 | ' | ||
145 | |||
146 | # Check that MAKE will contain argv[0], e.g make in this case | ||
147 | testing "Basic MAKE macro expansion" \ | ||
148 | "make -f -" \ | ||
149 | "make\n" "" ' | ||
150 | target: | ||
151 | @echo $(MAKE) | ||
152 | ' | ||
153 | |||
154 | # Check that MAKE defined as environment variable will overwrite default MAKE | ||
155 | testing "MAKE macro expansion; overwrite with env macro" \ | ||
156 | "MAKE=hello make -f -" \ | ||
157 | "hello\n" "" ' | ||
158 | target: | ||
159 | @echo $(MAKE) | ||
160 | ' | ||
161 | |||
162 | # Check that MAKE defined on the command-line will overwrite MAKE defined in | ||
163 | # Makefile | ||
164 | testing "MAKE macro expansion; overwrite with command-line macro" \ | ||
165 | "make -f - MAKE=hello" \ | ||
166 | "hello\n" "" ' | ||
167 | MAKE = test | ||
168 | |||
169 | target: | ||
170 | @echo $(MAKE) | ||
171 | ' | ||
172 | |||
173 | # POSIX draft states that if make was invoked using relative path, MAKE must | ||
174 | # contain absolute path, not just argv[0] | ||
175 | testing "MAKE macro expansion; turn relative path into absolute" \ | ||
176 | "../runtest-tempdir-links/make -f -" \ | ||
177 | "ok\n" "" ' | ||
178 | target: | ||
179 | @test -e "$(MAKE)" && test "$(MAKE)" = "$$(env which make)" && echo ok | ||
180 | ' | ||
181 | |||
182 | # $? contains prerequisites newer than target, file2 in this case | ||
183 | # $^ has all prerequisites, file1 and file2 | ||
184 | touch -t 202206171200 file1 | ||
185 | touch -t 202206171201 target | ||
186 | touch -t 202206171202 file2 | ||
187 | testing "Compare \$? and \$^ internal macros" \ | ||
188 | "make -f -" \ | ||
189 | "file2\nfile1 file2\n" "" ' | ||
190 | target: file1 file2 | ||
191 | @echo $? | ||
192 | @echo $^ | ||
193 | ' | ||
194 | rm -f target file1 file2 | ||
195 | |||
196 | # Phony targets are executed (once) even if a matching file exists. | ||
197 | # A .PHONY target with no prerequisites is ignored. | ||
198 | touch -t 202206171201 target | ||
199 | testing "Phony target" \ | ||
200 | "make -f -" \ | ||
201 | "phony\n" "" ' | ||
202 | .PHONY: target | ||
203 | .PHONY: | ||
204 | target: | ||
205 | @echo phony | ||
206 | ' | ||
207 | rm -f target | ||
208 | |||
209 | # Phony targets aren't touched with -t | ||
210 | testing "Phony target not touched" \ | ||
211 | "make -t -f - >/dev/null && test -f target && echo target" \ | ||
212 | "" "" ' | ||
213 | .PHONY: target | ||
214 | target: | ||
215 | @: | ||
216 | ' | ||
217 | rm -f target | ||
218 | |||
219 | # Include files are created or brought up-to-date | ||
220 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
221 | testing "Create include file" \ | ||
222 | "make -f -" \ | ||
223 | "made\n" "" ' | ||
224 | target: | ||
225 | @echo $(VAR) | ||
226 | mk: | ||
227 | @echo "VAR = made" >mk | ||
228 | include mk | ||
229 | ' | ||
230 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
231 | |||
232 | # Include files are created or brought up-to-date even when the -n | ||
233 | # option is given. | ||
234 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
235 | testing "Create include file even with -n" \ | ||
236 | "make -n -f -" \ | ||
237 | "echo made\n" "" ' | ||
238 | target: | ||
239 | @echo $(VAR) | ||
240 | mk: | ||
241 | @echo "VAR = made" >mk | ||
242 | include mk | ||
243 | ' | ||
244 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
245 | |||
246 | # Failure to create an include file isn't an error. (Provided the | ||
247 | # include line is ignoring non-existent files.) | ||
248 | testing "Failure to create include file is OK" \ | ||
249 | "make -f -" \ | ||
250 | "OK\n" "" ' | ||
251 | target: | ||
252 | @echo OK | ||
253 | mk: | ||
254 | @: | ||
255 | -include mk | ||
256 | ' | ||
257 | |||
258 | # Nested macro expansion is allowed. This should be compatible | ||
259 | # with other implementations. | ||
260 | testing "Nested macro expansion" \ | ||
261 | "make -f -" "0 bc\n1 d\n2\n3\n4 bcd\n5 bcd\n" "" ' | ||
262 | a = b | ||
263 | b = c | ||
264 | c = d | ||
265 | $(a:.q=.v)$(b:.z=.v) = bc | ||
266 | bcd = bcd | ||
267 | target: | ||
268 | @echo 0 $(bc) | ||
269 | @echo 1 $($($(a))) | ||
270 | @echo 2 $($(a) $(b) $(c)) | ||
271 | @echo 3 $($a $b $c) | ||
272 | @echo 4 $($(a)$(b)$(c)) | ||
273 | @echo 5 $($a$b$c) | ||
274 | ' | ||
275 | |||
276 | testing "Double-colon rule" \ | ||
277 | "make -f -" "target1\ntarget2\n" "" ' | ||
278 | target:: | ||
279 | @echo target1 | ||
280 | target:: | ||
281 | @echo target2 | ||
282 | ' | ||
283 | |||
284 | # There was a bug whereby the modification time of a file created by | ||
285 | # double-colon rules wasn't correctly updated. This test checks that | ||
286 | # the bug is now fixed. | ||
287 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
288 | touch -t 202206171200 file1 | ||
289 | touch -t 202206171201 intermediate | ||
290 | touch -t 202206171202 target | ||
291 | touch -t 202206171203 file2 | ||
292 | testing "Target depends on prerequisite updated by double-colon rule" \ | ||
293 | "make -f -" \ | ||
294 | "file2\n" "" ' | ||
295 | target: intermediate | ||
296 | @cat intermediate | ||
297 | intermediate:: file1 | ||
298 | @echo file1 >>intermediate | ||
299 | intermediate:: file2 | ||
300 | @echo file2 >>intermediate | ||
301 | ' | ||
302 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
303 | |||
304 | # Use chained inference rules to determine prerequisites. | ||
305 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
306 | touch target.p | ||
307 | testing "Chained inference rules" \ | ||
308 | "make -s -f - target.s" \ | ||
309 | "target.q\ntarget.r\ntarget.s\n" "" ' | ||
310 | .SUFFIXES: .p .q .r .s | ||
311 | .p.q: | ||
312 | @cp $< $*.q | ||
313 | @echo $*.q | ||
314 | .q.r: | ||
315 | @cp $< $*.r | ||
316 | @echo $*.r | ||
317 | .r.s: | ||
318 | @cp $< $*.s | ||
319 | @echo $*.s | ||
320 | ' | ||
321 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
322 | |||
323 | # Assign the output of a shell command to a macro. | ||
324 | testing "Shell assignment" \ | ||
325 | "make -f -" \ | ||
326 | "1 2 3 4\n" "" ' | ||
327 | hello != echo 1; echo 2; echo 3; echo; echo | ||
328 | |||
329 | target: | ||
330 | @echo "$(hello) 4" | ||
331 | ' | ||
332 | |||
333 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
334 | # make supports *, ? and [] wildcards in targets and prerequisites | ||
335 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
336 | touch -t 202206171201 t1a t2aa t3b | ||
337 | touch s1a s2aa s3b | ||
338 | testing "Expand wildcards in filenames" \ | ||
339 | "make -f - t1a t2aa t3b" \ | ||
340 | "t1a s1a s2aa s3b\nt2aa s1a s2aa s3b\nt3b s1a s2aa s3b\n" "" ' | ||
341 | t1? t2* t3[abc]: s1? s2* s3[abc] | ||
342 | @echo $@ $? | ||
343 | ' | ||
344 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
345 | |||
346 | # Skip duplicate entries in $? and $^ | ||
347 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
348 | touch -t 202206171200 file1 file3 | ||
349 | touch -t 202206171201 target | ||
350 | touch -t 202206171202 file2 | ||
351 | testing "Skip duplicate entries in \$? and \$^" \ | ||
352 | "make -f -" \ | ||
353 | "file2\nfile1 file2 file3\n" "" ' | ||
354 | target: file1 file2 file2 file3 file3 | ||
355 | @echo $? | ||
356 | @echo $^ | ||
357 | ' | ||
358 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
359 | |||
360 | # Skip duplicate entries in $? and $^, with each double-colon rule | ||
361 | # handled separately | ||
362 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
363 | touch -t 202206171200 file1 file3 | ||
364 | touch -t 202206171201 target | ||
365 | touch -t 202206171202 file2 | ||
366 | testing "Skip duplicate entries: double-colon rules" \ | ||
367 | "make -f -" \ | ||
368 | "file2\nfile1 file3 file2\nfile2\nfile2 file3\n" "" ' | ||
369 | target:: file1 file3 file1 file2 file3 | ||
370 | @echo $? | ||
371 | @echo $^ | ||
372 | target:: file2 file3 file3 | ||
373 | @echo $? | ||
374 | @echo $^ | ||
375 | ' | ||
376 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
377 | |||
378 | # Skip duplicate entries in $? and $^, with each double-colon rule | ||
379 | # handled separately. No prerequisites out-of-date in the first. | ||
380 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
381 | touch -t 202206171200 file1 file3 | ||
382 | touch -t 202206171201 target | ||
383 | touch -t 202206171202 file2 | ||
384 | testing "Skip duplicate entries: double-colon rules, only second invoked" \ | ||
385 | "make -f -" \ | ||
386 | "file2\nfile2 file3\n" "" ' | ||
387 | target:: file1 file3 file1 file3 | ||
388 | @echo $? | ||
389 | @echo $^ | ||
390 | target:: file2 file3 file3 | ||
391 | @echo $? | ||
392 | @echo $^ | ||
393 | ' | ||
394 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
395 | |||
396 | # Double-colon rules didn't work properly if their target was phony: | ||
397 | # - they didn't ignore the presence of a file matching the target name; | ||
398 | # - they were also invoked as if they were a single-colon rule. | ||
399 | mkdir make.tempdir && cd make.tempdir || exit 1 | ||
400 | touch -t 202206171200 file1 | ||
401 | touch -t 202206171201 target | ||
402 | testing "Phony target of double-colon rule" \ | ||
403 | "make -f - 2>&1" \ | ||
404 | "unconditional\nconditional\n" "" ' | ||
405 | .PHONY: target | ||
406 | target:: | ||
407 | @echo unconditional | ||
408 | target:: file1 | ||
409 | @echo conditional | ||
410 | file1: | ||
411 | @touch file1 | ||
412 | ' | ||
413 | cd .. || exit 1; rm -rf make.tempdir 2>/dev/null | ||
diff --git a/win32/Kbuild b/win32/Kbuild index 9f486d5e9..10614461a 100644 --- a/win32/Kbuild +++ b/win32/Kbuild | |||
@@ -8,6 +8,7 @@ lib-$(CONFIG_PLATFORM_MINGW32) += dirent.o | |||
8 | lib-$(CONFIG_PLATFORM_MINGW32) += env.o | 8 | lib-$(CONFIG_PLATFORM_MINGW32) += env.o |
9 | lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o | 9 | lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o |
10 | lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o | 10 | lib-$(CONFIG_PLATFORM_MINGW32) += fsync.o |
11 | lib-$(CONFIG_MAKE) += glob.o | ||
11 | lib-$(CONFIG_PLATFORM_MINGW32) += inet_pton.o | 12 | lib-$(CONFIG_PLATFORM_MINGW32) += inet_pton.o |
12 | lib-$(CONFIG_PLATFORM_MINGW32) += ioctl.o | 13 | lib-$(CONFIG_PLATFORM_MINGW32) += ioctl.o |
13 | lib-$(CONFIG_FEATURE_PRNG_ISAAC) += isaac.o | 14 | lib-$(CONFIG_FEATURE_PRNG_ISAAC) += isaac.o |
diff --git a/win32/glob.c b/win32/glob.c new file mode 100644 index 000000000..1cc6483e7 --- /dev/null +++ b/win32/glob.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | glob from musl (https://www.musl-libc.org/). | ||
3 | |||
4 | MIT licensed: | ||
5 | |||
6 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #include "libbb.h" | ||
30 | #include <glob.h> | ||
31 | #include <fnmatch.h> | ||
32 | |||
33 | struct match | ||
34 | { | ||
35 | struct match *next; | ||
36 | char name[]; | ||
37 | }; | ||
38 | |||
39 | static int append(struct match **tail, const char *name, size_t len, int mark) | ||
40 | { | ||
41 | struct match *new = malloc(sizeof(struct match) + len + 2); | ||
42 | if (!new) return -1; | ||
43 | (*tail)->next = new; | ||
44 | new->next = NULL; | ||
45 | memcpy(new->name, name, len+1); | ||
46 | if (mark && len && name[len-1]!='/') { | ||
47 | new->name[len] = '/'; | ||
48 | new->name[len+1] = 0; | ||
49 | } | ||
50 | *tail = new; | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*errfunc)(const char *path, int err), struct match **tail) | ||
55 | { | ||
56 | ptrdiff_t i, j; | ||
57 | int in_bracket, overflow; | ||
58 | char *p2, saved_sep; | ||
59 | int readerr, old_errno; | ||
60 | DIR *dir; | ||
61 | struct dirent *de; | ||
62 | |||
63 | /* If GLOB_MARK is unused, we don't care about type. */ | ||
64 | if (!type && !(flags & GLOB_MARK)) type = DT_REG; | ||
65 | |||
66 | /* Special-case the remaining pattern being all slashes, in | ||
67 | * which case we can use caller-passed type if it's a dir. */ | ||
68 | if (*pat && type!=DT_DIR) type = 0; | ||
69 | while (pos+1 < PATH_MAX && *pat=='/') buf[pos++] = *pat++; | ||
70 | |||
71 | /* Consume maximal [escaped-]literal prefix of pattern, copying | ||
72 | * and un-escaping it to the running buffer as we go. */ | ||
73 | i=0; j=0; | ||
74 | in_bracket = 0; overflow = 0; | ||
75 | for (; pat[i]!='*' && pat[i]!='?' && (!in_bracket || pat[i]!=']'); i++) { | ||
76 | if (!pat[i]) { | ||
77 | if (overflow) return 0; | ||
78 | pat += i; | ||
79 | pos += j; | ||
80 | i = j = 0; | ||
81 | break; | ||
82 | } else if (pat[i] == '[') { | ||
83 | in_bracket = 1; | ||
84 | } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { | ||
85 | /* Backslashes inside a bracket are (at least by | ||
86 | * our interpretation) non-special, so if next | ||
87 | * char is ']' we have a complete expression. */ | ||
88 | if (in_bracket && pat[i+1]==']') break; | ||
89 | /* Unpaired final backslash never matches. */ | ||
90 | if (!pat[i+1]) return 0; | ||
91 | i++; | ||
92 | } | ||
93 | if (pat[i] == '/') { | ||
94 | if (overflow) return 0; | ||
95 | in_bracket = 0; | ||
96 | pat += i+1; | ||
97 | i = -1; | ||
98 | pos += j+1; | ||
99 | j = -1; | ||
100 | } | ||
101 | /* Only store a character if it fits in the buffer, but if | ||
102 | * a potential bracket expression is open, the overflow | ||
103 | * must be remembered and handled later only if the bracket | ||
104 | * is unterminated (and thereby a literal), so as not to | ||
105 | * disallow long bracket expressions with short matches. */ | ||
106 | if (pos+(j+1) < PATH_MAX) { | ||
107 | buf[pos+j++] = pat[i]; | ||
108 | } else if (in_bracket) { | ||
109 | overflow = 1; | ||
110 | } else { | ||
111 | return 0; | ||
112 | } | ||
113 | /* If we consume any new components, the caller-passed type | ||
114 | * or dummy type from above is no longer valid. */ | ||
115 | type = 0; | ||
116 | } | ||
117 | buf[pos] = 0; | ||
118 | if (!*pat) { | ||
119 | /* If we consumed any components above, or if GLOB_MARK is | ||
120 | * requested and we don't yet know if the match is a dir, | ||
121 | * we must confirm the file exists and/or determine its type. | ||
122 | * | ||
123 | * If marking dirs, symlink type is inconclusive; we need the | ||
124 | * type for the symlink target, and therefore must try stat | ||
125 | * first unless type is known not to be a symlink. Otherwise, | ||
126 | * or if that fails, use lstat for determining existence to | ||
127 | * avoid false negatives in the case of broken symlinks. */ | ||
128 | struct stat st; | ||
129 | if ((flags & GLOB_MARK) && (!type||type==DT_LNK) && !stat(buf, &st)) { | ||
130 | if (S_ISDIR(st.st_mode)) type = DT_DIR; | ||
131 | else type = DT_REG; | ||
132 | } | ||
133 | if (!type && lstat(buf, &st)) { | ||
134 | if (errno!=ENOENT && (errfunc(buf, errno) || (flags & GLOB_ERR))) | ||
135 | return GLOB_ABORTED; | ||
136 | return 0; | ||
137 | } | ||
138 | if (append(tail, buf, pos, (flags & GLOB_MARK) && type==DT_DIR)) | ||
139 | return GLOB_NOSPACE; | ||
140 | return 0; | ||
141 | } | ||
142 | p2 = strchr(pat, '/'); | ||
143 | saved_sep = '/'; | ||
144 | /* Check if the '/' was escaped and, if so, remove the escape char | ||
145 | * so that it will not be unpaired when passed to fnmatch. */ | ||
146 | if (p2 && !(flags & GLOB_NOESCAPE)) { | ||
147 | char *p; | ||
148 | for (p=p2; p>pat && p[-1]=='\\'; p--); | ||
149 | if ((p2-p)%2) { | ||
150 | p2--; | ||
151 | saved_sep = '\\'; | ||
152 | } | ||
153 | } | ||
154 | dir = opendir(pos ? buf : "."); | ||
155 | if (!dir) { | ||
156 | if (errfunc(buf, errno) || (flags & GLOB_ERR)) | ||
157 | return GLOB_ABORTED; | ||
158 | return 0; | ||
159 | } | ||
160 | old_errno = errno; | ||
161 | while (errno=0, de=readdir(dir)) { | ||
162 | size_t l; | ||
163 | int fnm_flags, r; | ||
164 | |||
165 | /* Quickly skip non-directories when there's pattern left. */ | ||
166 | if (p2 && de->d_type && de->d_type!=DT_DIR && de->d_type!=DT_LNK) | ||
167 | continue; | ||
168 | |||
169 | l = strlen(de->d_name); | ||
170 | if (l >= PATH_MAX-pos) continue; | ||
171 | |||
172 | if (p2) *p2 = 0; | ||
173 | |||
174 | fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | ||
175 | | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); | ||
176 | |||
177 | if (fnmatch(pat, de->d_name, fnm_flags)) | ||
178 | continue; | ||
179 | |||
180 | /* With GLOB_PERIOD, don't allow matching . or .. unless | ||
181 | * fnmatch would match them with FNM_PERIOD rules in effect. */ | ||
182 | if (p2 && (flags & GLOB_PERIOD) && de->d_name[0]=='.' | ||
183 | && (!de->d_name[1] || (de->d_name[1]=='.' && !de->d_name[2])) | ||
184 | && fnmatch(pat, de->d_name, fnm_flags | FNM_PERIOD)) | ||
185 | continue; | ||
186 | |||
187 | memcpy(buf+pos, de->d_name, l+1); | ||
188 | if (p2) *p2 = saved_sep; | ||
189 | r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : (char *)"", flags, errfunc, tail); | ||
190 | if (r) { | ||
191 | closedir(dir); | ||
192 | return r; | ||
193 | } | ||
194 | } | ||
195 | readerr = errno; | ||
196 | if (p2) *p2 = saved_sep; | ||
197 | closedir(dir); | ||
198 | if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) | ||
199 | return GLOB_ABORTED; | ||
200 | errno = old_errno; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int ignore_err(const char *path UNUSED_PARAM, int err UNUSED_PARAM) | ||
205 | { | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void freelist(struct match *head) | ||
210 | { | ||
211 | struct match *match, *next; | ||
212 | for (match=head->next; match; match=next) { | ||
213 | next = match->next; | ||
214 | free(match); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | #if !ENABLE_PLATFORM_MINGW32 | ||
219 | static int sort(const void *a, const void *b) | ||
220 | { | ||
221 | return strcmp(*(const char **)a, *(const char **)b); | ||
222 | } | ||
223 | |||
224 | static int expand_tilde(char **pat, char *buf, size_t *pos) | ||
225 | { | ||
226 | char *p = *pat + 1; | ||
227 | size_t i = 0; | ||
228 | |||
229 | char delim, *name_end = __strchrnul(p, '/'); | ||
230 | if ((delim = *name_end)) *name_end++ = 0; | ||
231 | *pat = name_end; | ||
232 | |||
233 | char *home = *p ? NULL : getenv("HOME"); | ||
234 | if (!home) { | ||
235 | struct passwd pw, *res; | ||
236 | switch (*p ? getpwnam_r(p, &pw, buf, PATH_MAX, &res) | ||
237 | : getpwuid_r(getuid(), &pw, buf, PATH_MAX, &res)) { | ||
238 | case ENOMEM: | ||
239 | return GLOB_NOSPACE; | ||
240 | case 0: | ||
241 | if (!res) | ||
242 | default: | ||
243 | return GLOB_NOMATCH; | ||
244 | } | ||
245 | home = pw.pw_dir; | ||
246 | } | ||
247 | while (i < PATH_MAX - 2 && *home) | ||
248 | buf[i++] = *home++; | ||
249 | if (*home) | ||
250 | return GLOB_NOMATCH; | ||
251 | if ((buf[i] = delim)) | ||
252 | buf[++i] = 0; | ||
253 | *pos = i; | ||
254 | return 0; | ||
255 | } | ||
256 | #endif | ||
257 | |||
258 | int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g) | ||
259 | { | ||
260 | struct match head = { .next = NULL }, *tail = &head; | ||
261 | size_t cnt, i; | ||
262 | size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; | ||
263 | int error = 0; | ||
264 | char buf[PATH_MAX]; | ||
265 | |||
266 | if (!errfunc) errfunc = ignore_err; | ||
267 | |||
268 | if (!(flags & GLOB_APPEND)) { | ||
269 | g->gl_offs = offs; | ||
270 | g->gl_pathc = 0; | ||
271 | g->gl_pathv = NULL; | ||
272 | } | ||
273 | |||
274 | if (*pat) { | ||
275 | char *p = strdup(pat); | ||
276 | size_t pos = 0; | ||
277 | char *s = p; | ||
278 | if (!p) return GLOB_NOSPACE; | ||
279 | buf[0] = 0; | ||
280 | #if !ENABLE_PLATFORM_MINGW32 | ||
281 | if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) && *p == '~') | ||
282 | error = expand_tilde(&s, buf, &pos); | ||
283 | if (!error) | ||
284 | #endif | ||
285 | error = do_glob(buf, pos, 0, s, flags, errfunc, &tail); | ||
286 | free(p); | ||
287 | } | ||
288 | |||
289 | if (error == GLOB_NOSPACE) { | ||
290 | freelist(&head); | ||
291 | return error; | ||
292 | } | ||
293 | |||
294 | for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++); | ||
295 | if (!cnt) { | ||
296 | if (flags & GLOB_NOCHECK) { | ||
297 | tail = &head; | ||
298 | if (append(&tail, pat, strlen(pat), 0)) | ||
299 | return GLOB_NOSPACE; | ||
300 | cnt++; | ||
301 | } else | ||
302 | return GLOB_NOMATCH; | ||
303 | } | ||
304 | |||
305 | if (flags & GLOB_APPEND) { | ||
306 | char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); | ||
307 | if (!pathv) { | ||
308 | freelist(&head); | ||
309 | return GLOB_NOSPACE; | ||
310 | } | ||
311 | g->gl_pathv = pathv; | ||
312 | offs += g->gl_pathc; | ||
313 | } else { | ||
314 | g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); | ||
315 | if (!g->gl_pathv) { | ||
316 | freelist(&head); | ||
317 | return GLOB_NOSPACE; | ||
318 | } | ||
319 | for (i=0; i<offs; i++) | ||
320 | g->gl_pathv[i] = NULL; | ||
321 | } | ||
322 | for (i=0, tail=head.next; i<cnt; tail=tail->next, i++) | ||
323 | g->gl_pathv[offs + i] = tail->name; | ||
324 | g->gl_pathv[offs + i] = NULL; | ||
325 | g->gl_pathc += cnt; | ||
326 | |||
327 | #if !ENABLE_PLATFORM_MINGW32 | ||
328 | if (!(flags & GLOB_NOSORT)) | ||
329 | qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort); | ||
330 | #endif | ||
331 | |||
332 | return error; | ||
333 | } | ||
334 | |||
335 | void globfree(glob_t *g) | ||
336 | { | ||
337 | size_t i; | ||
338 | for (i=0; i<g->gl_pathc; i++) | ||
339 | free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); | ||
340 | free(g->gl_pathv); | ||
341 | g->gl_pathc = 0; | ||
342 | g->gl_pathv = NULL; | ||
343 | } | ||
diff --git a/win32/glob.h b/win32/glob.h new file mode 100644 index 000000000..a8141b8bf --- /dev/null +++ b/win32/glob.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | glob from musl (https://www.musl-libc.org/). | ||
3 | |||
4 | MIT licensed: | ||
5 | |||
6 | ---------------------------------------------------------------------- | ||
7 | Copyright © 2005-2020 Rich Felker, et al. | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person obtaining | ||
10 | a copy of this software and associated documentation files (the | ||
11 | "Software"), to deal in the Software without restriction, including | ||
12 | without limitation the rights to use, copy, modify, merge, publish, | ||
13 | distribute, sublicense, and/or sell copies of the Software, and to | ||
14 | permit persons to whom the Software is furnished to do so, subject to | ||
15 | the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
27 | ---------------------------------------------------------------------- | ||
28 | */ | ||
29 | #ifndef _GLOB_H | ||
30 | #define _GLOB_H | ||
31 | |||
32 | #ifdef __cplusplus | ||
33 | extern "C" { | ||
34 | #endif | ||
35 | |||
36 | typedef struct { | ||
37 | size_t gl_pathc; | ||
38 | char **gl_pathv; | ||
39 | size_t gl_offs; | ||
40 | int __dummy1; | ||
41 | void *__dummy2[5]; | ||
42 | } glob_t; | ||
43 | |||
44 | int glob(const char *__restrict, int, int (*)(const char *, int), glob_t *__restrict); | ||
45 | void globfree(glob_t *); | ||
46 | |||
47 | #if ENABLE_PLATFORM_MINGW32 | ||
48 | // Set some flags to zero so the compiler can exclude unused code. | ||
49 | #define GLOB_ERR 0 | ||
50 | #define GLOB_MARK 0 | ||
51 | #define GLOB_NOSORT 0x04 | ||
52 | #define GLOB_DOOFFS 0 | ||
53 | #define GLOB_NOCHECK 0x10 | ||
54 | #define GLOB_APPEND 0 | ||
55 | #define GLOB_NOESCAPE 0x40 | ||
56 | #define GLOB_PERIOD 0 | ||
57 | |||
58 | #define GLOB_TILDE 0 | ||
59 | #define GLOB_TILDE_CHECK 0 | ||
60 | #else | ||
61 | #define GLOB_ERR 0x01 | ||
62 | #define GLOB_MARK 0x02 | ||
63 | #define GLOB_NOSORT 0x04 | ||
64 | #define GLOB_DOOFFS 0x08 | ||
65 | #define GLOB_NOCHECK 0x10 | ||
66 | #define GLOB_APPEND 0x20 | ||
67 | #define GLOB_NOESCAPE 0x40 | ||
68 | #define GLOB_PERIOD 0x80 | ||
69 | |||
70 | #define GLOB_TILDE 0x1000 | ||
71 | #define GLOB_TILDE_CHECK 0x4000 | ||
72 | #endif | ||
73 | |||
74 | #define GLOB_NOSPACE 1 | ||
75 | #define GLOB_ABORTED 2 | ||
76 | #define GLOB_NOMATCH 3 | ||
77 | #define GLOB_NOSYS 4 | ||
78 | |||
79 | #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) | ||
80 | #define glob64 glob | ||
81 | #define globfree64 globfree | ||
82 | #define glob64_t glob_t | ||
83 | #endif | ||
84 | |||
85 | #ifdef __cplusplus | ||
86 | } | ||
87 | #endif | ||
88 | |||
89 | #endif | ||