]>
Commit | Line | Data |
---|---|---|
0083c904 | 1 | |
1f414ac4 BK |
2 | /* Install modified versions of certain ANSI-incompatible system header |
3 | files which are fixed to work correctly with ANSI C and placed in a | |
4 | directory that GNU C will search. | |
5 | ||
6 | Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. | |
7 | ||
8 | This file is part of GNU CC. | |
9 | ||
10 | GNU CC is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2, or (at your option) | |
13 | any later version. | |
14 | ||
15 | GNU CC is distributed in the hope that it will be useful, | |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with GNU CC; see the file COPYING. If not, write to | |
22 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
23 | Boston, MA 02111-1307, USA. */ | |
24 | ||
25 | #ifdef FIXINC_BROKEN | |
26 | /* The fixincl program is known to not run properly on this particular | |
27 | system. Instead of producing a probably broken executable, we force | |
28 | a compilation error and let the mkfixinc.sh script install the | |
29 | inclhack.sh shell script instead. */ | |
30 | # include "The fixincl program does not work properly on this system!" | |
31 | #endif | |
32 | ||
7b33bb99 | 33 | #include "auto-host.h" |
1f414ac4 BK |
34 | |
35 | #include <sys/types.h> | |
0083c904 BK |
36 | #include <sys/param.h> |
37 | #include <sys/stat.h> | |
1f414ac4 | 38 | #ifdef HAVE_SYS_WAIT_H |
0083c904 | 39 | #include <sys/wait.h> |
1f414ac4 | 40 | #endif |
0083c904 BK |
41 | #include <signal.h> |
42 | #include <stdio.h> | |
1f414ac4 | 43 | #ifdef HAVE_UNISTD_H |
0083c904 | 44 | #include <unistd.h> |
1f414ac4 | 45 | #endif |
0083c904 BK |
46 | #include <stdlib.h> |
47 | #include <errno.h> | |
48 | #include <string.h> | |
1f414ac4 | 49 | #ifdef HAVE_FCNTL_H |
0083c904 | 50 | #include <fcntl.h> |
1f414ac4 | 51 | #endif |
0083c904 BK |
52 | #include <ctype.h> |
53 | ||
f7d920fd | 54 | #include "gnu-regex.h" |
0083c904 BK |
55 | #include "server.h" |
56 | ||
1f414ac4 BK |
57 | static const char program_id[] = "fixincl version 1.0"; |
58 | ||
59 | #define MINIMUM_MAXIMUM_LINES 128 | |
60 | ||
61 | /* If this particular system's header files define the macro `MAXPATHLEN', | |
62 | we happily take advantage of it; otherwise we use a value which ought | |
63 | to be large enough. */ | |
64 | #ifndef MAXPATHLEN | |
65 | # define MAXPATHLEN 4096 | |
66 | #endif | |
67 | #define NAME_TABLE_SIZE (MINIMUM_MAXIMUM_LINES * MAXPATHLEN) | |
68 | ||
69 | char *file_name_buf; | |
70 | ||
0083c904 BK |
71 | #define tSCC static const char |
72 | #define tCC const char | |
73 | #define tSC static char | |
74 | ||
1f414ac4 BK |
75 | typedef int t_success; |
76 | ||
77 | #define FAILURE (-1) | |
78 | #define SUCCESS 0 | |
79 | #define PROBLEM 1 | |
0083c904 | 80 | |
1f414ac4 BK |
81 | #define SUCCEEDED(p) ((p) == SUCCESS) |
82 | #define SUCCESSFUL(p) SUCCEEDED (p) | |
83 | #define FAILED(p) ((p) < SUCCESS) | |
84 | #define HADGLITCH(p) ((p) > SUCCESS) | |
0083c904 | 85 | |
1f414ac4 | 86 | #define NUL '\0' |
0083c904 | 87 | |
1f414ac4 | 88 | /* Test Descriptor |
0083c904 | 89 | |
1f414ac4 BK |
90 | Each fix may have associated tests that determine |
91 | whether the fix needs to be applied or not. | |
92 | Each test has a type (from the te_test_type enumeration); | |
93 | associated test text; and, if the test is TT_EGREP or | |
94 | the negated form TT_NEGREP, a pointer to the compiled | |
95 | version of the text string. | |
96 | ||
97 | */ | |
0083c904 | 98 | typedef enum |
1f414ac4 BK |
99 | { |
100 | TT_TEST, TT_EGREP, TT_NEGREP | |
101 | } te_test_type; | |
0083c904 BK |
102 | |
103 | typedef struct test_desc tTestDesc; | |
104 | ||
105 | struct test_desc | |
1f414ac4 BK |
106 | { |
107 | te_test_type type; | |
108 | const char *pz_test_text; | |
109 | regex_t *p_test_regex; | |
110 | }; | |
0083c904 BK |
111 | |
112 | typedef struct patch_desc tPatchDesc; | |
113 | ||
1f414ac4 BK |
114 | /* Fix Descriptor |
115 | ||
116 | Everything you ever wanted to know about how to apply | |
117 | a particular fix (which files, how to qualify them, | |
118 | how to actually make the fix, etc...) | |
119 | ||
120 | */ | |
0083c904 BK |
121 | #define FD_MACH_ONLY 0x0000 |
122 | #define FD_MACH_IFNOT 0x0001 | |
123 | #define FD_SKIP_TEST 0x8000 | |
124 | ||
125 | typedef struct fix_desc tFixDesc; | |
126 | struct fix_desc | |
1f414ac4 BK |
127 | { |
128 | const char* fix_name; /* Name of the fix */ | |
129 | const char* file_list; /* List of files it applies to */ | |
130 | const char** papz_machs; /* List of machine/os-es it applies to */ | |
131 | regex_t* unused; | |
132 | int test_ct; | |
133 | int fd_flags; | |
134 | tTestDesc* p_test_desc; | |
135 | const char** patch_args; | |
136 | }; | |
137 | ||
138 | /* Working environment strings. Essentially, invocation 'options'. */ | |
139 | char *pz_dest_dir = NULL; | |
140 | char *pz_src_dir = NULL; | |
141 | char *pz_machine = NULL; | |
7d9ccd90 BK |
142 | char *pz_find_base = NULL; |
143 | int find_base_len = 0; | |
1f414ac4 BK |
144 | |
145 | pid_t process_chain_head = (pid_t) -1; | |
146 | ||
147 | const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]"; | |
148 | regex_t incl_quote_re; | |
149 | ||
d1c6a037 BK |
150 | char *load_file (const char *); |
151 | void process (char *, const char *); | |
152 | void run_compiles (); | |
153 | void wait_for_pid( pid_t, int ); | |
154 | void initialize (); | |
0083c904 BK |
155 | |
156 | #include "fixincl.x" | |
157 | ||
1f414ac4 BK |
158 | /* * * * * * * * * * * * * * * * * * * |
159 | * | |
160 | * MAIN ROUTINE | |
161 | */ | |
0083c904 BK |
162 | int |
163 | main (argc, argv) | |
164 | int argc; | |
165 | char **argv; | |
166 | { | |
1f414ac4 BK |
167 | static const char gnu_lib_mark[] = |
168 | "This file is part of the GNU C Library"; | |
0083c904 BK |
169 | |
170 | #ifndef NO_BOGOSITY_LIMITS | |
1f414ac4 BK |
171 | # define BOGUS_LIMIT MINIMUM_MAXIMUM_LINES |
172 | size_t loop_ct; | |
0083c904 BK |
173 | #endif |
174 | ||
1f414ac4 BK |
175 | char *apz_names[BOGUS_LIMIT]; |
176 | size_t file_name_ct; | |
0083c904 | 177 | |
1f414ac4 BK |
178 | /* Before anything else, ensure we can allocate our file name buffer. */ |
179 | file_name_buf = (char *) malloc (NAME_TABLE_SIZE); | |
180 | if (file_name_buf == (char *) NULL) | |
0083c904 | 181 | { |
1f414ac4 BK |
182 | fprintf (stderr, "fixincl cannot allocate 0x%08X bytes\n", |
183 | NAME_TABLE_SIZE); | |
184 | exit (EXIT_FAILURE); | |
185 | } | |
0083c904 | 186 | |
1f414ac4 BK |
187 | switch (argc) |
188 | { | |
189 | case 1: | |
190 | break; | |
191 | ||
192 | case 2: | |
0083c904 BK |
193 | if (strcmp (argv[1], "-v") == 0) |
194 | { | |
1f414ac4 BK |
195 | static const char zFmt[] = "echo '%s'"; |
196 | ||
197 | /* The 'version' option is really used to test that: | |
198 | 1. The program loads correctly (no missing libraries) | |
199 | 2. we can correctly run our server shell process | |
200 | 3. that we can compile all the regular expressions. | |
201 | */ | |
202 | run_compiles (); | |
203 | sprintf (file_name_buf, zFmt, program_id); | |
204 | fputs (file_name_buf + 5, stdout); | |
205 | exit (strcmp (run_shell (file_name_buf), program_id)); | |
0083c904 | 206 | } |
0083c904 | 207 | freopen (argv[1], "r", stdin); |
1f414ac4 BK |
208 | break; |
209 | ||
210 | default: | |
211 | fputs ("fixincl ERROR: too many command line arguments\n", stderr); | |
212 | exit (EXIT_FAILURE); | |
0083c904 BK |
213 | } |
214 | ||
d1c6a037 BK |
215 | initialize (); |
216 | ||
217 | #ifndef NO_BOGOSITY_LIMITS | |
218 | /* Some systems only allow so many calls to fork(2). | |
219 | This is inadequate for this program. Consequently, | |
220 | we must let a grandfather process spawn children | |
221 | that then spawn all the processes that do the real work. | |
222 | */ | |
223 | for (;;) | |
224 | { | |
225 | file_name_ct = 0; | |
226 | ||
227 | { | |
228 | char *pz_buf = file_name_buf; | |
229 | ||
230 | /* Only the parent process can read from stdin without confusing | |
231 | the world. (How does the child tell the parent to skip | |
232 | forward? Pipes and files behave differently.) */ | |
233 | ||
234 | while ( (file_name_ct < BOGUS_LIMIT) | |
235 | && (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN))) | |
236 | { | |
237 | if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL) | |
238 | break; | |
239 | while (isspace (*pz_buf)) | |
240 | pz_buf++; | |
241 | if ((*pz_buf == '\0') || (*pz_buf == '#')) | |
242 | continue; | |
243 | apz_names[file_name_ct++] = pz_buf; | |
244 | pz_buf += strlen (pz_buf); | |
245 | while (isspace (pz_buf[-1])) | |
246 | pz_buf--; | |
247 | *pz_buf++ = '\0'; | |
248 | } | |
249 | } | |
250 | ||
251 | /* IF we did not get any files this time thru | |
252 | THEN we must be done. */ | |
253 | if (file_name_ct == 0) | |
254 | return EXIT_SUCCESS; | |
255 | ||
256 | { | |
257 | pid_t child = fork (); | |
258 | if (child == NULLPROCESS) | |
259 | break; | |
260 | ||
261 | if (child == NOPROCESS) | |
262 | { | |
263 | fprintf (stderr, "Error %d (%s) forking in main\n", | |
264 | errno, strerror (errno)); | |
265 | exit (EXIT_FAILURE); | |
266 | } | |
267 | ||
268 | wait_for_pid( child, file_name_ct ); | |
269 | } | |
270 | } | |
271 | #else | |
272 | #error "NON-BOGUS LIMITS NOT SUPPORTED?!?!" | |
273 | #endif | |
274 | ||
275 | /* | |
276 | Here we are the child of the grandparent process. The parent | |
277 | of all the little fixup processes. We ignore the deaths of | |
278 | our children. */ | |
279 | ||
280 | signal (SIGCLD, SIG_IGN); | |
281 | ||
282 | #ifdef DEBUG | |
283 | fprintf (stderr, "Child start -- processing %d files\n", | |
284 | file_name_ct); | |
285 | #endif | |
286 | ||
287 | /* For every file specified in stdandard in | |
288 | (except as throttled for bogus reasons)... | |
289 | */ | |
290 | for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++) | |
291 | { | |
292 | char *pz_data; | |
293 | char *pz_file_name = apz_names[loop_ct]; | |
294 | ||
295 | if (access (pz_file_name, R_OK) != 0) | |
296 | { | |
297 | int erno = errno; | |
298 | fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n", | |
299 | pz_file_name, getcwd ((char *) NULL, MAXPATHLEN), | |
300 | erno, strerror (erno)); | |
301 | } | |
302 | else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL)) | |
303 | { | |
304 | if (strstr (pz_data, gnu_lib_mark) == (char *) NULL) | |
305 | process (pz_data, pz_file_name); | |
306 | free ((void *) pz_data); | |
307 | } | |
308 | } | |
309 | ||
310 | return EXIT_SUCCESS; | |
311 | } | |
312 | ||
313 | ||
314 | /* * * * * * * * * * * * */ | |
315 | ||
316 | void | |
317 | initialize() | |
318 | { | |
319 | static const char var_not_found[] = | |
320 | "fixincl ERROR: %s environment variable not defined\n"; | |
321 | ||
0083c904 | 322 | { |
1f414ac4 BK |
323 | static const char var[] = "TARGET_MACHINE"; |
324 | pz_machine = getenv (var); | |
325 | if (pz_machine == (char *) NULL) | |
0083c904 | 326 | { |
1f414ac4 | 327 | fprintf (stderr, var_not_found, var); |
0083c904 BK |
328 | exit (EXIT_FAILURE); |
329 | } | |
330 | } | |
331 | ||
332 | { | |
1f414ac4 BK |
333 | static const char var[] = "DESTDIR"; |
334 | pz_dest_dir = getenv (var); | |
335 | if (pz_dest_dir == (char *) NULL) | |
0083c904 | 336 | { |
1f414ac4 | 337 | fprintf (stderr, var_not_found, var); |
0083c904 BK |
338 | exit (EXIT_FAILURE); |
339 | } | |
340 | } | |
341 | ||
342 | { | |
1f414ac4 BK |
343 | static const char var[] = "SRCDIR"; |
344 | pz_src_dir = getenv (var); | |
345 | if (pz_src_dir == (char *) NULL) | |
0083c904 | 346 | { |
1f414ac4 | 347 | fprintf (stderr, var_not_found, var); |
0083c904 BK |
348 | exit (EXIT_FAILURE); |
349 | } | |
350 | } | |
351 | ||
7d9ccd90 BK |
352 | { |
353 | static const char var[] = "FIND_BASE"; | |
354 | pz_find_base = getenv (var); | |
355 | if (pz_find_base == (char *) NULL) | |
356 | { | |
357 | fprintf (stderr, var_not_found, var); | |
358 | exit (EXIT_FAILURE); | |
359 | } | |
360 | find_base_len = strlen( pz_find_base ); | |
361 | } | |
362 | ||
1f414ac4 BK |
363 | /* Compile all the regular expressions now. |
364 | That way, it is done only once for the whole run. | |
365 | */ | |
366 | run_compiles (); | |
0083c904 | 367 | |
1f414ac4 BK |
368 | signal (SIGQUIT, SIG_IGN); |
369 | signal (SIGIOT, SIG_IGN); | |
370 | signal (SIGPIPE, SIG_IGN); | |
371 | signal (SIGALRM, SIG_IGN); | |
372 | signal (SIGTERM, SIG_IGN); | |
0083c904 | 373 | |
d1c6a037 BK |
374 | /* |
375 | Make sure that if we opened a server process, we close it now. | |
376 | This is the grandparent process. We don't need the server anymore | |
377 | and our children should make their own. */ | |
0083c904 | 378 | |
d1c6a037 BK |
379 | close_server (); |
380 | (void)wait ( (int*)NULL ); | |
381 | } | |
0083c904 | 382 | |
d1c6a037 BK |
383 | /* * * * * * * * * * * * * |
384 | ||
385 | wait_for_pid - Keep calling `wait(2)' until it returns | |
386 | the process id we are looking for. Not every system has | |
387 | `waitpid(2)'. We also ensure that the children exit with success. */ | |
7d9ccd90 | 388 | |
d1c6a037 BK |
389 | void |
390 | wait_for_pid( pid_t child, int file_name_ct ) | |
391 | { | |
392 | #ifdef DEBUG | |
393 | fprintf (stderr, "Waiting for %d to complete %d files\n", | |
394 | child, file_name_ct); | |
0083c904 BK |
395 | #endif |
396 | ||
d1c6a037 BK |
397 | for (;;) { |
398 | int status; | |
399 | pid_t dead_kid = wait (&status); | |
7d9ccd90 | 400 | |
d1c6a037 BK |
401 | if (dead_kid == child) |
402 | { | |
403 | if (! WIFEXITED( status )) | |
404 | { | |
405 | fprintf (stderr, "child process %d is hung on signal %d\n", | |
406 | child, WSTOPSIG( status )); | |
407 | exit (EXIT_FAILURE); | |
408 | } | |
409 | if (WEXITSTATUS( status ) != 0) | |
410 | { | |
411 | fprintf (stderr, "child process %d exited with status %d\n", | |
412 | child, WEXITSTATUS( status )); | |
413 | exit (EXIT_FAILURE); | |
414 | } | |
1f414ac4 | 415 | #ifdef DEBUG |
d1c6a037 BK |
416 | fprintf (stderr, "child finished %d files %s\n", file_name_ct, |
417 | status ? strerror (status & 0xFF) : "ok"); | |
1f414ac4 | 418 | #endif |
d1c6a037 BK |
419 | break; /* normal child completion */ |
420 | } | |
1f414ac4 | 421 | |
d1c6a037 BK |
422 | /* |
423 | IF there is an error, THEN see if it is retryable. | |
424 | If it is not retryable, then break out of this loop. */ | |
425 | if (dead_kid == NOPROCESS) | |
426 | { | |
427 | switch (errno) { | |
428 | case EINTR: | |
429 | case EAGAIN: | |
430 | break; | |
431 | ||
432 | default: | |
433 | fprintf (stderr, "Error %d (%s) waiting for %d to finish\n", | |
434 | errno, strerror( errno ), child ); | |
435 | /* FALLTHROUGH */ | |
436 | ||
437 | case ECHILD: /* no children to wait for?? */ | |
438 | return; | |
0083c904 | 439 | } |
d1c6a037 BK |
440 | } |
441 | } done_waiting:; | |
0083c904 BK |
442 | } |
443 | ||
444 | ||
1f414ac4 BK |
445 | /* * * * * * * * * * * * * |
446 | ||
447 | load_file loads all the contents of a file into malloc-ed memory. | |
448 | Its argument is the name of the file to read in; the returned | |
449 | result is the NUL terminated contents of the file. The file | |
450 | is presumed to be an ASCII text file containing no NULs. */ | |
0083c904 | 451 | char * |
1f414ac4 BK |
452 | load_file (pz_file_name) |
453 | const char *pz_file_name; | |
0083c904 | 454 | { |
1f414ac4 BK |
455 | char *pz_data; |
456 | size_t file_size; | |
0083c904 BK |
457 | |
458 | { | |
459 | struct stat stbf; | |
1f414ac4 BK |
460 | |
461 | if (stat (pz_file_name, &stbf) != 0) | |
0083c904 BK |
462 | { |
463 | fprintf (stderr, "error %d (%s) stat-ing %s\n", | |
1f414ac4 | 464 | errno, strerror (errno), pz_file_name); |
0083c904 BK |
465 | return (char *) NULL; |
466 | } | |
1f414ac4 | 467 | file_size = stbf.st_size; |
0083c904 | 468 | } |
1f414ac4 | 469 | if (file_size == 0) |
0083c904 BK |
470 | return (char *) NULL; |
471 | ||
1f414ac4 BK |
472 | pz_data = (char *) malloc ((file_size + 16) & ~0x00F); |
473 | if (pz_data == (char *) NULL) | |
0083c904 BK |
474 | { |
475 | fprintf (stderr, "error: could not malloc %d bytes\n", | |
1f414ac4 | 476 | file_size); |
0083c904 BK |
477 | exit (EXIT_FAILURE); |
478 | } | |
479 | ||
480 | { | |
1f414ac4 BK |
481 | FILE *fp = fopen (pz_file_name, "r"); |
482 | size_t size_left = file_size; | |
483 | char *read_ptr = pz_data; | |
0083c904 BK |
484 | |
485 | if (fp == (FILE *) NULL) | |
486 | { | |
487 | fprintf (stderr, "error %d (%s) opening %s\n", errno, | |
1f414ac4 BK |
488 | strerror (errno), pz_file_name); |
489 | free ((void *) pz_data); | |
0083c904 BK |
490 | return (char *) NULL; |
491 | } | |
492 | ||
493 | do | |
494 | { | |
1f414ac4 | 495 | size_t sizeRead = fread ((void *) read_ptr, 1, size_left, fp); |
0083c904 BK |
496 | |
497 | if (sizeRead == 0) | |
498 | { | |
499 | if (feof (fp)) | |
500 | break; | |
501 | ||
502 | if (ferror (fp)) | |
503 | { | |
7d9ccd90 BK |
504 | int err = errno; |
505 | if (err != EISDIR) | |
506 | fprintf (stderr, "error %d (%s) reading %s\n", err, | |
507 | strerror (err), pz_file_name); | |
1f414ac4 | 508 | free ((void *) pz_data); |
0083c904 BK |
509 | fclose (fp); |
510 | return (char *) NULL; | |
511 | } | |
512 | } | |
513 | ||
1f414ac4 BK |
514 | read_ptr += sizeRead; |
515 | size_left -= sizeRead; | |
0083c904 | 516 | } |
1f414ac4 | 517 | while (size_left != 0); |
0083c904 | 518 | |
1f414ac4 | 519 | *read_ptr = '\0'; |
0083c904 | 520 | fclose (fp); |
0083c904 | 521 | } |
1f414ac4 | 522 | return pz_data; |
0083c904 BK |
523 | } |
524 | ||
525 | ||
1f414ac4 BK |
526 | /* * * * * * * * * * * * * |
527 | ||
528 | run_compiles run all the regexp compiles for all the fixes once. | |
529 | */ | |
0083c904 | 530 | void |
1f414ac4 | 531 | run_compiles () |
0083c904 | 532 | { |
1f414ac4 | 533 | tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n" |
0083c904 | 534 | "\texpr = `%s'\n" "\terror %s\n"; |
1f414ac4 BK |
535 | tFixDesc *p_fixd = fixDescList; |
536 | int fix_ct = FIX_COUNT; | |
537 | tTestDesc *p_test; | |
538 | int test_ct; | |
539 | int re_ct = REGEX_COUNT; | |
540 | const char *pz_err; | |
541 | regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t)); | |
542 | ||
543 | if (p_re == (regex_t *) NULL) | |
0083c904 BK |
544 | { |
545 | fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n", | |
546 | REGEX_COUNT * sizeof (regex_t)); | |
547 | exit (EXIT_FAILURE); | |
548 | } | |
549 | ||
d1c6a037 BK |
550 | /* Make sure re_compile_pattern does not stumble across invalid |
551 | data */ | |
552 | ||
553 | memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) ); | |
554 | memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) ); | |
555 | ||
1f414ac4 BK |
556 | /* The patterns we search for are all egrep patterns. |
557 | In the shell version of this program, we invoke egrep | |
558 | with the supplied pattern. Here, we will run | |
559 | re_compile_pattern, but it must be using the same rules. */ | |
560 | ||
0083c904 | 561 | re_set_syntax (RE_SYNTAX_EGREP); |
1f414ac4 BK |
562 | pz_err = re_compile_pattern (incl_quote_pat, sizeof (incl_quote_pat)-1, |
563 | &incl_quote_re); | |
564 | if (pz_err != (char *) NULL) | |
0083c904 | 565 | { |
1f414ac4 BK |
566 | fprintf (stderr, z_bad_comp, "quoted include", "run_compiles", |
567 | incl_quote_pat, pz_err); | |
0083c904 BK |
568 | exit (EXIT_FAILURE); |
569 | } | |
570 | ||
1f414ac4 | 571 | /* FOR every fixup, ... */ |
0083c904 BK |
572 | do |
573 | { | |
1f414ac4 BK |
574 | p_test = p_fixd->p_test_desc; |
575 | test_ct = p_fixd->test_ct; | |
0083c904 | 576 | |
1f414ac4 BK |
577 | /* IF the machine type pointer is not NULL (we are not in test mode) |
578 | AND this test is for or not done on particular machines | |
579 | THEN ... */ | |
580 | ||
581 | if ( (pz_machine != NULL) | |
582 | && (p_fixd->papz_machs != (const char**) NULL) ) | |
583 | { | |
584 | const char **papz_machs = p_fixd->papz_machs; | |
585 | char *pz = file_name_buf; | |
586 | char *pz_sep = ""; | |
587 | tCC *pz_if_true; | |
588 | tCC *pz_if_false; | |
589 | tSCC skip[] = "skip"; | |
590 | tSCC run[] = "run"; | |
591 | ||
592 | /* Construct a shell script that looks like this: | |
593 | ||
594 | case our-cpu-platform-os in | |
595 | tests-cpu-platform-os-pattern ) | |
596 | echo run ;; | |
597 | * ) | |
598 | echo skip ;; | |
599 | esac | |
600 | ||
601 | where 'run' and 'skip' may be reversed, depending on | |
602 | the sense of the test. */ | |
603 | ||
604 | sprintf (pz, "case %s in\n", pz_machine); | |
605 | pz += strlen (pz); | |
606 | ||
607 | if (p_fixd->fd_flags & FD_MACH_IFNOT) | |
608 | { | |
609 | pz_if_true = skip; | |
610 | pz_if_false = run; | |
611 | } | |
612 | else | |
613 | { | |
614 | pz_if_true = run; | |
615 | pz_if_false = skip; | |
616 | } | |
617 | ||
618 | /* FOR any additional machine names to test for, | |
619 | insert the " | \\\n" glue and the machine pattern. */ | |
620 | ||
621 | for (;;) | |
622 | { | |
623 | const char* pz_mach = *(papz_machs++); | |
624 | ||
625 | if (pz_mach == (const char*) NULL) | |
626 | break; | |
627 | sprintf (pz, "%s %s", pz_sep, pz_mach); | |
628 | pz += strlen (pz); | |
629 | pz_sep = " | \\\n"; | |
630 | } | |
631 | sprintf (pz, " )\n echo %s ;;\n * )\n echo %s ;;\nesac", | |
632 | pz_if_true, pz_if_false); | |
633 | ||
634 | /* Run the script. | |
635 | The result will start either with 's' or 'r'. */ | |
636 | ||
7d032a4f RO |
637 | { |
638 | int skip; | |
639 | pz = run_shell (file_name_buf); | |
640 | skip = (*pz == 's'); | |
641 | free ( (void*)pz ); | |
642 | if (skip) | |
643 | { | |
644 | p_fixd->fd_flags |= FD_SKIP_TEST; | |
645 | continue; | |
646 | } | |
647 | } | |
0083c904 | 648 | } |
0083c904 | 649 | |
1f414ac4 BK |
650 | /* FOR every test for the fixup, ... */ |
651 | ||
652 | while (--test_ct >= 0) | |
0083c904 | 653 | { |
1f414ac4 | 654 | switch (p_test->type) |
0083c904 BK |
655 | { |
656 | case TT_EGREP: | |
657 | case TT_NEGREP: | |
1f414ac4 BK |
658 | /* You might consider putting the following under #ifdef. |
659 | The number of re's used is computed by autogen. | |
660 | So, it is static and known at compile time. */ | |
661 | ||
662 | if (--re_ct < 0) | |
0083c904 BK |
663 | { |
664 | fputs ("out of RE's\n", stderr); | |
665 | exit (EXIT_FAILURE); | |
666 | } | |
667 | ||
1f414ac4 BK |
668 | p_test->p_test_regex = p_re++; |
669 | pz_err = re_compile_pattern (p_test->pz_test_text, | |
670 | strlen (p_test->pz_test_text), | |
671 | p_test->p_test_regex); | |
672 | if (pz_err != (char *) NULL) | |
0083c904 | 673 | { |
1f414ac4 BK |
674 | fprintf (stderr, z_bad_comp, "select test", p_fixd->fix_name, |
675 | p_test->pz_test_text, pz_err); | |
0083c904 BK |
676 | exit (EXIT_FAILURE); |
677 | } | |
678 | } | |
1f414ac4 | 679 | p_test++; |
0083c904 BK |
680 | } |
681 | } | |
1f414ac4 | 682 | while (p_fixd++, --fix_ct > 0); |
0083c904 BK |
683 | } |
684 | ||
685 | ||
1f414ac4 BK |
686 | /* * * * * * * * * * * * * |
687 | ||
688 | create_file Create the output modified file. | |
689 | Input: the name of the file to create | |
690 | Returns: a file pointer to the new, open file */ | |
691 | ||
692 | #define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) | |
693 | ||
0083c904 | 694 | FILE * |
1f414ac4 BK |
695 | create_file (pz_file_name) |
696 | const char *pz_file_name; | |
0083c904 BK |
697 | { |
698 | int fd; | |
699 | FILE *pf; | |
700 | char fname[MAXPATHLEN]; | |
701 | ||
7d9ccd90 BK |
702 | #ifdef DEBUG |
703 | if (strncmp( pz_file_name, pz_find_base, find_base_len ) != 0) | |
704 | { | |
705 | fprintf (stderr, "Error: input file %s does not match %s/*\n", | |
706 | pz_file_name, pz_find_base ); | |
707 | exit (1); | |
708 | } | |
709 | #endif | |
710 | ||
711 | sprintf (fname, "%s/%s", pz_dest_dir, pz_file_name + find_base_len); | |
0083c904 | 712 | |
1f414ac4 | 713 | fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL); |
0083c904 | 714 | |
1f414ac4 | 715 | /* We may need to create the directories needed... */ |
0083c904 BK |
716 | if ((fd < 0) && (errno == ENOENT)) |
717 | { | |
1f414ac4 | 718 | char *pz_dir = strchr (fname + 1, '/'); |
0083c904 BK |
719 | struct stat stbf; |
720 | ||
1f414ac4 | 721 | while (pz_dir != (char *) NULL) |
0083c904 | 722 | { |
1f414ac4 | 723 | *pz_dir = NUL; |
0083c904 BK |
724 | if (stat (fname, &stbf) < 0) |
725 | { | |
726 | mkdir (fname, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | |
727 | | S_IROTH | S_IXOTH); | |
728 | } | |
729 | ||
1f414ac4 BK |
730 | *pz_dir = '/'; |
731 | pz_dir = strchr (pz_dir + 1, '/'); | |
0083c904 | 732 | } |
1f414ac4 BK |
733 | |
734 | /* Now, lets try the open again... */ | |
735 | fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL); | |
0083c904 BK |
736 | } |
737 | if (fd < 0) | |
738 | { | |
739 | fprintf (stderr, "Error %d (%s) creating %s\n", | |
740 | errno, strerror (errno), fname); | |
741 | exit (EXIT_FAILURE); | |
742 | } | |
1f414ac4 | 743 | fprintf (stderr, "Fixed: %s\n", pz_file_name); |
0083c904 BK |
744 | pf = fdopen (fd, "w"); |
745 | ||
746 | #ifdef LATER | |
747 | { | |
1f414ac4 BK |
748 | static const char hdr[] = |
749 | "/* DO NOT EDIT THIS FILE.\n\n" | |
750 | " It has been auto-edited by fixincludes from /usr/include/%s\n" | |
751 | " This had to be done to correct non-standard usages in the\n" | |
752 | " original, manufacturer supplied header file. */\n\n"; | |
753 | ||
754 | fprintf (pf, hdr, pz_file_name); | |
0083c904 BK |
755 | } |
756 | #endif | |
757 | return pf; | |
758 | } | |
759 | ||
0083c904 | 760 | |
1f414ac4 | 761 | /* * * * * * * * * * * * * |
0083c904 | 762 | |
1f414ac4 BK |
763 | test_test make sure a shell-style test expression passes. |
764 | Input: a pointer to the descriptor of the test to run and | |
765 | the name of the file that we might want to fix | |
766 | Result: SUCCESS or FAILURE, depending on the result of the | |
767 | shell script we run. */ | |
768 | ||
769 | t_success | |
770 | test_test (p_test, pz_file_name) | |
771 | tTestDesc *p_test; | |
772 | char* pz_file_name; | |
773 | { | |
774 | char *pz_res; | |
775 | t_success res = FAILURE; | |
776 | ||
777 | static char cmd_buf[4096]; | |
778 | tSCC cmd_fmt[] = | |
779 | "file=%s\n" | |
780 | "if ( test %s ) > /dev/null 2>&1\n" | |
781 | "then echo TRUE\n" | |
782 | "else echo FALSE\n" | |
783 | "fi"; | |
784 | ||
785 | sprintf (cmd_buf, cmd_fmt, pz_file_name, p_test->pz_test_text); | |
786 | pz_res = run_shell (cmd_buf); | |
787 | if (*pz_res == 'T') | |
0083c904 | 788 | res = SUCCESS; |
1f414ac4 | 789 | free ((void *) pz_res); |
0083c904 BK |
790 | return res; |
791 | } | |
792 | ||
793 | ||
1f414ac4 BK |
794 | /* * * * * * * * * * * * * |
795 | ||
796 | egrep_test make sure an egrep expression is found in the file text. | |
797 | Input: a pointer to the descriptor of the test to run and | |
798 | the pointer to the contents of the file under suspicion | |
799 | Result: SUCCESS if the pattern is found, FAILURE otherwise | |
800 | ||
801 | The caller may choose 'FAILURE' as 'SUCCESS' if the sense of the test | |
802 | is inverted. */ | |
803 | ||
804 | t_success | |
805 | egrep_test (pz_data, p_test) | |
806 | char *pz_data; | |
807 | tTestDesc *p_test; | |
0083c904 BK |
808 | { |
809 | regmatch_t match; | |
1f414ac4 | 810 | |
0083c904 | 811 | #ifndef NO_BOGOSITY |
1f414ac4 BK |
812 | if (p_test->p_test_regex == 0) |
813 | fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n", | |
814 | p_test->pz_test_text); | |
0083c904 | 815 | #endif |
1f414ac4 | 816 | if (regexec (p_test->p_test_regex, pz_data, 1, &match, 0) == 0) |
0083c904 BK |
817 | return SUCCESS; |
818 | return FAILURE; | |
819 | } | |
820 | ||
821 | ||
1f414ac4 BK |
822 | /* * * * * * * * * * * * * |
823 | * | |
824 | extract_quoted_files | |
825 | ||
826 | The syntax, `#include "file.h"' specifies that the compiler is to | |
827 | search the local directory of the current file before the include | |
828 | list. Consequently, if we have modified a header and stored it in | |
829 | another directory, any files that are included by that modified | |
830 | file in that fashion must also be copied into this new directory. | |
831 | This routine finds those flavors of #include and for each one found | |
832 | emits a triple of: | |
833 | ||
834 | 1. source directory of the original file | |
835 | 2. the relative path file name of the #includ-ed file | |
836 | 3. the full destination path for this file | |
837 | ||
838 | Input: the text of the file, the file name and a pointer to the | |
839 | match list where the match information was stored. | |
840 | Result: internally nothing. The results are written to stdout | |
841 | for interpretation by the invoking shell */ | |
0083c904 BK |
842 | |
843 | void | |
1f414ac4 BK |
844 | extract_quoted_files (pz_data, pz_file_name, p_re_match) |
845 | char *pz_data; | |
846 | const char *pz_file_name; | |
847 | regmatch_t *p_re_match; | |
0083c904 | 848 | { |
1f414ac4 BK |
849 | char *pz_dir_end = strrchr (pz_file_name, '/'); |
850 | char *pz_incl_quot = pz_data; | |
0083c904 | 851 | |
1f414ac4 | 852 | fprintf (stderr, "Quoted includes in %s\n", pz_file_name); |
0083c904 | 853 | |
1f414ac4 BK |
854 | /* Set "pz_file_name" to point to the containing subdirectory of the source |
855 | If there is none, then it is in our current direcory, ".". */ | |
856 | ||
857 | if (pz_dir_end == (char *) NULL) | |
858 | pz_file_name = "."; | |
0083c904 | 859 | else |
1f414ac4 | 860 | *pz_dir_end = '\0'; |
0083c904 BK |
861 | |
862 | for (;;) | |
863 | { | |
1f414ac4 BK |
864 | pz_incl_quot += p_re_match->rm_so; |
865 | ||
866 | /* Skip forward to the included file name */ | |
867 | while (isspace (*pz_incl_quot)) | |
868 | pz_incl_quot++; | |
869 | while (isspace (*++pz_incl_quot)) | |
870 | ; | |
871 | pz_incl_quot += sizeof ("include") - 1; | |
872 | while (*pz_incl_quot++ != '"') | |
873 | ; | |
874 | ||
875 | /* Print the source directory and the subdirectory of the file | |
876 | in question. */ | |
877 | printf ("%s %s/", pz_src_dir, pz_file_name); | |
878 | pz_dir_end = pz_incl_quot; | |
879 | ||
880 | /* Append to the directory the relative path of the desired file */ | |
881 | while (*pz_incl_quot != '"') | |
882 | putc (*pz_incl_quot++, stdout); | |
883 | ||
884 | /* Now print the destination directory appended with the | |
885 | relative path of the desired file */ | |
886 | printf (" %s/%s/", pz_dest_dir, pz_file_name); | |
887 | while (*pz_dir_end != '"') | |
888 | putc (*pz_dir_end++, stdout); | |
889 | ||
890 | /* End of entry */ | |
0083c904 BK |
891 | putc ('\n', stdout); |
892 | ||
1f414ac4 BK |
893 | /* Find the next entry */ |
894 | if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0) | |
0083c904 BK |
895 | break; |
896 | } | |
897 | } | |
898 | ||
899 | ||
1f414ac4 BK |
900 | /* * * * * * * * * * * * * |
901 | ||
902 | Process the potential fixes for a particular include file. | |
903 | Input: the original text of the file and the file's name | |
904 | Result: none. A new file may or may not be created. */ | |
905 | ||
0083c904 | 906 | void |
1f414ac4 BK |
907 | process (pz_data, pz_file_name) |
908 | char *pz_data; | |
909 | const char *pz_file_name; | |
0083c904 | 910 | { |
1f414ac4 BK |
911 | static char env_current_file[1024] = { "file=" }; |
912 | tFixDesc *p_fixd = fixDescList; | |
913 | int todo_ct = FIX_COUNT; | |
914 | t_fd_pair fdp = { -1, -1 }; | |
0083c904 | 915 | |
1f414ac4 BK |
916 | /* IF this is the first time through, |
917 | THEN put the 'file' environment variable into the environment. | |
918 | This is used by some of the subject shell scripts and tests. */ | |
0083c904 | 919 | |
1f414ac4 BK |
920 | if (env_current_file[5] == NUL) |
921 | putenv (env_current_file); | |
0083c904 BK |
922 | |
923 | /* | |
1f414ac4 BK |
924 | Ghastly as it is, this actually updates the value of the variable: |
925 | ||
926 | putenv(3C) C Library Functions putenv(3C) | |
927 | ||
928 | DESCRIPTION | |
929 | putenv() makes the value of the environment variable name | |
930 | equal to value by altering an existing variable or creating | |
931 | a new one. In either case, the string pointed to by string | |
932 | becomes part of the environment, so altering the string will | |
933 | change the environment. string points to a string of the | |
934 | form ``name=value.'' The space used by string is no longer | |
935 | used once a new string-defining name is passed to putenv(). | |
0083c904 | 936 | */ |
1f414ac4 BK |
937 | strcpy (env_current_file + 5, pz_file_name); |
938 | process_chain_head = NOPROCESS; | |
939 | ||
940 | /* For every fix in our fix list, ... */ | |
941 | for (; todo_ct > 0; p_fixd++, todo_ct--) | |
0083c904 | 942 | { |
1f414ac4 BK |
943 | tTestDesc *p_test; |
944 | int test_ct; | |
0083c904 | 945 | |
1f414ac4 | 946 | if (p_fixd->fd_flags & FD_SKIP_TEST) |
0083c904 BK |
947 | continue; |
948 | ||
1f414ac4 BK |
949 | /* IF there is a file name restriction, |
950 | THEN ensure the current file name matches one in the pattern */ | |
951 | ||
952 | if (p_fixd->file_list != (char *) NULL) | |
0083c904 | 953 | { |
1f414ac4 BK |
954 | const char *pz_fname = pz_file_name; |
955 | const char *pz_scan = p_fixd->file_list; | |
956 | size_t name_len; | |
0083c904 | 957 | |
1f414ac4 BK |
958 | while ((pz_fname[0] == '.') && (pz_fname[1] == '/')) |
959 | pz_fname += 2; | |
960 | name_len = strlen (pz_fname); | |
0083c904 BK |
961 | |
962 | for (;;) | |
963 | { | |
1f414ac4 BK |
964 | pz_scan = strstr (pz_scan + 1, pz_fname); |
965 | /* IF we can't match the string at all, | |
966 | THEN bail */ | |
967 | if (pz_scan == (char *) NULL) | |
968 | goto next_fix; | |
0083c904 | 969 | |
1f414ac4 BK |
970 | /* IF the match is surrounded by the '|' markers, |
971 | THEN we found a full match -- time to run the tests */ | |
972 | ||
973 | if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|')) | |
0083c904 BK |
974 | break; |
975 | } | |
976 | } | |
977 | ||
1f414ac4 BK |
978 | /* FOR each test, see if it fails. |
979 | IF it does fail, then we go on to the next test */ | |
0083c904 | 980 | |
1f414ac4 BK |
981 | for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct; |
982 | test_ct-- > 0; | |
983 | p_test++) | |
0083c904 | 984 | { |
1f414ac4 BK |
985 | #ifdef DEBUG |
986 | static const char z_test_fail[] = | |
987 | "%16s test %2d failed for %s\n"; | |
988 | #endif | |
989 | switch (p_test->type) | |
0083c904 BK |
990 | { |
991 | case TT_TEST: | |
1f414ac4 BK |
992 | if (!SUCCESSFUL (test_test (p_test, pz_file_name))) |
993 | { | |
994 | #ifdef DEBUG | |
995 | fprintf (stderr, z_test_fail, p_fixd->fix_name, | |
996 | p_fixd->test_ct - test_ct, pz_file_name); | |
997 | #endif | |
998 | goto next_fix; | |
999 | } | |
0083c904 BK |
1000 | break; |
1001 | ||
1002 | case TT_EGREP: | |
1f414ac4 BK |
1003 | if (!SUCCESSFUL (egrep_test (pz_data, p_test))) |
1004 | { | |
1005 | #ifdef DEBUG | |
1006 | fprintf (stderr, z_test_fail, p_fixd->fix_name, | |
1007 | p_fixd->test_ct - test_ct, pz_file_name); | |
1008 | #endif | |
1009 | goto next_fix; | |
1010 | } | |
0083c904 BK |
1011 | break; |
1012 | ||
1013 | case TT_NEGREP: | |
1f414ac4 BK |
1014 | if (SUCCESSFUL (egrep_test (pz_data, p_test))) |
1015 | { | |
1016 | #ifdef DEBUG | |
1017 | fprintf (stderr, z_test_fail, p_fixd->fix_name, | |
1018 | p_fixd->test_ct - test_ct, pz_file_name); | |
1019 | #endif | |
1020 | goto next_fix; | |
1021 | } | |
0083c904 BK |
1022 | break; |
1023 | } | |
1024 | } | |
1025 | ||
7d9ccd90 | 1026 | fprintf (stderr, "Applying %-24s to %s\n", |
1f414ac4 BK |
1027 | p_fixd->fix_name, pz_file_name); |
1028 | ||
1029 | /* IF we do not have a read pointer, | |
1030 | THEN this is the first fix for the current file. | |
1031 | Open the source file. That will be used as stdin for | |
1032 | the first fix. Any subsequent fixes will use the | |
1033 | stdout descriptor of the previous fix as its stdin. */ | |
0083c904 | 1034 | |
1f414ac4 BK |
1035 | if (fdp.read_fd == -1) |
1036 | { | |
1037 | fdp.read_fd = open (pz_file_name, O_RDONLY); | |
1038 | if (fdp.read_fd < 0) | |
0083c904 | 1039 | { |
1f414ac4 BK |
1040 | fprintf (stderr, "Error %d (%s) opening %s\n", errno, |
1041 | strerror (errno), pz_file_name); | |
1042 | exit (EXIT_FAILURE); | |
0083c904 | 1043 | } |
1f414ac4 | 1044 | } |
0083c904 | 1045 | |
1f414ac4 BK |
1046 | /* This loop should only cycle for 1/2 of one loop. |
1047 | "chain_open" starts a process that uses "fdp.read_fd" as | |
1048 | its stdin and returns the new fd this process will use | |
1049 | for stdout. */ | |
0083c904 | 1050 | |
1f414ac4 BK |
1051 | for (;;) |
1052 | { | |
1053 | static int failCt = 0; | |
1054 | int fd = chain_open (fdp.read_fd, | |
1055 | (t_pchar *) p_fixd->patch_args, | |
1056 | (process_chain_head == -1) | |
1057 | ? &process_chain_head : (pid_t *) NULL); | |
0083c904 | 1058 | |
1f414ac4 BK |
1059 | if (fd != -1) |
1060 | { | |
1061 | fdp.read_fd = fd; | |
1062 | break; | |
0083c904 | 1063 | } |
1f414ac4 BK |
1064 | |
1065 | fprintf (stderr, "Error %d (%s) starting filter process " | |
1066 | "for %s\n", errno, strerror (errno), | |
1067 | p_fixd->fix_name); | |
1068 | ||
1069 | if ((errno != EAGAIN) || (++failCt > 10)) | |
1070 | exit (EXIT_FAILURE); | |
1071 | sleep (1); | |
0083c904 BK |
1072 | } |
1073 | ||
1f414ac4 BK |
1074 | next_fix: |
1075 | ; | |
0083c904 BK |
1076 | } |
1077 | ||
1f414ac4 BK |
1078 | /* IF after all the tests we did not start any patch programs, |
1079 | THEN quit now. */ | |
1080 | ||
1081 | if (fdp.read_fd < 0) | |
0083c904 BK |
1082 | return; |
1083 | ||
1f414ac4 BK |
1084 | /* OK. We have work to do. Read back in the output |
1085 | of the filtering chain. Compare each byte as we read it with | |
1086 | the contents of the original file. As soon as we find any | |
1087 | difference, we will create the output file, write out all | |
1088 | the matched text and then copy any remaining data from the | |
1089 | output of the filter chain. | |
1090 | */ | |
0083c904 | 1091 | { |
1f414ac4 BK |
1092 | FILE *in_fp = fdopen (fdp.read_fd, "r"); |
1093 | FILE *out_fp = (FILE *) NULL; | |
1094 | char *pz_cmp = pz_data; | |
0083c904 BK |
1095 | |
1096 | for (;;) | |
1097 | { | |
1098 | int ch; | |
1099 | ||
1f414ac4 | 1100 | ch = getc (in_fp); |
0083c904 BK |
1101 | if (ch == EOF) |
1102 | break; | |
1103 | ||
1f414ac4 BK |
1104 | /* IF we are emitting the output |
1105 | THEN emit this character, too. | |
1106 | */ | |
1107 | if (out_fp != (FILE *) NULL) | |
1108 | putc (ch, out_fp); | |
0083c904 | 1109 | |
1f414ac4 BK |
1110 | /* ELSE if this character does not match the original, |
1111 | THEN now is the time to start the output. | |
1112 | */ | |
1113 | else if (ch != *pz_cmp) | |
0083c904 | 1114 | { |
1f414ac4 BK |
1115 | out_fp = create_file (pz_file_name); |
1116 | ||
1117 | /* IF there are matched data, write it all now. */ | |
1118 | if (pz_cmp != pz_data) | |
0083c904 | 1119 | { |
1f414ac4 BK |
1120 | char c = *pz_cmp; |
1121 | ||
1122 | *pz_cmp = NUL; | |
1123 | fputs (pz_data, out_fp); | |
1124 | *pz_cmp = c; | |
0083c904 | 1125 | } |
0083c904 | 1126 | |
1f414ac4 BK |
1127 | /* Emit the current unmatching character */ |
1128 | putc (ch, out_fp); | |
0083c904 BK |
1129 | } |
1130 | else | |
1f414ac4 BK |
1131 | /* ELSE the character matches. Advance the compare ptr */ |
1132 | pz_cmp++; | |
0083c904 BK |
1133 | } |
1134 | ||
1f414ac4 BK |
1135 | /* IF we created the output file, ... */ |
1136 | if (out_fp != (FILE *) NULL) | |
0083c904 BK |
1137 | { |
1138 | regmatch_t match; | |
1139 | ||
1f414ac4 BK |
1140 | /* Close the file and see if we have to worry about |
1141 | `#include "file.h"' constructs. */ | |
1142 | fclose (out_fp); | |
1143 | if (regexec (&incl_quote_re, pz_data, 1, &match, 0) == 0) | |
1144 | extract_quoted_files (pz_data, pz_file_name, &match); | |
0083c904 | 1145 | } |
1f414ac4 | 1146 | fclose (in_fp); |
0083c904 | 1147 | } |
1f414ac4 | 1148 | close (fdp.read_fd); /* probably redundant, but I'm paranoid */ |
0083c904 | 1149 | } |