0
|
1 /* Install modified versions of certain ANSI-incompatible system header
|
|
2 files which are fixed to work correctly with ANSI C and placed in a
|
|
3 directory that GCC will search.
|
|
4
|
|
5 Copyright (C) 1997, 1998, 1999, 2000, 2004, 2009
|
|
6 Free Software Foundation, Inc.
|
|
7
|
|
8 This file is part of GCC.
|
|
9
|
|
10 GCC 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 3, or (at your option)
|
|
13 any later version.
|
|
14
|
|
15 GCC 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 GCC; see the file COPYING3. If not see
|
|
22 <http://www.gnu.org/licenses/>. */
|
|
23
|
|
24 #include "fixlib.h"
|
|
25
|
|
26 #include <fnmatch.h>
|
|
27 #include <sys/stat.h>
|
|
28 #ifndef SEPARATE_FIX_PROC
|
|
29 #include <sys/wait.h>
|
|
30 #endif
|
|
31
|
|
32 #if defined( HAVE_MMAP_FILE )
|
|
33 #include <sys/mman.h>
|
|
34 #define BAD_ADDR ((void*)-1)
|
|
35 #endif
|
|
36
|
|
37 #ifndef SEPARATE_FIX_PROC
|
|
38 #include "server.h"
|
|
39 #endif
|
|
40
|
|
41 /* The contents of this string are not very important. It is mostly
|
|
42 just used as part of the "I am alive and working" test. */
|
|
43
|
|
44 static const char program_id[] = "fixincl version 1.1";
|
|
45
|
|
46 /* This format will be used at the start of every generated file */
|
|
47
|
|
48 static const char z_std_preamble[] =
|
|
49 "/* DO NOT EDIT THIS FILE.\n\n\
|
|
50 It has been auto-edited by fixincludes from:\n\n\
|
|
51 \t\"%s/%s\"\n\n\
|
|
52 This had to be done to correct non-standard usages in the\n\
|
|
53 original, manufacturer supplied header file. */\n\n";
|
|
54
|
|
55 int find_base_len = 0;
|
|
56
|
|
57 typedef enum {
|
|
58 VERB_SILENT = 0,
|
|
59 VERB_FIXES,
|
|
60 VERB_APPLIES,
|
|
61 VERB_PROGRESS,
|
|
62 VERB_TESTS,
|
|
63 VERB_EVERYTHING
|
|
64 } te_verbose;
|
|
65
|
|
66 te_verbose verbose_level = VERB_PROGRESS;
|
|
67 int have_tty = 0;
|
|
68
|
|
69 #define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
|
|
70 #define NOT_SILENT VLEVEL(VERB_FIXES)
|
|
71
|
|
72 pid_t process_chain_head = (pid_t) -1;
|
|
73
|
|
74 char* pz_curr_file; /* name of the current file under test/fix */
|
|
75 char* pz_curr_data; /* original contents of that file */
|
|
76 char* pz_temp_file; /* for DOS, a place to stash the temporary
|
|
77 fixed data between system(3) calls */
|
|
78 t_bool curr_data_mapped;
|
|
79 int data_map_fd;
|
|
80 size_t data_map_size;
|
|
81 size_t ttl_data_size = 0;
|
|
82
|
|
83 #ifdef DO_STATS
|
|
84 int process_ct = 0;
|
|
85 int apply_ct = 0;
|
|
86 int fixed_ct = 0;
|
|
87 int altered_ct = 0;
|
|
88 #endif /* DO_STATS */
|
|
89
|
|
90 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
|
|
91 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
|
|
92 regex_t incl_quote_re;
|
|
93
|
|
94 static void do_version (void) ATTRIBUTE_NORETURN;
|
|
95 char *load_file (const char *);
|
|
96 void run_compiles (void);
|
|
97 void initialize (int argc, char** argv);
|
|
98 void process (void);
|
|
99
|
|
100 /* External Source Code */
|
|
101
|
|
102 #include "fixincl.x"
|
|
103
|
|
104 /* * * * * * * * * * * * * * * * * * *
|
|
105 *
|
|
106 * MAIN ROUTINE
|
|
107 */
|
|
108 extern int main (int, char **);
|
|
109 int
|
|
110 main (int argc, char** argv)
|
|
111 {
|
|
112 char *file_name_buf;
|
|
113
|
|
114 initialize ( argc, argv );
|
|
115
|
|
116 have_tty = isatty (fileno (stderr));
|
|
117
|
|
118 /* Before anything else, ensure we can allocate our file name buffer. */
|
|
119 file_name_buf = load_file_data (stdin);
|
|
120
|
|
121 /* Because of the way server shells work, you have to keep stdin, out
|
|
122 and err open so that the proper input file does not get closed
|
|
123 by accident */
|
|
124
|
|
125 freopen ("/dev/null", "r", stdin);
|
|
126
|
|
127 if (file_name_buf == (char *) NULL)
|
|
128 {
|
|
129 fputs ("No file names listed for fixing\n", stderr);
|
|
130 exit (EXIT_FAILURE);
|
|
131 }
|
|
132
|
|
133 for (;;)
|
|
134 {
|
|
135 char* pz_end;
|
|
136
|
|
137 /* skip to start of name, past any "./" prefixes */
|
|
138
|
|
139 while (ISSPACE (*file_name_buf)) file_name_buf++;
|
|
140 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
|
|
141 file_name_buf += 2;
|
|
142
|
|
143 /* Check for end of list */
|
|
144
|
|
145 if (*file_name_buf == NUL)
|
|
146 break;
|
|
147
|
|
148 /* Set global file name pointer and find end of name */
|
|
149
|
|
150 pz_curr_file = file_name_buf;
|
|
151 pz_end = strchr( pz_curr_file, '\n' );
|
|
152 if (pz_end == (char*)NULL)
|
|
153 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
|
|
154 else
|
|
155 file_name_buf = pz_end + 1;
|
|
156
|
|
157 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
|
|
158
|
|
159 /* IF no name is found (blank line) or comment marker, skip line */
|
|
160
|
|
161 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
|
|
162 continue;
|
|
163 *pz_end = NUL;
|
|
164
|
|
165 process ();
|
|
166 } /* for (;;) */
|
|
167
|
|
168 #ifdef DO_STATS
|
|
169 if (VLEVEL( VERB_PROGRESS )) {
|
|
170 tSCC zFmt[] =
|
|
171 "\
|
|
172 Processed %5d files containing %d bytes \n\
|
|
173 Applying %5d fixes to %d files\n\
|
|
174 Altering %5d of them\n";
|
|
175
|
|
176 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
|
|
177 fixed_ct, altered_ct);
|
|
178 }
|
|
179 #endif /* DO_STATS */
|
|
180
|
|
181 # ifdef SEPARATE_FIX_PROC
|
|
182 unlink( pz_temp_file );
|
|
183 # endif
|
|
184 exit (EXIT_SUCCESS);
|
|
185 }
|
|
186
|
|
187
|
|
188 static void
|
|
189 do_version (void)
|
|
190 {
|
|
191 static const char zFmt[] = "echo '%s'";
|
|
192 char zBuf[ 1024 ];
|
|
193
|
|
194 /* The 'version' option is really used to test that:
|
|
195 1. The program loads correctly (no missing libraries)
|
|
196 2. that we can compile all the regular expressions.
|
|
197 3. we can correctly run our server shell process
|
|
198 */
|
|
199 run_compiles ();
|
|
200 sprintf (zBuf, zFmt, program_id);
|
|
201 #ifndef SEPARATE_FIX_PROC
|
|
202 puts (zBuf + 5);
|
|
203 exit (strcmp (run_shell (zBuf), program_id));
|
|
204 #else
|
|
205 exit (system (zBuf));
|
|
206 #endif
|
|
207 }
|
|
208
|
|
209 /* * * * * * * * * * * * */
|
|
210
|
|
211 void
|
|
212 initialize ( int argc, char** argv )
|
|
213 {
|
|
214 xmalloc_set_program_name (argv[0]);
|
|
215
|
|
216 switch (argc)
|
|
217 {
|
|
218 case 1:
|
|
219 break;
|
|
220
|
|
221 case 2:
|
|
222 if (strcmp (argv[1], "-v") == 0)
|
|
223 do_version ();
|
|
224 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
|
|
225 {
|
|
226 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
|
|
227 errno, xstrerror (errno), argv[1] );
|
|
228 exit (EXIT_FAILURE);
|
|
229 }
|
|
230 break;
|
|
231
|
|
232 default:
|
|
233 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
|
|
234 exit (EXIT_FAILURE);
|
|
235 }
|
|
236
|
|
237 #ifdef SIGCHLD
|
|
238 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
|
|
239 receive the signal. A different setting is inheritable */
|
|
240 signal (SIGCHLD, SIG_DFL);
|
|
241 #endif
|
|
242
|
|
243 initialize_opts ();
|
|
244
|
|
245 if (ISDIGIT ( *pz_verbose ))
|
|
246 verbose_level = (te_verbose)atoi( pz_verbose );
|
|
247 else
|
|
248 switch (*pz_verbose) {
|
|
249 case 's':
|
|
250 case 'S':
|
|
251 verbose_level = VERB_SILENT; break;
|
|
252
|
|
253 case 'f':
|
|
254 case 'F':
|
|
255 verbose_level = VERB_FIXES; break;
|
|
256
|
|
257 case 'a':
|
|
258 case 'A':
|
|
259 verbose_level = VERB_APPLIES; break;
|
|
260
|
|
261 default:
|
|
262 case 'p':
|
|
263 case 'P':
|
|
264 verbose_level = VERB_PROGRESS; break;
|
|
265
|
|
266 case 't':
|
|
267 case 'T':
|
|
268 verbose_level = VERB_TESTS; break;
|
|
269
|
|
270 case 'e':
|
|
271 case 'E':
|
|
272 verbose_level = VERB_EVERYTHING; break;
|
|
273 }
|
|
274 if (verbose_level >= VERB_EVERYTHING) {
|
|
275 verbose_level = VERB_EVERYTHING;
|
|
276 fputs ("fixinc verbosity: EVERYTHING\n", stderr);
|
|
277 }
|
|
278 while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
|
|
279 pz_find_base += 2;
|
|
280 if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
|
|
281 find_base_len = strlen( pz_find_base );
|
|
282
|
|
283 /* Compile all the regular expressions now.
|
|
284 That way, it is done only once for the whole run.
|
|
285 */
|
|
286 run_compiles ();
|
|
287
|
|
288 # ifdef SEPARATE_FIX_PROC
|
|
289 /* NULL as the first argument to `tempnam' causes it to DTRT
|
|
290 wrt the temporary directory where the file will be created. */
|
|
291 pz_temp_file = tempnam( NULL, "fxinc" );
|
|
292 # endif
|
|
293
|
|
294 signal (SIGQUIT, SIG_IGN);
|
|
295 signal (SIGIOT, SIG_IGN);
|
|
296 signal (SIGPIPE, SIG_IGN);
|
|
297 signal (SIGALRM, SIG_IGN);
|
|
298 signal (SIGTERM, SIG_IGN);
|
|
299 }
|
|
300
|
|
301 /* * * * * * * * * * * * *
|
|
302
|
|
303 load_file loads all the contents of a file into malloc-ed memory.
|
|
304 Its argument is the name of the file to read in; the returned
|
|
305 result is the NUL terminated contents of the file. The file
|
|
306 is presumed to be an ASCII text file containing no NULs. */
|
|
307 char *
|
|
308 load_file ( const char* fname )
|
|
309 {
|
|
310 struct stat stbf;
|
|
311 char* res;
|
|
312
|
|
313 if (stat (fname, &stbf) != 0)
|
|
314 {
|
|
315 if (NOT_SILENT)
|
|
316 fprintf (stderr, "error %d (%s) stat-ing %s\n",
|
|
317 errno, xstrerror (errno), fname );
|
|
318 return (char *) NULL;
|
|
319 }
|
|
320 if (stbf.st_size == 0)
|
|
321 return (char*)NULL;
|
|
322
|
|
323 /* Make the data map size one larger than the file size for documentation
|
|
324 purposes. Truth is that there will be a following NUL character if
|
|
325 the file size is not a multiple of the page size. If it is a multiple,
|
|
326 then this adjustment sometimes fails anyway. */
|
|
327 data_map_size = stbf.st_size+1;
|
|
328 data_map_fd = open (fname, O_RDONLY);
|
|
329 ttl_data_size += data_map_size-1;
|
|
330
|
|
331 if (data_map_fd < 0)
|
|
332 {
|
|
333 if (NOT_SILENT)
|
|
334 fprintf (stderr, "error %d (%s) opening %s for read\n",
|
|
335 errno, xstrerror (errno), fname);
|
|
336 return (char*)NULL;
|
|
337 }
|
|
338
|
|
339 #ifdef HAVE_MMAP_FILE
|
|
340 curr_data_mapped = BOOL_TRUE;
|
|
341
|
|
342 /* IF the file size is a multiple of the page size,
|
|
343 THEN sometimes you will seg fault trying to access a trailing byte */
|
|
344 if ((stbf.st_size & (getpagesize()-1)) == 0)
|
|
345 res = (char*)BAD_ADDR;
|
|
346 else
|
|
347 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
|
|
348 MAP_PRIVATE, data_map_fd, 0);
|
|
349 if (res == (char*)BAD_ADDR)
|
|
350 #endif
|
|
351 {
|
|
352 FILE* fp = fdopen (data_map_fd, "r");
|
|
353 curr_data_mapped = BOOL_FALSE;
|
|
354 res = load_file_data (fp);
|
|
355 fclose (fp);
|
|
356 }
|
|
357
|
|
358 return res;
|
|
359 }
|
|
360
|
|
361 static int
|
|
362 machine_matches( tFixDesc* p_fixd )
|
|
363 {
|
|
364 char const ** papz_machs = p_fixd->papz_machs;
|
|
365 int have_match = BOOL_FALSE;
|
|
366
|
|
367 for (;;)
|
|
368 {
|
|
369 char const * pz_mpat = *(papz_machs++);
|
|
370 if (pz_mpat == NULL)
|
|
371 break;
|
|
372 if (fnmatch(pz_mpat, pz_machine, 0) == 0)
|
|
373 {
|
|
374 have_match = BOOL_TRUE;
|
|
375 break;
|
|
376 }
|
|
377 }
|
|
378
|
|
379 /* Check for sense inversion then set the "skip test" flag, if needed */
|
|
380 if (p_fixd->fd_flags & FD_MACH_IFNOT)
|
|
381 have_match = ! have_match;
|
|
382
|
|
383 if (! have_match)
|
|
384 p_fixd->fd_flags |= FD_SKIP_TEST;
|
|
385
|
|
386 return have_match;
|
|
387 }
|
|
388
|
|
389 /* * * * * * * * * * * * *
|
|
390 *
|
|
391 * run_compiles run all the regexp compiles for all the fixes once.
|
|
392 */
|
|
393 void
|
|
394 run_compiles (void)
|
|
395 {
|
|
396 tFixDesc *p_fixd = fixDescList;
|
|
397 int fix_ct = FIX_COUNT;
|
|
398 regex_t *p_re = XCNEWVEC (regex_t, REGEX_COUNT);
|
|
399
|
|
400 /* Make sure compile_re does not stumble across invalid data */
|
|
401
|
|
402 memset (&incl_quote_re, '\0', sizeof (regex_t));
|
|
403
|
|
404 compile_re (incl_quote_pat, &incl_quote_re, 1,
|
|
405 "quoted include", "run_compiles");
|
|
406
|
|
407 /* Allow machine name tests to be ignored (testing, mainly) */
|
|
408
|
|
409 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
|
|
410 pz_machine = (char*)NULL;
|
|
411
|
|
412 /* FOR every fixup, ... */
|
|
413 do
|
|
414 {
|
|
415 tTestDesc *p_test = p_fixd->p_test_desc;
|
|
416 int test_ct = p_fixd->test_ct;
|
|
417
|
|
418 /* IF the machine type pointer is not NULL (we are not in test mode)
|
|
419 AND this test is for or not done on particular machines
|
|
420 THEN ... */
|
|
421
|
|
422 if ( (pz_machine != NULL)
|
|
423 && (p_fixd->papz_machs != (const char**) NULL)
|
|
424 && ! machine_matches (p_fixd) )
|
|
425 continue;
|
|
426
|
|
427 /* FOR every test for the fixup, ... */
|
|
428
|
|
429 while (--test_ct >= 0)
|
|
430 {
|
|
431 switch (p_test->type)
|
|
432 {
|
|
433 case TT_EGREP:
|
|
434 case TT_NEGREP:
|
|
435 p_test->p_test_regex = p_re++;
|
|
436 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
|
|
437 "select test", p_fixd->fix_name);
|
|
438 default: break;
|
|
439 }
|
|
440 p_test++;
|
|
441 }
|
|
442 }
|
|
443 while (p_fixd++, --fix_ct > 0);
|
|
444 }
|
|
445
|
|
446
|
|
447 /* * * * * * * * * * * * *
|
|
448
|
|
449 create_file Create the output modified file.
|
|
450 Input: the name of the file to create
|
|
451 Returns: a file pointer to the new, open file */
|
|
452
|
|
453 #if defined(S_IRUSR) && defined(S_IWUSR) && \
|
|
454 defined(S_IRGRP) && defined(S_IROTH)
|
|
455
|
|
456 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
|
457 #else
|
|
458 # define S_IRALL 0644
|
|
459 #endif
|
|
460
|
|
461 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
|
|
462 defined(S_IROTH) && defined(S_IXOTH)
|
|
463
|
|
464 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
|
|
465 #else
|
|
466 # define S_DIRALL 0755
|
|
467 #endif
|
|
468
|
|
469
|
|
470 static FILE *
|
|
471 create_file (void)
|
|
472 {
|
|
473 int fd;
|
|
474 FILE *pf;
|
|
475 char fname[MAXPATHLEN];
|
|
476
|
|
477 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
|
|
478
|
|
479 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
|
|
480
|
|
481 /* We may need to create the directories needed... */
|
|
482 if ((fd < 0) && (errno == ENOENT))
|
|
483 {
|
|
484 char *pz_dir = strchr (fname + 1, '/');
|
|
485 struct stat stbf;
|
|
486
|
|
487 while (pz_dir != (char *) NULL)
|
|
488 {
|
|
489 *pz_dir = NUL;
|
|
490 if (stat (fname, &stbf) < 0)
|
|
491 {
|
|
492 #ifdef _WIN32
|
|
493 mkdir (fname);
|
|
494 #else
|
|
495 mkdir (fname, S_IFDIR | S_DIRALL);
|
|
496 #endif
|
|
497 }
|
|
498
|
|
499 *pz_dir = '/';
|
|
500 pz_dir = strchr (pz_dir + 1, '/');
|
|
501 }
|
|
502
|
|
503 /* Now, lets try the open again... */
|
|
504 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
|
|
505 }
|
|
506 if (fd < 0)
|
|
507 {
|
|
508 fprintf (stderr, "Error %d (%s) creating %s\n",
|
|
509 errno, xstrerror (errno), fname);
|
|
510 exit (EXIT_FAILURE);
|
|
511 }
|
|
512 if (NOT_SILENT)
|
|
513 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
|
|
514 pf = fdopen (fd, "w");
|
|
515
|
|
516 /*
|
|
517 * IF pz_machine is NULL, then we are in some sort of test mode.
|
|
518 * Do not insert the current directory name. Use a constant string.
|
|
519 */
|
|
520 fprintf (pf, z_std_preamble,
|
|
521 (pz_machine == NULL)
|
|
522 ? "fixinc/tests/inc"
|
|
523 : pz_input_dir,
|
|
524 pz_curr_file);
|
|
525
|
|
526 return pf;
|
|
527 }
|
|
528
|
|
529
|
|
530 /* * * * * * * * * * * * *
|
|
531
|
|
532 test_test make sure a shell-style test expression passes.
|
|
533 Input: a pointer to the descriptor of the test to run and
|
|
534 the name of the file that we might want to fix
|
|
535 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
|
|
536 shell script we run. */
|
|
537 #ifndef SEPARATE_FIX_PROC
|
|
538 static int
|
|
539 test_test (tTestDesc* p_test, char* pz_test_file)
|
|
540 {
|
|
541 tSCC cmd_fmt[] =
|
|
542 "file=%s\n\
|
|
543 if ( test %s ) > /dev/null 2>&1\n\
|
|
544 then echo TRUE\n\
|
|
545 else echo FALSE\n\
|
|
546 fi";
|
|
547
|
|
548 char *pz_res;
|
|
549 int res;
|
|
550
|
|
551 static char cmd_buf[4096];
|
|
552
|
|
553 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
|
|
554 pz_res = run_shell (cmd_buf);
|
|
555
|
|
556 switch (*pz_res) {
|
|
557 case 'T':
|
|
558 res = APPLY_FIX;
|
|
559 break;
|
|
560
|
|
561 case 'F':
|
|
562 res = SKIP_FIX;
|
|
563 break;
|
|
564
|
|
565 default:
|
|
566 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
|
|
567 pz_res, cmd_buf );
|
|
568 res = SKIP_FIX;
|
|
569 }
|
|
570
|
|
571 free ((void *) pz_res);
|
|
572 return res;
|
|
573 }
|
|
574 #else
|
|
575 /*
|
|
576 * IF we are in MS-DOS land, then whatever shell-type test is required
|
|
577 * will, by definition, fail
|
|
578 */
|
|
579 #define test_test(t,tf) SKIP_FIX
|
|
580 #endif
|
|
581
|
|
582 /* * * * * * * * * * * * *
|
|
583
|
|
584 egrep_test make sure an egrep expression is found in the file text.
|
|
585 Input: a pointer to the descriptor of the test to run and
|
|
586 the pointer to the contents of the file under suspicion
|
|
587 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
|
|
588
|
|
589 The caller may choose to reverse meaning if the sense of the test
|
|
590 is inverted. */
|
|
591
|
|
592 static int
|
|
593 egrep_test (char* pz_data, tTestDesc* p_test)
|
|
594 {
|
|
595 #ifdef DEBUG
|
|
596 if (p_test->p_test_regex == 0)
|
|
597 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
|
|
598 p_test->pz_test_text);
|
|
599 #endif
|
|
600 if (xregexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
|
|
601 return APPLY_FIX;
|
|
602 return SKIP_FIX;
|
|
603 }
|
|
604
|
|
605
|
|
606 /* * * * * * * * * * * * *
|
|
607
|
|
608 quoted_file_exists Make sure that a file exists before we emit
|
|
609 the file name. If we emit the name, our invoking shell will try
|
|
610 to copy a non-existing file into the destination directory. */
|
|
611
|
|
612 static int
|
|
613 quoted_file_exists (const char* pz_src_path,
|
|
614 const char* pz_file_path,
|
|
615 const char* pz_file)
|
|
616 {
|
|
617 char z[ MAXPATHLEN ];
|
|
618 char* pz;
|
|
619 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
|
|
620 pz = z + strlen ( z );
|
|
621
|
|
622 for (;;) {
|
|
623 char ch = *pz_file++;
|
|
624 if (! ISGRAPH( ch ))
|
|
625 return 0;
|
|
626 if (ch == '"')
|
|
627 break;
|
|
628 *pz++ = ch;
|
|
629 }
|
|
630 *pz = '\0';
|
|
631 {
|
|
632 struct stat s;
|
|
633 if (stat (z, &s) != 0)
|
|
634 return 0;
|
|
635 return S_ISREG( s.st_mode );
|
|
636 }
|
|
637 }
|
|
638
|
|
639
|
|
640 /* * * * * * * * * * * * *
|
|
641 *
|
|
642 extract_quoted_files
|
|
643
|
|
644 The syntax, `#include "file.h"' specifies that the compiler is to
|
|
645 search the local directory of the current file before the include
|
|
646 list. Consequently, if we have modified a header and stored it in
|
|
647 another directory, any files that are included by that modified
|
|
648 file in that fashion must also be copied into this new directory.
|
|
649 This routine finds those flavors of #include and for each one found
|
|
650 emits a triple of:
|
|
651
|
|
652 1. source directory of the original file
|
|
653 2. the relative path file name of the #includ-ed file
|
|
654 3. the full destination path for this file
|
|
655
|
|
656 Input: the text of the file, the file name and a pointer to the
|
|
657 match list where the match information was stored.
|
|
658 Result: internally nothing. The results are written to stdout
|
|
659 for interpretation by the invoking shell */
|
|
660
|
|
661
|
|
662 static void
|
|
663 extract_quoted_files (char* pz_data,
|
|
664 const char* pz_fixed_file,
|
|
665 regmatch_t* p_re_match)
|
|
666 {
|
|
667 char *pz_dir_end = strrchr (pz_fixed_file, '/');
|
|
668 char *pz_incl_quot = pz_data;
|
|
669
|
|
670 if (VLEVEL( VERB_APPLIES ))
|
|
671 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
|
|
672
|
|
673 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
|
|
674 If there is none, then it is in our current directory, ".". */
|
|
675
|
|
676 if (pz_dir_end == (char *) NULL)
|
|
677 pz_fixed_file = ".";
|
|
678 else
|
|
679 *pz_dir_end = '\0';
|
|
680
|
|
681 for (;;)
|
|
682 {
|
|
683 pz_incl_quot += p_re_match->rm_so;
|
|
684
|
|
685 /* Skip forward to the included file name */
|
|
686 while (*pz_incl_quot != '"')
|
|
687 pz_incl_quot++;
|
|
688
|
|
689 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
|
|
690 {
|
|
691 /* Print the source directory and the subdirectory
|
|
692 of the file in question. */
|
|
693 printf ("%s %s/", pz_src_dir, pz_fixed_file);
|
|
694 pz_dir_end = pz_incl_quot;
|
|
695
|
|
696 /* Append to the directory the relative path of the desired file */
|
|
697 while (*pz_incl_quot != '"')
|
|
698 putc (*pz_incl_quot++, stdout);
|
|
699
|
|
700 /* Now print the destination directory appended with the
|
|
701 relative path of the desired file */
|
|
702 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
|
|
703 while (*pz_dir_end != '"')
|
|
704 putc (*pz_dir_end++, stdout);
|
|
705
|
|
706 /* End of entry */
|
|
707 putc ('\n', stdout);
|
|
708 }
|
|
709
|
|
710 /* Find the next entry */
|
|
711 if (xregexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
|
|
712 break;
|
|
713 }
|
|
714 }
|
|
715
|
|
716
|
|
717 /* * * * * * * * * * * * *
|
|
718
|
|
719 Somebody wrote a *_fix subroutine that we must call.
|
|
720 */
|
|
721 #ifndef SEPARATE_FIX_PROC
|
|
722 static int
|
|
723 internal_fix (int read_fd, tFixDesc* p_fixd)
|
|
724 {
|
|
725 int fd[2];
|
|
726
|
|
727 if (pipe( fd ) != 0)
|
|
728 {
|
|
729 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
|
|
730 exit (EXIT_FAILURE);
|
|
731 }
|
|
732
|
|
733 for (;;)
|
|
734 {
|
|
735 pid_t childid = fork();
|
|
736
|
|
737 switch (childid)
|
|
738 {
|
|
739 case -1:
|
|
740 break;
|
|
741
|
|
742 case 0:
|
|
743 close (fd[0]);
|
|
744 goto do_child_task;
|
|
745
|
|
746 default:
|
|
747 /*
|
|
748 * Parent process
|
|
749 */
|
|
750 close (read_fd);
|
|
751 close (fd[1]);
|
|
752 return fd[0];
|
|
753 }
|
|
754
|
|
755 /*
|
|
756 * Parent in error
|
|
757 */
|
|
758 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
|
|
759 p_fixd->fix_name);
|
|
760 {
|
|
761 static int failCt = 0;
|
|
762 if ((errno != EAGAIN) || (++failCt > 10))
|
|
763 exit (EXIT_FAILURE);
|
|
764 sleep (1);
|
|
765 }
|
|
766 } do_child_task:;
|
|
767
|
|
768 /*
|
|
769 * Close our current stdin and stdout
|
|
770 */
|
|
771 close (STDIN_FILENO);
|
|
772 close (STDOUT_FILENO);
|
|
773 UNLOAD_DATA();
|
|
774
|
|
775 /*
|
|
776 * Make the fd passed in the stdin, and the write end of
|
|
777 * the new pipe become the stdout.
|
|
778 */
|
|
779 dup2 (fd[1], STDOUT_FILENO);
|
|
780 dup2 (read_fd, STDIN_FILENO);
|
|
781
|
|
782 apply_fix (p_fixd, pz_curr_file);
|
|
783 exit (0);
|
|
784 }
|
|
785 #endif /* !SEPARATE_FIX_PROC */
|
|
786
|
|
787
|
|
788 #ifdef SEPARATE_FIX_PROC
|
|
789 static void
|
|
790 fix_with_system (tFixDesc* p_fixd,
|
|
791 tCC* pz_fix_file,
|
|
792 tCC* pz_file_source,
|
|
793 tCC* pz_temp_file)
|
|
794 {
|
|
795 char* pz_cmd;
|
|
796 char* pz_scan;
|
|
797 size_t argsize;
|
|
798
|
|
799 if (p_fixd->fd_flags & FD_SUBROUTINE)
|
|
800 {
|
|
801 static const char z_applyfix_prog[] =
|
|
802 "/../fixincludes/applyfix" EXE_EXT;
|
|
803
|
|
804 struct stat buf;
|
|
805 argsize = 32
|
|
806 + strlen (pz_orig_dir)
|
|
807 + sizeof (z_applyfix_prog)
|
|
808 + strlen (pz_fix_file)
|
|
809 + strlen (pz_file_source)
|
|
810 + strlen (pz_temp_file);
|
|
811
|
|
812 /* Allocate something sure to be big enough for our purposes */
|
|
813 pz_cmd = XNEWVEC (char, argsize);
|
|
814 strcpy (pz_cmd, pz_orig_dir);
|
|
815 pz_scan = pz_cmd + strlen (pz_orig_dir);
|
|
816
|
|
817 strcpy (pz_scan, z_applyfix_prog);
|
|
818
|
|
819 /* IF we can't find the "applyfix" executable file at the first guess,
|
|
820 try one level higher up */
|
|
821 if (stat (pz_cmd, &buf) == -1)
|
|
822 {
|
|
823 strcpy (pz_scan, "/..");
|
|
824 strcpy (pz_scan+3, z_applyfix_prog);
|
|
825 }
|
|
826
|
|
827 pz_scan += strlen (pz_scan);
|
|
828
|
|
829 /*
|
|
830 * Now add the fix number and file names that may be needed
|
|
831 */
|
|
832 sprintf (pz_scan, " %ld '%s' '%s'", (long) (p_fixd - fixDescList),
|
|
833 pz_fix_file, pz_file_source, pz_temp_file);
|
|
834 }
|
|
835 else /* NOT an "internal" fix: */
|
|
836 {
|
|
837 size_t parg_size;
|
|
838 #ifdef __MSDOS__
|
|
839 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
|
|
840 dst is a temporary file anyway, so we know there's no other
|
|
841 file by that name; and DOS's system(3) doesn't mind to
|
|
842 clobber existing file in redirection. Besides, with DOS 8+3
|
|
843 limited file namespace, we can easily lose if dst already has
|
|
844 an extension that is 3 or more characters long.
|
|
845
|
|
846 I do not think the 8+3 issue is relevant because all the files
|
|
847 we operate on are named "*.h", making 8+2 adequate. Anyway,
|
|
848 the following bizarre use of 'cat' only works on DOS boxes.
|
|
849 It causes the file to be dropped into a temporary file for
|
|
850 'cat' to read (pipes do not work on DOS). */
|
|
851 tSCC z_cmd_fmt[] = " '%s' | cat > '%s'";
|
|
852 #else
|
|
853 /* Don't use positional formatting arguments because some lame-o
|
|
854 implementations cannot cope :-(. */
|
|
855 tSCC z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
|
|
856 #endif
|
|
857 tCC** ppArgs = p_fixd->patch_args;
|
|
858
|
|
859 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
|
|
860 + strlen( pz_file_source );
|
|
861 parg_size = argsize;
|
|
862
|
|
863
|
|
864 /*
|
|
865 * Compute the size of the command line. Add lotsa extra space
|
|
866 * because some of the args to sed use lotsa single quotes.
|
|
867 * (This requires three extra bytes per quote. Here we allow
|
|
868 * for up to 8 single quotes for each argument, including the
|
|
869 * command name "sed" itself. Nobody will *ever* need more. :)
|
|
870 */
|
|
871 for (;;)
|
|
872 {
|
|
873 tCC* p_arg = *(ppArgs++);
|
|
874 if (p_arg == NULL)
|
|
875 break;
|
|
876 argsize += 24 + strlen( p_arg );
|
|
877 }
|
|
878
|
|
879 /* Estimated buffer size we will need. */
|
|
880 pz_scan = pz_cmd = XNEWVEC (char, argsize);
|
|
881 /* How much of it do we allot to the program name and its
|
|
882 arguments. */
|
|
883 parg_size = argsize - parg_size;
|
|
884
|
|
885 ppArgs = p_fixd->patch_args;
|
|
886
|
|
887 /*
|
|
888 * Copy the program name, unquoted
|
|
889 */
|
|
890 {
|
|
891 tCC* pArg = *(ppArgs++);
|
|
892 for (;;)
|
|
893 {
|
|
894 char ch = *(pArg++);
|
|
895 if (ch == NUL)
|
|
896 break;
|
|
897 *(pz_scan++) = ch;
|
|
898 }
|
|
899 }
|
|
900
|
|
901 /*
|
|
902 * Copy the program arguments, quoted
|
|
903 */
|
|
904 for (;;)
|
|
905 {
|
|
906 tCC* pArg = *(ppArgs++);
|
|
907 char* pz_scan_save;
|
|
908 if (pArg == NULL)
|
|
909 break;
|
|
910 *(pz_scan++) = ' ';
|
|
911 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
|
|
912 parg_size - (pz_scan - pz_cmd) );
|
|
913 /*
|
|
914 * Make sure we don't overflow the buffer due to sloppy
|
|
915 * size estimation.
|
|
916 */
|
|
917 while (pz_scan == (char*)NULL)
|
|
918 {
|
|
919 size_t already_filled = pz_scan_save - pz_cmd;
|
|
920 pz_cmd = xrealloc (pz_cmd, argsize += 100);
|
|
921 pz_scan_save = pz_scan = pz_cmd + already_filled;
|
|
922 parg_size += 100;
|
|
923 pz_scan = make_raw_shell_str( pz_scan, pArg,
|
|
924 parg_size - (pz_scan - pz_cmd) );
|
|
925 }
|
|
926 }
|
|
927
|
|
928 /*
|
|
929 * add the file machinations.
|
|
930 */
|
|
931 #ifdef __MSDOS__
|
|
932 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
|
|
933 #else
|
|
934 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
|
|
935 pz_temp_file, pz_temp_file, pz_temp_file);
|
|
936 #endif
|
|
937 }
|
|
938 system( pz_cmd );
|
|
939 free( (void*)pz_cmd );
|
|
940 }
|
|
941
|
|
942 /* * * * * * * * * * * * *
|
|
943
|
|
944 This loop should only cycle for 1/2 of one loop.
|
|
945 "chain_open" starts a process that uses "read_fd" as
|
|
946 its stdin and returns the new fd this process will use
|
|
947 for stdout. */
|
|
948
|
|
949 #else /* is *NOT* SEPARATE_FIX_PROC */
|
|
950 static int
|
|
951 start_fixer (int read_fd, tFixDesc* p_fixd, char* pz_fix_file)
|
|
952 {
|
|
953 tCC* pz_cmd_save;
|
|
954 char* pz_cmd;
|
|
955
|
|
956 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
|
|
957 return internal_fix (read_fd, p_fixd);
|
|
958
|
|
959 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
|
|
960 {
|
|
961 pz_cmd = NULL;
|
|
962 pz_cmd_save = NULL;
|
|
963 }
|
|
964 else
|
|
965 {
|
|
966 tSCC z_cmd_fmt[] = "file='%s'\n%s";
|
|
967 pz_cmd = XNEWVEC (char, strlen (p_fixd->patch_args[2])
|
|
968 + sizeof (z_cmd_fmt) + strlen (pz_fix_file));
|
|
969 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
|
|
970 pz_cmd_save = p_fixd->patch_args[2];
|
|
971 p_fixd->patch_args[2] = pz_cmd;
|
|
972 }
|
|
973
|
|
974 /* Start a fix process, handing off the previous read fd for its
|
|
975 stdin and getting a new fd that reads from the fix process' stdout.
|
|
976 We normally will not loop, but we will up to 10 times if we keep
|
|
977 getting "EAGAIN" errors.
|
|
978
|
|
979 */
|
|
980 for (;;)
|
|
981 {
|
|
982 static int failCt = 0;
|
|
983 int fd;
|
|
984
|
|
985 fd = chain_open (read_fd,
|
|
986 (tCC **) p_fixd->patch_args,
|
|
987 (process_chain_head == -1)
|
|
988 ? &process_chain_head : (pid_t *) NULL);
|
|
989
|
|
990 if (fd != -1)
|
|
991 {
|
|
992 read_fd = fd;
|
|
993 break;
|
|
994 }
|
|
995
|
|
996 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
|
|
997 p_fixd->fix_name);
|
|
998
|
|
999 if ((errno != EAGAIN) || (++failCt > 10))
|
|
1000 exit (EXIT_FAILURE);
|
|
1001 sleep (1);
|
|
1002 }
|
|
1003
|
|
1004 /* IF we allocated a shell script command,
|
|
1005 THEN free it and restore the command format to the fix description */
|
|
1006 if (pz_cmd != (char*)NULL)
|
|
1007 {
|
|
1008 free ((void*)pz_cmd);
|
|
1009 p_fixd->patch_args[2] = pz_cmd_save;
|
|
1010 }
|
|
1011
|
|
1012 return read_fd;
|
|
1013 }
|
|
1014 #endif
|
|
1015
|
|
1016
|
|
1017 /* * * * * * * * * * * * *
|
|
1018 *
|
|
1019 * Process the potential fixes for a particular include file.
|
|
1020 * Input: the original text of the file and the file's name
|
|
1021 * Result: none. A new file may or may not be created.
|
|
1022 */
|
|
1023 static t_bool
|
|
1024 fix_applies (tFixDesc* p_fixd)
|
|
1025 {
|
|
1026 const char *pz_fname = pz_curr_file;
|
|
1027 const char *pz_scan = p_fixd->file_list;
|
|
1028 int test_ct;
|
|
1029 tTestDesc *p_test;
|
|
1030
|
|
1031 #ifdef SEPARATE_FIX_PROC
|
|
1032 /*
|
|
1033 * There is only one fix that uses a shell script as of this writing.
|
|
1034 * I hope to nuke it anyway, it does not apply to DOS and it would
|
|
1035 * be painful to implement. Therefore, no "shell" fixes for DOS.
|
|
1036 */
|
|
1037 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
|
|
1038 return BOOL_FALSE;
|
|
1039 #else
|
|
1040 if (p_fixd->fd_flags & FD_SKIP_TEST)
|
|
1041 return BOOL_FALSE;
|
|
1042 #endif
|
|
1043
|
|
1044 /* IF there is a file name restriction,
|
|
1045 THEN ensure the current file name matches one in the pattern */
|
|
1046
|
|
1047 if (pz_scan != (char *) NULL)
|
|
1048 {
|
|
1049 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
|
|
1050 pz_fname += 2;
|
|
1051
|
|
1052 for (;;)
|
|
1053 {
|
|
1054 if (fnmatch (pz_scan, pz_fname, 0) == 0)
|
|
1055 break;
|
|
1056 pz_scan += strlen (pz_scan) + 1;
|
|
1057 if (*pz_scan == NUL)
|
|
1058 return BOOL_FALSE;
|
|
1059 }
|
|
1060 }
|
|
1061
|
|
1062 /* FOR each test, see if it fails.
|
|
1063 IF it does fail, then we go on to the next test */
|
|
1064
|
|
1065 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
|
|
1066 test_ct-- > 0;
|
|
1067 p_test++)
|
|
1068 {
|
|
1069 switch (p_test->type)
|
|
1070 {
|
|
1071 case TT_TEST:
|
|
1072 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
|
|
1073 #ifdef DEBUG
|
|
1074 if (VLEVEL( VERB_EVERYTHING ))
|
|
1075 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
|
|
1076 pz_fname, p_fixd->test_ct - test_ct);
|
|
1077 #endif
|
|
1078 return BOOL_FALSE;
|
|
1079 }
|
|
1080 break;
|
|
1081
|
|
1082 case TT_EGREP:
|
|
1083 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
|
|
1084 #ifdef DEBUG
|
|
1085 if (VLEVEL( VERB_EVERYTHING ))
|
|
1086 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
|
|
1087 pz_fname, p_fixd->test_ct - test_ct);
|
|
1088 #endif
|
|
1089 return BOOL_FALSE;
|
|
1090 }
|
|
1091 break;
|
|
1092
|
|
1093 case TT_NEGREP:
|
|
1094 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
|
|
1095 #ifdef DEBUG
|
|
1096 if (VLEVEL( VERB_EVERYTHING ))
|
|
1097 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
|
|
1098 pz_fname, p_fixd->test_ct - test_ct);
|
|
1099 #endif
|
|
1100 /* Negated sense */
|
|
1101 return BOOL_FALSE;
|
|
1102 }
|
|
1103 break;
|
|
1104
|
|
1105 case TT_FUNCTION:
|
|
1106 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
|
|
1107 != APPLY_FIX) {
|
|
1108 #ifdef DEBUG
|
|
1109 if (VLEVEL( VERB_EVERYTHING ))
|
|
1110 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
|
|
1111 pz_fname, p_fixd->test_ct - test_ct);
|
|
1112 #endif
|
|
1113 return BOOL_FALSE;
|
|
1114 }
|
|
1115 break;
|
|
1116 }
|
|
1117 }
|
|
1118
|
|
1119 return BOOL_TRUE;
|
|
1120 }
|
|
1121
|
|
1122
|
|
1123 /* * * * * * * * * * * * *
|
|
1124
|
|
1125 Write out a replacement file */
|
|
1126
|
|
1127 static void
|
|
1128 write_replacement (tFixDesc* p_fixd)
|
|
1129 {
|
|
1130 const char* pz_text = p_fixd->patch_args[0];
|
|
1131
|
|
1132 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
|
|
1133 return;
|
|
1134
|
|
1135 {
|
|
1136 FILE* out_fp = create_file ();
|
|
1137 size_t sz = strlen (pz_text);
|
|
1138 fwrite (pz_text, sz, 1, out_fp);
|
|
1139 if (pz_text[ sz-1 ] != '\n')
|
|
1140 fputc ('\n', out_fp);
|
|
1141 fclose (out_fp);
|
|
1142 }
|
|
1143 }
|
|
1144
|
|
1145
|
|
1146 /* * * * * * * * * * * * *
|
|
1147
|
|
1148 We have work to do. Read back in the output
|
|
1149 of the filtering chain. Compare each byte as we read it with
|
|
1150 the contents of the original file. As soon as we find any
|
|
1151 difference, we will create the output file, write out all
|
|
1152 the matched text and then copy any remaining data from the
|
|
1153 output of the filter chain.
|
|
1154 */
|
|
1155 static void
|
|
1156 test_for_changes (int read_fd)
|
|
1157 {
|
|
1158 FILE *in_fp = fdopen (read_fd, "r");
|
|
1159 FILE *out_fp = (FILE *) NULL;
|
|
1160 unsigned char *pz_cmp = (unsigned char*)pz_curr_data;
|
|
1161
|
|
1162 #ifdef DO_STATS
|
|
1163 fixed_ct++;
|
|
1164 #endif
|
|
1165 for (;;)
|
|
1166 {
|
|
1167 int ch;
|
|
1168
|
|
1169 ch = getc (in_fp);
|
|
1170 if (ch == EOF)
|
|
1171 break;
|
|
1172 ch &= 0xFF; /* all bytes are 8 bits */
|
|
1173
|
|
1174 /* IF we are emitting the output
|
|
1175 THEN emit this character, too.
|
|
1176 */
|
|
1177 if (out_fp != (FILE *) NULL)
|
|
1178 putc (ch, out_fp);
|
|
1179
|
|
1180 /* ELSE if this character does not match the original,
|
|
1181 THEN now is the time to start the output.
|
|
1182 */
|
|
1183 else if (ch != *pz_cmp)
|
|
1184 {
|
|
1185 out_fp = create_file ();
|
|
1186
|
|
1187 #ifdef DO_STATS
|
|
1188 altered_ct++;
|
|
1189 #endif
|
|
1190 /* IF there are matched data, write the matched part now. */
|
|
1191 if ((char*)pz_cmp != pz_curr_data)
|
|
1192 fwrite (pz_curr_data, (size_t)((char*)pz_cmp - pz_curr_data),
|
|
1193 1, out_fp);
|
|
1194
|
|
1195 /* Emit the current unmatching character */
|
|
1196 putc (ch, out_fp);
|
|
1197 }
|
|
1198 else
|
|
1199 /* ELSE the character matches. Advance the compare ptr */
|
|
1200 pz_cmp++;
|
|
1201 }
|
|
1202
|
|
1203 /* IF we created the output file, ... */
|
|
1204 if (out_fp != (FILE *) NULL)
|
|
1205 {
|
|
1206 regmatch_t match;
|
|
1207
|
|
1208 /* Close the file and see if we have to worry about
|
|
1209 `#include "file.h"' constructs. */
|
|
1210 fclose (out_fp);
|
|
1211 if (xregexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
|
|
1212 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
|
|
1213 }
|
|
1214
|
|
1215 fclose (in_fp);
|
|
1216 close (read_fd); /* probably redundant, but I'm paranoid */
|
|
1217 }
|
|
1218
|
|
1219
|
|
1220 /* * * * * * * * * * * * *
|
|
1221
|
|
1222 Process the potential fixes for a particular include file.
|
|
1223 Input: the original text of the file and the file's name
|
|
1224 Result: none. A new file may or may not be created. */
|
|
1225
|
|
1226 void
|
|
1227 process (void)
|
|
1228 {
|
|
1229 tFixDesc *p_fixd = fixDescList;
|
|
1230 int todo_ct = FIX_COUNT;
|
|
1231 int read_fd = -1;
|
|
1232 # ifndef SEPARATE_FIX_PROC
|
|
1233 int num_children = 0;
|
|
1234 # else /* is SEPARATE_FIX_PROC */
|
|
1235 char* pz_file_source = pz_curr_file;
|
|
1236 # endif
|
|
1237
|
|
1238 if (access (pz_curr_file, R_OK) != 0)
|
|
1239 {
|
|
1240 int erno = errno;
|
|
1241 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
|
|
1242 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
|
|
1243 erno, xstrerror (erno));
|
|
1244 return;
|
|
1245 }
|
|
1246
|
|
1247 pz_curr_data = load_file (pz_curr_file);
|
|
1248 if (pz_curr_data == (char *) NULL)
|
|
1249 return;
|
|
1250
|
|
1251 #ifdef DO_STATS
|
|
1252 process_ct++;
|
|
1253 #endif
|
|
1254 if (VLEVEL( VERB_PROGRESS ) && have_tty)
|
|
1255 fprintf (stderr, "%6lu %-50s \r",
|
|
1256 (unsigned long) data_map_size, pz_curr_file);
|
|
1257
|
|
1258 # ifndef SEPARATE_FIX_PROC
|
|
1259 process_chain_head = NOPROCESS;
|
|
1260
|
|
1261 /* For every fix in our fix list, ... */
|
|
1262 for (; todo_ct > 0; p_fixd++, todo_ct--)
|
|
1263 {
|
|
1264 if (! fix_applies (p_fixd))
|
|
1265 continue;
|
|
1266
|
|
1267 if (VLEVEL( VERB_APPLIES ))
|
|
1268 fprintf (stderr, "Applying %-24s to %s\n",
|
|
1269 p_fixd->fix_name, pz_curr_file);
|
|
1270
|
|
1271 if (p_fixd->fd_flags & FD_REPLACEMENT)
|
|
1272 {
|
|
1273 write_replacement (p_fixd);
|
|
1274 UNLOAD_DATA();
|
|
1275 return;
|
|
1276 }
|
|
1277
|
|
1278 /* IF we do not have a read pointer,
|
|
1279 THEN this is the first fix for the current file.
|
|
1280 Open the source file. That will be used as stdin for
|
|
1281 the first fix. Any subsequent fixes will use the
|
|
1282 stdout descriptor of the previous fix for its stdin. */
|
|
1283
|
|
1284 if (read_fd == -1)
|
|
1285 {
|
|
1286 read_fd = open (pz_curr_file, O_RDONLY);
|
|
1287 if (read_fd < 0)
|
|
1288 {
|
|
1289 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
|
|
1290 xstrerror (errno), pz_curr_file);
|
|
1291 exit (EXIT_FAILURE);
|
|
1292 }
|
|
1293
|
|
1294 /* Ensure we do not get duplicate output */
|
|
1295
|
|
1296 fflush (stdout);
|
|
1297 }
|
|
1298
|
|
1299 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
|
|
1300 num_children++;
|
|
1301 }
|
|
1302
|
|
1303 /* IF we have a read-back file descriptor,
|
|
1304 THEN check for changes and write output if changed. */
|
|
1305
|
|
1306 if (read_fd >= 0)
|
|
1307 {
|
|
1308 test_for_changes (read_fd);
|
|
1309 #ifdef DO_STATS
|
|
1310 apply_ct += num_children;
|
|
1311 #endif
|
|
1312 /* Wait for child processes created by chain_open()
|
|
1313 to avoid leaving zombies. */
|
|
1314 do {
|
|
1315 wait ((int *) NULL);
|
|
1316 } while (--num_children > 0);
|
|
1317 }
|
|
1318
|
|
1319 # else /* is SEPARATE_FIX_PROC */
|
|
1320
|
|
1321 for (; todo_ct > 0; p_fixd++, todo_ct--)
|
|
1322 {
|
|
1323 if (! fix_applies (p_fixd))
|
|
1324 continue;
|
|
1325
|
|
1326 if (VLEVEL( VERB_APPLIES ))
|
|
1327 fprintf (stderr, "Applying %-24s to %s\n",
|
|
1328 p_fixd->fix_name, pz_curr_file);
|
|
1329
|
|
1330 if (p_fixd->fd_flags & FD_REPLACEMENT)
|
|
1331 {
|
|
1332 write_replacement (p_fixd);
|
|
1333 UNLOAD_DATA();
|
|
1334 return;
|
|
1335 }
|
|
1336 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
|
|
1337 pz_file_source = pz_temp_file;
|
|
1338 }
|
|
1339
|
|
1340 read_fd = open (pz_temp_file, O_RDONLY);
|
|
1341 if (read_fd < 0)
|
|
1342 {
|
|
1343 if (errno != ENOENT)
|
|
1344 fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
|
|
1345 errno, xstrerror (errno), pz_temp_file);
|
|
1346 }
|
|
1347 else
|
|
1348 {
|
|
1349 test_for_changes (read_fd);
|
|
1350 /* Unlinking a file while it is still open is a Bad Idea on
|
|
1351 DOS/Windows. */
|
|
1352 close (read_fd);
|
|
1353 unlink (pz_temp_file);
|
|
1354 }
|
|
1355
|
|
1356 # endif
|
|
1357 UNLOAD_DATA();
|
|
1358 }
|