OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [fixincludes/] [fixincl.c] - Blame information for rev 770

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 724 jeremybenn
/* 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.