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