OSDN Git Service

* alias.c alloc-pool.c bitmap.c bitmap.h bt-load.c builtins.c
[pf3gnuchains/gcc-fork.git] / gcc / protoize.c
1 /* Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
2    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3    1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "intl.h"
27 #include "cppdefault.h"
28
29 #include <setjmp.h>
30 #include <signal.h>
31 #if ! defined( SIGCHLD ) && defined( SIGCLD )
32 #  define SIGCHLD SIGCLD
33 #endif
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #undef abort
38 #include "version.h"
39
40 /* Include getopt.h for the sake of getopt_long.  */
41 #include "getopt.h"
42
43 /* Macro to see if the path elements match.  */
44 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
45 #define IS_SAME_PATH_CHAR(a,b) (TOUPPER (a) == TOUPPER (b))
46 #else
47 #define IS_SAME_PATH_CHAR(a,b) ((a) == (b))
48 #endif
49
50 /* Macro to see if the paths match.  */
51 #define IS_SAME_PATH(a,b) (FILENAME_CMP (a, b) == 0)
52
53 /* Suffix for aux-info files.  */
54 #ifdef __MSDOS__
55 #define AUX_INFO_SUFFIX "X"
56 #else
57 #define AUX_INFO_SUFFIX ".X"
58 #endif
59
60 /* Suffix for saved files.  */
61 #ifdef __MSDOS__
62 #define SAVE_SUFFIX "sav"
63 #else
64 #define SAVE_SUFFIX ".save"
65 #endif
66
67 /* Suffix for renamed C++ files.  */
68 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
69 #define CPLUS_FILE_SUFFIX "cc"
70 #else
71 #define CPLUS_FILE_SUFFIX "C"
72 #endif
73
74 static void usage (void) ATTRIBUTE_NORETURN;
75 static void aux_info_corrupted (void) ATTRIBUTE_NORETURN;
76 static void declare_source_confusing (const char *) ATTRIBUTE_NORETURN;
77 static const char *shortpath (const char *, const char *);
78 extern void fancy_abort  (void) ATTRIBUTE_NORETURN;
79 static void notice (const char *, ...) ATTRIBUTE_PRINTF_1;
80 static char *savestring (const char *, unsigned int);
81 static char *dupnstr (const char *, size_t);
82 static const char *substr (const char *, const char * const);
83 static int safe_read (int, void *, int);
84 static void safe_write (int, void *, int, const char *);
85 static void save_pointers (void);
86 static void restore_pointers (void);
87 static int is_id_char (int);
88 static int in_system_include_dir (const char *);
89 static int directory_specified_p (const char *);
90 static int file_excluded_p (const char *);
91 static char *unexpand_if_needed (const char *);
92 static char *abspath (const char *, const char *);
93 static void check_aux_info (int);
94 static const char *find_corresponding_lparen (const char *);
95 static int referenced_file_is_newer (const char *, time_t);
96 static void save_def_or_dec (const char *, int);
97 static void munge_compile_params (const char *);
98 static int gen_aux_info_file (const char *);
99 static void process_aux_info_file (const char *, int, int);
100 static int identify_lineno (const char *);
101 static void check_source (int, const char *);
102 static const char *seek_to_line (int);
103 static const char *forward_to_next_token_char (const char *);
104 static void output_bytes (const char *, size_t);
105 static void output_string (const char *);
106 static void output_up_to (const char *);
107 static int other_variable_style_function (const char *);
108 static const char *find_rightmost_formals_list (const char *);
109 static void do_cleaning (char *, const char *);
110 static const char *careful_find_l_paren (const char *);
111 static void do_processing (void);
112
113 /* Look for these where the `const' qualifier is intentionally cast aside.  */
114 #define NONCONST
115
116 /* Define a default place to find the SYSCALLS.X file.  */
117
118 #ifndef UNPROTOIZE
119
120 #ifndef STANDARD_EXEC_PREFIX
121 #define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-lib/"
122 #endif /* !defined STANDARD_EXEC_PREFIX */
123
124 static const char * const standard_exec_prefix = STANDARD_EXEC_PREFIX;
125 static const char * const target_machine = DEFAULT_TARGET_MACHINE;
126 static const char * const target_version = DEFAULT_TARGET_VERSION;
127
128 #endif /* !defined (UNPROTOIZE) */
129
130 /* Suffix of aux_info files.  */
131
132 static const char * const aux_info_suffix = AUX_INFO_SUFFIX;
133
134 /* String to attach to filenames for saved versions of original files.  */
135
136 static const char * const save_suffix = SAVE_SUFFIX;
137
138 #ifndef UNPROTOIZE
139
140 /* String to attach to C filenames renamed to C++.  */
141
142 static const char * const cplus_suffix = CPLUS_FILE_SUFFIX;
143
144 /* File name of the file which contains descriptions of standard system
145    routines.  Note that we never actually do anything with this file per se,
146    but we do read in its corresponding aux_info file.  */
147
148 static const char syscalls_filename[] = "SYSCALLS.c";
149
150 /* Default place to find the above file.  */
151
152 static const char * default_syscalls_dir;
153
154 /* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
155    file.  */
156
157 static char * syscalls_absolute_filename;
158
159 #endif /* !defined (UNPROTOIZE) */
160
161 /* Type of the structure that holds information about macro unexpansions.  */
162
163 struct unexpansion_struct {
164   const char *const expanded;
165   const char *const contracted;
166 };
167 typedef struct unexpansion_struct unexpansion;
168
169 /* A table of conversions that may need to be made for some (stupid) older
170    operating systems where these types are preprocessor macros rather than
171    typedefs (as they really ought to be).
172
173    WARNING: The contracted forms must be as small (or smaller) as the
174    expanded forms, or else havoc will ensue.  */
175
176 static const unexpansion unexpansions[] = {
177   { "struct _iobuf", "FILE" },
178   { 0, 0 }
179 };
180
181 /* The number of "primary" slots in the hash tables for filenames and for
182    function names.  This can be as big or as small as you like, except that
183    it must be a power of two.  */
184
185 #define HASH_TABLE_SIZE         (1 << 9)
186
187 /* Bit mask to use when computing hash values.  */
188
189 static const int hash_mask = (HASH_TABLE_SIZE - 1);
190
191
192 /* Datatype for lists of directories or filenames.  */
193 struct string_list
194 {
195   const char *name;
196   struct string_list *next;
197 };
198
199 static struct string_list *string_list_cons (const char *,
200                                              struct string_list *);
201
202 /* List of directories in which files should be converted.  */
203
204 struct string_list *directory_list;
205
206 /* List of file names which should not be converted.
207    A file is excluded if the end of its name, following a /,
208    matches one of the names in this list.  */
209
210 struct string_list *exclude_list;
211
212 /* The name of the other style of variable-number-of-parameters functions
213    (i.e. the style that we want to leave unconverted because we don't yet
214    know how to convert them to this style.  This string is used in warning
215    messages.  */
216
217 /* Also define here the string that we can search for in the parameter lists
218    taken from the .X files which will unambiguously indicate that we have
219    found a varargs style function.  */
220
221 #ifdef UNPROTOIZE
222 static const char * const other_var_style = "stdarg";
223 #else /* !defined (UNPROTOIZE) */
224 static const char * const other_var_style = "varargs";
225 static const char *varargs_style_indicator = "va_alist";
226 #endif /* !defined (UNPROTOIZE) */
227
228 /* The following two types are used to create hash tables.  In this program,
229    there are two hash tables which are used to store and quickly lookup two
230    different classes of strings.  The first type of strings stored in the
231    first hash table are absolute filenames of files which protoize needs to
232    know about.  The second type of strings (stored in the second hash table)
233    are function names.  It is this second class of strings which really
234    inspired the use of the hash tables, because there may be a lot of them.  */
235
236 typedef struct hash_table_entry_struct hash_table_entry;
237
238 /* Do some typedefs so that we don't have to write "struct" so often.  */
239
240 typedef struct def_dec_info_struct def_dec_info;
241 typedef struct file_info_struct file_info;
242 typedef struct f_list_chain_item_struct f_list_chain_item;
243
244 #ifndef UNPROTOIZE
245 static int is_syscalls_file (const file_info *);
246 static void rename_c_file (const hash_table_entry *);
247 static const def_dec_info *find_extern_def (const def_dec_info *,
248                                             const def_dec_info *);
249 static const def_dec_info *find_static_definition (const def_dec_info *);
250 static void connect_defs_and_decs (const hash_table_entry *);
251 static void add_local_decl (const def_dec_info *, const char *);
252 static void add_global_decls (const file_info *, const char *);
253 #endif /* ! UNPROTOIZE */
254 static int needs_to_be_converted (const file_info *);
255 static void visit_each_hash_node (const hash_table_entry *,
256                                   void (*)(const hash_table_entry *));
257 static hash_table_entry *add_symbol (hash_table_entry *, const char *);
258 static hash_table_entry *lookup (hash_table_entry *, const char *);
259 static void free_def_dec (def_dec_info *);
260 static file_info *find_file (const char *, int);
261 static void reverse_def_dec_list (const hash_table_entry *);
262 static void edit_fn_declaration (const def_dec_info *, const char *);
263 static int edit_formals_lists (const char *, unsigned int,
264                                const def_dec_info *);
265 static void edit_fn_definition (const def_dec_info *, const char *);
266 static void scan_for_missed_items (const file_info *);
267 static void edit_file (const hash_table_entry *);
268
269 /* In the struct below, note that the "_info" field has two different uses
270    depending on the type of hash table we are in (i.e. either the filenames
271    hash table or the function names hash table).  In the filenames hash table
272    the info fields of the entries point to the file_info struct which is
273    associated with each filename (1 per filename).  In the function names
274    hash table, the info field points to the head of a singly linked list of
275    def_dec_info entries which are all defs or decs of the function whose
276    name is pointed to by the "symbol" field.  Keeping all of the defs/decs
277    for a given function name on a special list specifically for that function
278    name makes it quick and easy to find out all of the important information
279    about a given (named) function.  */
280
281 struct hash_table_entry_struct {
282   hash_table_entry *            hash_next;      /* -> to secondary entries */
283   const char *                  symbol;         /* -> to the hashed string */
284   union {
285     const def_dec_info *        _ddip;
286     file_info *                 _fip;
287   } _info;
288 };
289 #define ddip _info._ddip
290 #define fip _info._fip
291
292 /* Define a type specifically for our two hash tables.  */
293
294 typedef hash_table_entry hash_table[HASH_TABLE_SIZE];
295
296 /* The following struct holds all of the important information about any
297    single filename (e.g. file) which we need to know about.  */
298
299 struct file_info_struct {
300   const hash_table_entry *      hash_entry; /* -> to associated hash entry */
301   const def_dec_info *          defs_decs;  /* -> to chain of defs/decs */
302   time_t                        mtime;      /* Time of last modification.  */
303 };
304
305 /* Due to the possibility that functions may return pointers to functions,
306    (which may themselves have their own parameter lists) and due to the
307    fact that returned pointers-to-functions may be of type "pointer-to-
308    function-returning-pointer-to-function" (ad nauseum) we have to keep
309    an entire chain of ANSI style formal parameter lists for each function.
310
311    Normally, for any given function, there will only be one formals list
312    on the chain, but you never know.
313
314    Note that the head of each chain of formals lists is pointed to by the
315    `f_list_chain' field of the corresponding def_dec_info record.
316
317    For any given chain, the item at the head of the chain is the *leftmost*
318    parameter list seen in the actual C language function declaration.  If
319    there are other members of the chain, then these are linked in left-to-right
320    order from the head of the chain.  */
321
322 struct f_list_chain_item_struct {
323   const f_list_chain_item *     chain_next;     /* -> to next item on chain */
324   const char *                  formals_list;   /* -> to formals list string */
325 };
326
327 /* The following struct holds all of the important information about any
328    single function definition or declaration which we need to know about.
329    Note that for unprotoize we don't need to know very much because we
330    never even create records for stuff that we don't intend to convert
331    (like for instance defs and decs which are already in old K&R format
332    and "implicit" function declarations).  */
333
334 struct def_dec_info_struct {
335   const def_dec_info *  next_in_file;   /* -> to rest of chain for file */
336   file_info *           file;           /* -> file_info for containing file */
337   int                   line;           /* source line number of def/dec */
338   const char *          ansi_decl;      /* -> left end of ansi decl */
339   hash_table_entry *    hash_entry;     /* -> hash entry for function name */
340   unsigned int          is_func_def;    /* = 0 means this is a declaration */
341   const def_dec_info *  next_for_func;  /* -> to rest of chain for func name */
342   unsigned int          f_list_count;   /* count of formals lists we expect */
343   char                  prototyped;     /* = 0 means already prototyped */
344 #ifndef UNPROTOIZE
345   const f_list_chain_item * f_list_chain;       /* -> chain of formals lists */
346   const def_dec_info *  definition;     /* -> def/dec containing related def */
347   char                  is_static;      /* = 0 means visibility is "extern"  */
348   char                  is_implicit;    /* != 0 for implicit func decl's */
349   char                  written;        /* != 0 means written for implicit */
350 #else /* !defined (UNPROTOIZE) */
351   const char *          formal_names;   /* -> to list of names of formals */
352   const char *          formal_decls;   /* -> to string of formal declarations */
353 #endif /* !defined (UNPROTOIZE) */
354 };
355
356 /* Pointer to the tail component of the filename by which this program was
357    invoked.  Used everywhere in error and warning messages.  */
358
359 static const char *pname;
360
361 /* Error counter.  Will be nonzero if we should give up at the next convenient
362    stopping point.  */
363
364 static int errors = 0;
365
366 /* Option flags.  */
367 /* ??? These comments should say what the flag mean as well as the options
368    that set them.  */
369
370 /* File name to use for running gcc.  Allows GCC 2 to be named
371    something other than gcc.  */
372 static const char *compiler_file_name = "gcc";
373
374 static int version_flag = 0;            /* Print our version number.  */
375 static int quiet_flag = 0;              /* Don't print messages normally.  */
376 static int nochange_flag = 0;           /* Don't convert, just say what files
377                                            we would have converted.  */
378 static int nosave_flag = 0;             /* Don't save the old version.  */
379 static int keep_flag = 0;               /* Don't delete the .X files.  */
380 static const char ** compile_params = 0;        /* Option string for gcc.  */
381 #ifdef UNPROTOIZE
382 static const char *indent_string = "     ";     /* Indentation for newly
383                                                    inserted parm decls.  */
384 #else /* !defined (UNPROTOIZE) */
385 static int local_flag = 0;              /* Insert new local decls (when?).  */
386 static int global_flag = 0;             /* set by -g option */
387 static int cplusplus_flag = 0;          /* Rename converted files to *.C.  */
388 static const char *nondefault_syscalls_dir = 0; /* Dir to look for
389                                                    SYSCALLS.c.X in.  */
390 #endif /* !defined (UNPROTOIZE) */
391
392 /* An index into the compile_params array where we should insert the source
393    file name when we are ready to exec the C compiler.  A zero value indicates
394    that we have not yet called munge_compile_params.  */
395
396 static int input_file_name_index = 0;
397
398 /* An index into the compile_params array where we should insert the filename
399    for the aux info file, when we run the C compiler.  */
400 static int aux_info_file_name_index = 0;
401
402 /* Count of command line arguments which were "filename" arguments.  */
403
404 static int n_base_source_files = 0;
405
406 /* Points to a malloc'ed list of pointers to all of the filenames of base
407    source files which were specified on the command line.  */
408
409 static const char **base_source_filenames;
410
411 /* Line number of the line within the current aux_info file that we
412    are currently processing.  Used for error messages in case the prototypes
413    info file is corrupted somehow.  */
414
415 static int current_aux_info_lineno;
416
417 /* Pointer to the name of the source file currently being converted.  */
418
419 static const char *convert_filename;
420
421 /* Pointer to relative root string (taken from aux_info file) which indicates
422    where directory the user was in when he did the compilation step that
423    produced the containing aux_info file.  */
424
425 static const char *invocation_filename;
426
427 /* Pointer to the base of the input buffer that holds the original text for the
428    source file currently being converted.  */
429
430 static const char *orig_text_base;
431
432 /* Pointer to the byte just beyond the end of the input buffer that holds the
433    original text for the source file currently being converted.  */
434
435 static const char *orig_text_limit;
436
437 /* Pointer to the base of the input buffer that holds the cleaned text for the
438    source file currently being converted.  */
439
440 static const char *clean_text_base;
441
442 /* Pointer to the byte just beyond the end of the input buffer that holds the
443    cleaned text for the source file currently being converted.  */
444
445 static const char *clean_text_limit;
446
447 /* Pointer to the last byte in the cleaned text buffer that we have already
448    (virtually) copied to the output buffer (or decided to ignore).  */
449
450 static const char * clean_read_ptr;
451
452 /* Pointer to the base of the output buffer that holds the replacement text
453    for the source file currently being converted.  */
454
455 static char *repl_text_base;
456
457 /* Pointer to the byte just beyond the end of the output buffer that holds the
458    replacement text for the source file currently being converted.  */
459
460 static char *repl_text_limit;
461
462 /* Pointer to the last byte which has been stored into the output buffer.
463    The next byte to be stored should be stored just past where this points
464    to.  */
465
466 static char * repl_write_ptr;
467
468 /* Pointer into the cleaned text buffer for the source file we are currently
469    converting.  This points to the first character of the line that we last
470    did a "seek_to_line" to (see below).  */
471
472 static const char *last_known_line_start;
473
474 /* Number of the line (in the cleaned text buffer) that we last did a
475    "seek_to_line" to.  Will be one if we just read a new source file
476    into the cleaned text buffer.  */
477
478 static int last_known_line_number;
479
480 /* The filenames hash table.  */
481
482 static hash_table filename_primary;
483
484 /* The function names hash table.  */
485
486 static hash_table function_name_primary;
487
488 /* The place to keep the recovery address which is used only in cases where
489    we get hopelessly confused by something in the cleaned original text.  */
490
491 static jmp_buf source_confusion_recovery;
492
493 /* A pointer to the current directory filename (used by abspath).  */
494
495 static char *cwd_buffer;
496
497 /* A place to save the read pointer until we are sure that an individual
498    attempt at editing will succeed.  */
499
500 static const char * saved_clean_read_ptr;
501
502 /* A place to save the write pointer until we are sure that an individual
503    attempt at editing will succeed.  */
504
505 static char * saved_repl_write_ptr;
506 \f
507 /* Translate and output an error message.  */
508 static void
509 notice (const char *msgid, ...)
510 {
511   va_list ap;
512   
513   va_start (ap, msgid);
514   vfprintf (stderr, _(msgid), ap);
515   va_end (ap);
516 }
517
518 \f
519 /* Make a copy of a string INPUT with size SIZE.  */
520
521 static char *
522 savestring (const char *input, unsigned int size)
523 {
524   char *output = xmalloc (size + 1);
525   strcpy (output, input);
526   return output;
527 }
528
529 /* More 'friendly' abort that prints the line and file.
530    config.h can #define abort fancy_abort if you like that sort of thing.  */
531
532 void
533 fancy_abort (void)
534 {
535   notice ("%s: internal abort\n", pname);
536   exit (FATAL_EXIT_CODE);
537 }
538 \f
539 /* Make a duplicate of the first N bytes of a given string in a newly
540    allocated area.  */
541
542 static char *
543 dupnstr (const char *s, size_t n)
544 {
545   char *ret_val = xmalloc (n + 1);
546
547   strncpy (ret_val, s, n);
548   ret_val[n] = '\0';
549   return ret_val;
550 }
551
552 /* Return a pointer to the first occurrence of s2 within s1 or NULL if s2
553    does not occur within s1.  Assume neither s1 nor s2 are null pointers.  */
554
555 static const char *
556 substr (const char *s1, const char *const s2)
557 {
558   for (; *s1 ; s1++)
559     {
560       const char *p1;
561       const char *p2;
562       int c;
563
564       for (p1 = s1, p2 = s2; (c = *p2); p1++, p2++)
565         if (*p1 != c)
566           goto outer;
567       return s1;
568 outer:
569       ;
570     }
571   return 0;
572 }
573 \f
574 /* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
575    retrying if necessary.  Return the actual number of bytes read.  */
576
577 static int
578 safe_read (int desc, void *ptr, int len)
579 {
580   int left = len;
581   while (left > 0) {
582     int nchars = read (desc, ptr, left);
583     if (nchars < 0)
584       {
585 #ifdef EINTR
586         if (errno == EINTR)
587           continue;
588 #endif
589         return nchars;
590       }
591     if (nchars == 0)
592       break;
593     /* Arithmetic on void pointers is a gcc extension.  */
594     ptr = (char *) ptr + nchars;
595     left -= nchars;
596   }
597   return len - left;
598 }
599
600 /* Write LEN bytes at PTR to descriptor DESC,
601    retrying if necessary, and treating any real error as fatal.  */
602
603 static void
604 safe_write (int desc, void *ptr, int len, const char *out_fname)
605 {
606   while (len > 0) {
607     int written = write (desc, ptr, len);
608     if (written < 0)
609       {
610         int errno_val = errno;
611 #ifdef EINTR
612         if (errno_val == EINTR)
613           continue;
614 #endif
615         notice ("%s: error writing file `%s': %s\n",
616                 pname, shortpath (NULL, out_fname), xstrerror (errno_val));
617         return;
618       }
619     /* Arithmetic on void pointers is a gcc extension.  */
620     ptr = (char *) ptr + written;
621     len -= written;
622   }
623 }
624 \f
625 /* Get setup to recover in case the edit we are about to do goes awry.  */
626
627 static void
628 save_pointers (void)
629 {
630   saved_clean_read_ptr = clean_read_ptr;
631   saved_repl_write_ptr = repl_write_ptr;
632 }
633
634 /* Call this routine to recover our previous state whenever something looks
635    too confusing in the source code we are trying to edit.  */
636
637 static void
638 restore_pointers (void)
639 {
640   clean_read_ptr = saved_clean_read_ptr;
641   repl_write_ptr = saved_repl_write_ptr;
642 }
643
644 /* Return true if the given character is a valid identifier character.  */
645
646 static int
647 is_id_char (int ch)
648 {
649   return (ISIDNUM (ch) || (ch == '$'));
650 }
651
652 /* Give a message indicating the proper way to invoke this program and then
653    exit with nonzero status.  */
654
655 static void
656 usage (void)
657 {
658 #ifdef UNPROTOIZE
659   notice ("%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
660           pname, pname);
661 #else /* !defined (UNPROTOIZE) */
662   notice ("%s: usage '%s [ -VqfnkNlgC ] [ -B <dirname> ] [ filename ... ]'\n",
663           pname, pname);
664 #endif /* !defined (UNPROTOIZE) */
665   exit (FATAL_EXIT_CODE);
666 }
667
668 /* Return true if the given filename (assumed to be an absolute filename)
669    designates a file residing anywhere beneath any one of the "system"
670    include directories.  */
671
672 static int
673 in_system_include_dir (const char *path)
674 {
675   const struct default_include *p;
676
677   if (! IS_ABSOLUTE_PATH (path))
678     abort ();           /* Must be an absolutized filename.  */
679
680   for (p = cpp_include_defaults; p->fname; p++)
681     if (!strncmp (path, p->fname, strlen (p->fname))
682         && IS_DIR_SEPARATOR (path[strlen (p->fname)]))
683       return 1;
684   return 0;
685 }
686 \f
687 #if 0
688 /* Return true if the given filename designates a file that the user has
689    read access to and for which the user has write access to the containing
690    directory.  */
691
692 static int
693 file_could_be_converted (const char *path)
694 {
695   char *const dir_name = alloca (strlen (path) + 1);
696
697   if (access (path, R_OK))
698     return 0;
699
700   {
701     char *dir_last_slash;
702
703     strcpy (dir_name, path);
704     dir_last_slash = strrchr (dir_name, DIR_SEPARATOR);
705 #ifdef DIR_SEPARATOR_2
706     {
707       char *slash;
708
709       slash = strrchr (dir_last_slash ? dir_last_slash : dir_name,
710                        DIR_SEPARATOR_2);
711       if (slash)
712         dir_last_slash = slash;
713     }
714 #endif
715     if (dir_last_slash)
716       *dir_last_slash = '\0';
717     else
718       abort ();  /* Should have been an absolutized filename.  */
719   }
720
721   if (access (path, W_OK))
722     return 0;
723
724   return 1;
725 }
726
727 /* Return true if the given filename designates a file that we are allowed
728    to modify.  Files which we should not attempt to modify are (a) "system"
729    include files, and (b) files which the user doesn't have write access to,
730    and (c) files which reside in directories which the user doesn't have
731    write access to.  Unless requested to be quiet, give warnings about
732    files that we will not try to convert for one reason or another.  An
733    exception is made for "system" include files, which we never try to
734    convert and for which we don't issue the usual warnings.  */
735
736 static int
737 file_normally_convertible (const char *path)
738 {
739   char *const dir_name = alloca (strlen (path) + 1);
740
741   if (in_system_include_dir (path))
742     return 0;
743
744   {
745     char *dir_last_slash;
746
747     strcpy (dir_name, path);
748     dir_last_slash = strrchr (dir_name, DIR_SEPARATOR);
749 #ifdef DIR_SEPARATOR_2
750     {
751       char *slash;
752
753       slash = strrchr (dir_last_slash ? dir_last_slash : dir_name,
754                        DIR_SEPARATOR_2);
755       if (slash)
756         dir_last_slash = slash;
757     }
758 #endif
759     if (dir_last_slash)
760       *dir_last_slash = '\0';
761     else
762       abort ();  /* Should have been an absolutized filename.  */
763   }
764
765   if (access (path, R_OK))
766     {
767       if (!quiet_flag)
768         notice ("%s: warning: no read access for file `%s'\n",
769                 pname, shortpath (NULL, path));
770       return 0;
771     }
772
773   if (access (path, W_OK))
774     {
775       if (!quiet_flag)
776         notice ("%s: warning: no write access for file `%s'\n",
777                 pname, shortpath (NULL, path));
778       return 0;
779     }
780
781   if (access (dir_name, W_OK))
782     {
783       if (!quiet_flag)
784         notice ("%s: warning: no write access for dir containing `%s'\n",
785                 pname, shortpath (NULL, path));
786       return 0;
787     }
788
789   return 1;
790 }
791 #endif /* 0 */
792 \f
793 #ifndef UNPROTOIZE
794
795 /* Return true if the given file_info struct refers to the special SYSCALLS.c.X
796    file.  Return false otherwise.  */
797
798 static int
799 is_syscalls_file (const file_info *fi_p)
800 {
801   char const *f = fi_p->hash_entry->symbol;
802   size_t fl = strlen (f), sysl = sizeof (syscalls_filename) - 1;
803   return sysl <= fl  &&  strcmp (f + fl - sysl, syscalls_filename) == 0;
804 }
805
806 #endif /* !defined (UNPROTOIZE) */
807
808 /* Check to see if this file will need to have anything done to it on this
809    run.  If there is nothing in the given file which both needs conversion
810    and for which we have the necessary stuff to do the conversion, return
811    false.  Otherwise, return true.
812
813    Note that (for protoize) it is only valid to call this function *after*
814    the connections between declarations and definitions have all been made
815    by connect_defs_and_decs.  */
816
817 static int
818 needs_to_be_converted (const file_info *file_p)
819 {
820   const def_dec_info *ddp;
821
822 #ifndef UNPROTOIZE
823
824   if (is_syscalls_file (file_p))
825     return 0;
826
827 #endif /* !defined (UNPROTOIZE) */
828
829   for (ddp = file_p->defs_decs; ddp; ddp = ddp->next_in_file)
830
831     if (
832
833 #ifndef UNPROTOIZE
834
835       /* ... and if we a protoizing and this function is in old style ...  */
836       !ddp->prototyped
837       /* ... and if this a definition or is a decl with an associated def ...  */
838       && (ddp->is_func_def || (!ddp->is_func_def && ddp->definition))
839
840 #else /* defined (UNPROTOIZE) */
841
842       /* ... and if we are unprotoizing and this function is in new style ...  */
843       ddp->prototyped
844
845 #endif /* defined (UNPROTOIZE) */
846       )
847           /* ... then the containing file needs converting.  */
848           return -1;
849   return 0;
850 }
851
852 /* Return 1 if the file name NAME is in a directory
853    that should be converted.  */
854
855 static int
856 directory_specified_p (const char *name)
857 {
858   struct string_list *p;
859
860   for (p = directory_list; p; p = p->next)
861     if (!strncmp (name, p->name, strlen (p->name))
862         && IS_DIR_SEPARATOR (name[strlen (p->name)]))
863       {
864         const char *q = name + strlen (p->name) + 1;
865
866         /* If there are more slashes, it's in a subdir, so
867            this match doesn't count.  */
868         while (*q++)
869           if (IS_DIR_SEPARATOR (*(q-1)))
870             goto lose;
871         return 1;
872
873       lose: ;
874       }
875
876   return 0;
877 }
878
879 /* Return 1 if the file named NAME should be excluded from conversion.  */
880
881 static int
882 file_excluded_p (const char *name)
883 {
884   struct string_list *p;
885   int len = strlen (name);
886
887   for (p = exclude_list; p; p = p->next)
888     if (!strcmp (name + len - strlen (p->name), p->name)
889         && IS_DIR_SEPARATOR (name[len - strlen (p->name) - 1]))
890       return 1;
891
892   return 0;
893 }
894
895 /* Construct a new element of a string_list.
896    STRING is the new element value, and REST holds the remaining elements.  */
897
898 static struct string_list *
899 string_list_cons (const char *string, struct string_list *rest)
900 {
901   struct string_list *temp = xmalloc (sizeof (struct string_list));
902
903   temp->next = rest;
904   temp->name = string;
905   return temp;
906 }
907 \f
908 /* ??? The GNU convention for mentioning function args in its comments
909    is to capitalize them.  So change "hash_tab_p" to HASH_TAB_P below.
910    Likewise for all the other functions.  */
911
912 /* Given a hash table, apply some function to each node in the table. The
913    table to traverse is given as the "hash_tab_p" argument, and the
914    function to be applied to each node in the table is given as "func"
915    argument.  */
916
917 static void
918 visit_each_hash_node (const hash_table_entry *hash_tab_p,
919                       void (*func) (const hash_table_entry *))
920 {
921   const hash_table_entry *primary;
922
923   for (primary = hash_tab_p; primary < &hash_tab_p[HASH_TABLE_SIZE]; primary++)
924     if (primary->symbol)
925       {
926         hash_table_entry *second;
927
928         (*func)(primary);
929         for (second = primary->hash_next; second; second = second->hash_next)
930           (*func) (second);
931       }
932 }
933
934 /* Initialize all of the fields of a new hash table entry, pointed
935    to by the "p" parameter.  Note that the space to hold the entry
936    is assumed to have already been allocated before this routine is
937    called.  */
938
939 static hash_table_entry *
940 add_symbol (hash_table_entry *p, const char *s)
941 {
942   p->hash_next = NULL;
943   p->symbol = xstrdup (s);
944   p->ddip = NULL;
945   p->fip = NULL;
946   return p;
947 }
948
949 /* Look for a particular function name or filename in the particular
950    hash table indicated by "hash_tab_p".  If the name is not in the
951    given hash table, add it.  Either way, return a pointer to the
952    hash table entry for the given name.  */
953
954 static hash_table_entry *
955 lookup (hash_table_entry *hash_tab_p, const char *search_symbol)
956 {
957   int hash_value = 0;
958   const char *search_symbol_char_p = search_symbol;
959   hash_table_entry *p;
960
961   while (*search_symbol_char_p)
962     hash_value += *search_symbol_char_p++;
963   hash_value &= hash_mask;
964   p = &hash_tab_p[hash_value];
965   if (! p->symbol)
966       return add_symbol (p, search_symbol);
967   if (!strcmp (p->symbol, search_symbol))
968     return p;
969   while (p->hash_next)
970     {
971       p = p->hash_next;
972       if (!strcmp (p->symbol, search_symbol))
973         return p;
974     }
975   p->hash_next = xmalloc (sizeof (hash_table_entry));
976   p = p->hash_next;
977   return add_symbol (p, search_symbol);
978 }
979 \f
980 /* Throw a def/dec record on the junk heap.
981
982    Also, since we are not using this record anymore, free up all of the
983    stuff it pointed to.  */
984
985 static void
986 free_def_dec (def_dec_info *p)
987 {
988   free ((NONCONST void *) p->ansi_decl);
989
990 #ifndef UNPROTOIZE
991   {
992     const f_list_chain_item * curr;
993     const f_list_chain_item * next;
994
995     for (curr = p->f_list_chain; curr; curr = next)
996       {
997         next = curr->chain_next;
998         free ((NONCONST void *) curr);
999       }
1000   }
1001 #endif /* !defined (UNPROTOIZE) */
1002
1003   free (p);
1004 }
1005
1006 /* Unexpand as many macro symbol as we can find.
1007
1008    If the given line must be unexpanded, make a copy of it in the heap and
1009    return a pointer to the unexpanded copy.  Otherwise return NULL.  */
1010
1011 static char *
1012 unexpand_if_needed (const char *aux_info_line)
1013 {
1014   static char *line_buf = 0;
1015   static int line_buf_size = 0;
1016   const unexpansion *unexp_p;
1017   int got_unexpanded = 0;
1018   const char *s;
1019   char *copy_p = line_buf;
1020
1021   if (line_buf == 0)
1022     {
1023       line_buf_size = 1024;
1024       line_buf = xmalloc (line_buf_size);
1025     }
1026
1027   copy_p = line_buf;
1028
1029   /* Make a copy of the input string in line_buf, expanding as necessary.  */
1030
1031   for (s = aux_info_line; *s != '\n'; )
1032     {
1033       for (unexp_p = unexpansions; unexp_p->expanded; unexp_p++)
1034         {
1035           const char *in_p = unexp_p->expanded;
1036           size_t len = strlen (in_p);
1037
1038           if (*s == *in_p && !strncmp (s, in_p, len) && !is_id_char (s[len]))
1039             {
1040               int size = strlen (unexp_p->contracted);
1041               got_unexpanded = 1;
1042               if (copy_p + size - line_buf >= line_buf_size)
1043                 {
1044                   int offset = copy_p - line_buf;
1045                   line_buf_size *= 2;
1046                   line_buf_size += size;
1047                   line_buf = xrealloc (line_buf, line_buf_size);
1048                   copy_p = line_buf + offset;
1049                 }
1050               strcpy (copy_p, unexp_p->contracted);
1051               copy_p += size;
1052
1053               /* Assume that there will not be another replacement required
1054                  within the text just replaced.  */
1055
1056               s += len;
1057               goto continue_outer;
1058             }
1059         }
1060       if (copy_p - line_buf == line_buf_size)
1061         {
1062           int offset = copy_p - line_buf;
1063           line_buf_size *= 2;
1064           line_buf = xrealloc (line_buf, line_buf_size);
1065           copy_p = line_buf + offset;
1066         }
1067       *copy_p++ = *s++;
1068 continue_outer: ;
1069     }
1070   if (copy_p + 2 - line_buf >= line_buf_size)
1071     {
1072       int offset = copy_p - line_buf;
1073       line_buf_size *= 2;
1074       line_buf = xrealloc (line_buf, line_buf_size);
1075       copy_p = line_buf + offset;
1076     }
1077   *copy_p++ = '\n';
1078   *copy_p = '\0';
1079
1080   return (got_unexpanded ? savestring (line_buf, copy_p - line_buf) : 0);
1081 }
1082 \f
1083 /* Return the absolutized filename for the given relative
1084    filename.  Note that if that filename is already absolute, it may
1085    still be returned in a modified form because this routine also
1086    eliminates redundant slashes and single dots and eliminates double
1087    dots to get a shortest possible filename from the given input
1088    filename.  The absolutization of relative filenames is made by
1089    assuming that the given filename is to be taken as relative to
1090    the first argument (cwd) or to the current directory if cwd is
1091    NULL.  */
1092
1093 static char *
1094 abspath (const char *cwd, const char *rel_filename)
1095 {
1096   /* Setup the current working directory as needed.  */
1097   const char *const cwd2 = (cwd) ? cwd : cwd_buffer;
1098   char *const abs_buffer = alloca (strlen (cwd2) + strlen (rel_filename) + 2);
1099   char *endp = abs_buffer;
1100   char *outp, *inp;
1101
1102   /* Copy the  filename (possibly preceded by the current working
1103      directory name) into the absolutization buffer.  */
1104
1105   {
1106     const char *src_p;
1107
1108     if (! IS_ABSOLUTE_PATH (rel_filename))
1109       {
1110         src_p = cwd2;
1111         while ((*endp++ = *src_p++))
1112           continue;
1113         *(endp-1) = DIR_SEPARATOR;              /* overwrite null */
1114       }
1115 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1116     else if (IS_DIR_SEPARATOR (rel_filename[0]))
1117       {
1118         /* A path starting with a directory separator is considered absolute
1119            for dos based filesystems, but it's really not -- it's just the
1120            convention used throughout GCC and it works. However, in this
1121            case, we still need to prepend the drive spec from cwd_buffer.  */
1122         *endp++ = cwd2[0];
1123         *endp++ = cwd2[1];
1124       }
1125 #endif
1126     src_p = rel_filename;
1127     while ((*endp++ = *src_p++))
1128       continue;
1129   }
1130
1131   /* Now make a copy of abs_buffer into abs_buffer, shortening the
1132      filename (by taking out slashes and dots) as we go.  */
1133
1134   outp = inp = abs_buffer;
1135   *outp++ = *inp++;             /* copy first slash */
1136 #if defined (apollo) || defined (_WIN32) || defined (__INTERIX)
1137   if (IS_DIR_SEPARATOR (inp[0]))
1138     *outp++ = *inp++;           /* copy second slash */
1139 #endif
1140   for (;;)
1141     {
1142       if (!inp[0])
1143         break;
1144       else if (IS_DIR_SEPARATOR (inp[0]) && IS_DIR_SEPARATOR (outp[-1]))
1145         {
1146           inp++;
1147           continue;
1148         }
1149       else if (inp[0] == '.' && IS_DIR_SEPARATOR (outp[-1]))
1150         {
1151           if (!inp[1])
1152             break;
1153           else if (IS_DIR_SEPARATOR (inp[1]))
1154             {
1155               inp += 2;
1156               continue;
1157             }
1158           else if ((inp[1] == '.') && (inp[2] == 0
1159                                        || IS_DIR_SEPARATOR (inp[2])))
1160             {
1161               inp += (IS_DIR_SEPARATOR (inp[2])) ? 3 : 2;
1162               outp -= 2;
1163               while (outp >= abs_buffer && ! IS_DIR_SEPARATOR (*outp))
1164                 outp--;
1165               if (outp < abs_buffer)
1166                 {
1167                   /* Catch cases like /.. where we try to backup to a
1168                      point above the absolute root of the logical file
1169                      system.  */
1170
1171                   notice ("%s: invalid file name: %s\n",
1172                           pname, rel_filename);
1173                   exit (FATAL_EXIT_CODE);
1174                 }
1175               *++outp = '\0';
1176               continue;
1177             }
1178         }
1179       *outp++ = *inp++;
1180     }
1181
1182   /* On exit, make sure that there is a trailing null, and make sure that
1183      the last character of the returned string is *not* a slash.  */
1184
1185   *outp = '\0';
1186   if (IS_DIR_SEPARATOR (outp[-1]))
1187     *--outp  = '\0';
1188
1189   /* Make a copy (in the heap) of the stuff left in the absolutization
1190      buffer and return a pointer to the copy.  */
1191
1192   return savestring (abs_buffer, outp - abs_buffer);
1193 }
1194 \f
1195 /* Given a filename (and possibly a directory name from which the filename
1196    is relative) return a string which is the shortest possible
1197    equivalent for the corresponding full (absolutized) filename.  The
1198    shortest possible equivalent may be constructed by converting the
1199    absolutized filename to be a relative filename (i.e. relative to
1200    the actual current working directory).  However if a relative filename
1201    is longer, then the full absolute filename is returned.
1202
1203    KNOWN BUG:
1204
1205    Note that "simple-minded" conversion of any given type of filename (either
1206    relative or absolute) may not result in a valid equivalent filename if any
1207    subpart of the original filename is actually a symbolic link.  */
1208
1209 static const char *
1210 shortpath (const char *cwd, const char *filename)
1211 {
1212   char *rel_buffer;
1213   char *rel_buf_p;
1214   char *cwd_p = cwd_buffer;
1215   char *path_p;
1216   int unmatched_slash_count = 0;
1217   size_t filename_len = strlen (filename);
1218
1219   path_p = abspath (cwd, filename);
1220   rel_buf_p = rel_buffer = xmalloc (filename_len);
1221
1222   while (*cwd_p && IS_SAME_PATH_CHAR (*cwd_p, *path_p))
1223     {
1224       cwd_p++;
1225       path_p++;
1226     }
1227   if (!*cwd_p && (!*path_p || IS_DIR_SEPARATOR (*path_p)))
1228     {
1229       /* whole pwd matched */
1230       if (!*path_p)             /* input *is* the current path! */
1231         return ".";
1232       else
1233         return ++path_p;
1234     }
1235   else
1236     {
1237       if (*path_p)
1238         {
1239           --cwd_p;
1240           --path_p;
1241           while (! IS_DIR_SEPARATOR (*cwd_p))     /* backup to last slash */
1242             {
1243               --cwd_p;
1244               --path_p;
1245             }
1246           cwd_p++;
1247           path_p++;
1248           unmatched_slash_count++;
1249         }
1250
1251       /* Find out how many directory levels in cwd were *not* matched.  */
1252       while (*cwd_p++)
1253         if (IS_DIR_SEPARATOR (*(cwd_p-1)))
1254           unmatched_slash_count++;
1255
1256       /* Now we know how long the "short name" will be.
1257          Reject it if longer than the input.  */
1258       if (unmatched_slash_count * 3 + strlen (path_p) >= filename_len)
1259         return filename;
1260
1261       /* For each of them, put a `../' at the beginning of the short name.  */
1262       while (unmatched_slash_count--)
1263         {
1264           /* Give up if the result gets to be longer
1265              than the absolute path name.  */
1266           if (rel_buffer + filename_len <= rel_buf_p + 3)
1267             return filename;
1268           *rel_buf_p++ = '.';
1269           *rel_buf_p++ = '.';
1270           *rel_buf_p++ = DIR_SEPARATOR;
1271         }
1272
1273       /* Then tack on the unmatched part of the desired file's name.  */
1274       do
1275         {
1276           if (rel_buffer + filename_len <= rel_buf_p)
1277             return filename;
1278         }
1279       while ((*rel_buf_p++ = *path_p++));
1280
1281       --rel_buf_p;
1282       if (IS_DIR_SEPARATOR (*(rel_buf_p-1)))
1283         *--rel_buf_p = '\0';
1284       return rel_buffer;
1285     }
1286 }
1287 \f
1288 /* Lookup the given filename in the hash table for filenames.  If it is a
1289    new one, then the hash table info pointer will be null.  In this case,
1290    we create a new file_info record to go with the filename, and we initialize
1291    that record with some reasonable values.  */
1292
1293 /* FILENAME was const, but that causes a warning on AIX when calling stat.
1294    That is probably a bug in AIX, but might as well avoid the warning.  */
1295
1296 static file_info *
1297 find_file (const char *filename, int do_not_stat)
1298 {
1299   hash_table_entry *hash_entry_p;
1300
1301   hash_entry_p = lookup (filename_primary, filename);
1302   if (hash_entry_p->fip)
1303     return hash_entry_p->fip;
1304   else
1305     {
1306       struct stat stat_buf;
1307       file_info *file_p = xmalloc (sizeof (file_info));
1308
1309       /* If we cannot get status on any given source file, give a warning
1310          and then just set its time of last modification to infinity.  */
1311
1312       if (do_not_stat)
1313         stat_buf.st_mtime = (time_t) 0;
1314       else
1315         {
1316           if (stat (filename, &stat_buf) == -1)
1317             {
1318               int errno_val = errno;
1319               notice ("%s: %s: can't get status: %s\n",
1320                       pname, shortpath (NULL, filename),
1321                       xstrerror (errno_val));
1322               stat_buf.st_mtime = (time_t) -1;
1323             }
1324         }
1325
1326       hash_entry_p->fip = file_p;
1327       file_p->hash_entry = hash_entry_p;
1328       file_p->defs_decs = NULL;
1329       file_p->mtime = stat_buf.st_mtime;
1330       return file_p;
1331     }
1332 }
1333
1334 /* Generate a fatal error because some part of the aux_info file is
1335    messed up.  */
1336
1337 static void
1338 aux_info_corrupted (void)
1339 {
1340   notice ("\n%s: fatal error: aux info file corrupted at line %d\n",
1341           pname, current_aux_info_lineno);
1342   exit (FATAL_EXIT_CODE);
1343 }
1344
1345 /* ??? This comment is vague.  Say what the condition is for.  */
1346 /* Check to see that a condition is true.  This is kind of like an assert.  */
1347
1348 static void
1349 check_aux_info (int cond)
1350 {
1351   if (! cond)
1352     aux_info_corrupted ();
1353 }
1354
1355 /* Given a pointer to the closing right parenthesis for a particular formals
1356    list (in an aux_info file) find the corresponding left parenthesis and
1357    return a pointer to it.  */
1358
1359 static const char *
1360 find_corresponding_lparen (const char *p)
1361 {
1362   const char *q;
1363   int paren_depth;
1364
1365   for (paren_depth = 1, q = p-1; paren_depth; q--)
1366     {
1367       switch (*q)
1368         {
1369         case ')':
1370           paren_depth++;
1371           break;
1372         case '(':
1373           paren_depth--;
1374           break;
1375         }
1376     }
1377   return ++q;
1378 }
1379 \f
1380 /* Given a line from  an aux info file, and a time at which the aux info
1381    file it came from was created, check to see if the item described in
1382    the line comes from a file which has been modified since the aux info
1383    file was created.  If so, return nonzero, else return zero.  */
1384
1385 static int
1386 referenced_file_is_newer (const char *l, time_t aux_info_mtime)
1387 {
1388   const char *p;
1389   file_info *fi_p;
1390   char *filename;
1391
1392   check_aux_info (l[0] == '/');
1393   check_aux_info (l[1] == '*');
1394   check_aux_info (l[2] == ' ');
1395
1396   {
1397     const char *filename_start = p = l + 3;
1398
1399     while (*p != ':'
1400 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1401            || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
1402 #endif
1403            )
1404       p++;
1405     filename = alloca ((size_t) (p - filename_start) + 1);
1406     strncpy (filename, filename_start, (size_t) (p - filename_start));
1407     filename[p-filename_start] = '\0';
1408   }
1409
1410   /* Call find_file to find the file_info record associated with the file
1411      which contained this particular def or dec item.  Note that this call
1412      may cause a new file_info record to be created if this is the first time
1413      that we have ever known about this particular file.  */
1414
1415   fi_p = find_file (abspath (invocation_filename, filename), 0);
1416
1417   return (fi_p->mtime > aux_info_mtime);
1418 }
1419 \f
1420 /* Given a line of info from the aux_info file, create a new
1421    def_dec_info record to remember all of the important information about
1422    a function definition or declaration.
1423
1424    Link this record onto the list of such records for the particular file in
1425    which it occurred in proper (descending) line number order (for now).
1426
1427    If there is an identical record already on the list for the file, throw
1428    this one away.  Doing so takes care of the (useless and troublesome)
1429    duplicates which are bound to crop up due to multiple inclusions of any
1430    given individual header file.
1431
1432    Finally, link the new def_dec record onto the list of such records
1433    pertaining to this particular function name.  */
1434
1435 static void
1436 save_def_or_dec (const char *l, int is_syscalls)
1437 {
1438   const char *p;
1439   const char *semicolon_p;
1440   def_dec_info *def_dec_p = xmalloc (sizeof (def_dec_info));
1441
1442 #ifndef UNPROTOIZE
1443   def_dec_p->written = 0;
1444 #endif /* !defined (UNPROTOIZE) */
1445
1446   /* Start processing the line by picking off 5 pieces of information from
1447      the left hand end of the line.  These are filename, line number,
1448      new/old/implicit flag (new = ANSI prototype format), definition or
1449      declaration flag, and extern/static flag).  */
1450
1451   check_aux_info (l[0] == '/');
1452   check_aux_info (l[1] == '*');
1453   check_aux_info (l[2] == ' ');
1454
1455   {
1456     const char *filename_start = p = l + 3;
1457     char *filename;
1458
1459     while (*p != ':'
1460 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1461            || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
1462 #endif
1463            )
1464       p++;
1465     filename = alloca ((size_t) (p - filename_start) + 1);
1466     strncpy (filename, filename_start, (size_t) (p - filename_start));
1467     filename[p-filename_start] = '\0';
1468
1469     /* Call find_file to find the file_info record associated with the file
1470        which contained this particular def or dec item.  Note that this call
1471        may cause a new file_info record to be created if this is the first time
1472        that we have ever known about this particular file.
1473
1474        Note that we started out by forcing all of the base source file names
1475        (i.e. the names of the aux_info files with the .X stripped off) into the
1476        filenames hash table, and we simultaneously setup file_info records for
1477        all of these base file names (even if they may be useless later).
1478        The file_info records for all of these "base" file names (properly)
1479        act as file_info records for the "original" (i.e. un-included) files
1480        which were submitted to gcc for compilation (when the -aux-info
1481        option was used).  */
1482
1483     def_dec_p->file = find_file (abspath (invocation_filename, filename), is_syscalls);
1484   }
1485
1486   {
1487     const char *line_number_start = ++p;
1488     char line_number[10];
1489
1490     while (*p != ':'
1491 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1492            || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
1493 #endif
1494            )
1495       p++;
1496     strncpy (line_number, line_number_start, (size_t) (p - line_number_start));
1497     line_number[p-line_number_start] = '\0';
1498     def_dec_p->line = atoi (line_number);
1499   }
1500
1501   /* Check that this record describes a new-style, old-style, or implicit
1502      definition or declaration.  */
1503
1504   p++;  /* Skip over the `:'.  */
1505   check_aux_info ((*p == 'N') || (*p == 'O') || (*p == 'I'));
1506
1507   /* Is this a new style (ANSI prototyped) definition or declaration? */
1508
1509   def_dec_p->prototyped = (*p == 'N');
1510
1511 #ifndef UNPROTOIZE
1512
1513   /* Is this an implicit declaration? */
1514
1515   def_dec_p->is_implicit = (*p == 'I');
1516
1517 #endif /* !defined (UNPROTOIZE) */
1518
1519   p++;
1520
1521   check_aux_info ((*p == 'C') || (*p == 'F'));
1522
1523   /* Is this item a function definition (F) or a declaration (C).  Note that
1524      we treat item taken from the syscalls file as though they were function
1525      definitions regardless of what the stuff in the file says.  */
1526
1527   def_dec_p->is_func_def = ((*p++ == 'F') || is_syscalls);
1528
1529 #ifndef UNPROTOIZE
1530   def_dec_p->definition = 0;    /* Fill this in later if protoizing.  */
1531 #endif /* !defined (UNPROTOIZE) */
1532
1533   check_aux_info (*p++ == ' ');
1534   check_aux_info (*p++ == '*');
1535   check_aux_info (*p++ == '/');
1536   check_aux_info (*p++ == ' ');
1537
1538 #ifdef UNPROTOIZE
1539   check_aux_info ((!strncmp (p, "static", 6)) || (!strncmp (p, "extern", 6)));
1540 #else /* !defined (UNPROTOIZE) */
1541   if (!strncmp (p, "static", 6))
1542     def_dec_p->is_static = -1;
1543   else if (!strncmp (p, "extern", 6))
1544     def_dec_p->is_static = 0;
1545   else
1546     check_aux_info (0); /* Didn't find either `extern' or `static'.  */
1547 #endif /* !defined (UNPROTOIZE) */
1548
1549   {
1550     const char *ansi_start = p;
1551
1552     p += 6;     /* Pass over the "static" or "extern".  */
1553
1554     /* We are now past the initial stuff.  Search forward from here to find
1555        the terminating semicolon that should immediately follow the entire
1556        ANSI format function declaration.  */
1557
1558     while (*++p != ';')
1559       continue;
1560
1561     semicolon_p = p;
1562
1563     /* Make a copy of the ansi declaration part of the line from the aux_info
1564        file.  */
1565
1566     def_dec_p->ansi_decl
1567       = dupnstr (ansi_start, (size_t) ((semicolon_p+1) - ansi_start));
1568
1569     /* Backup and point at the final right paren of the final argument list.  */
1570
1571     p--;
1572
1573 #ifndef UNPROTOIZE
1574     def_dec_p->f_list_chain = NULL;
1575 #endif /* !defined (UNPROTOIZE) */
1576
1577     while (p != ansi_start && (p[-1] == ' ' || p[-1] == '\t')) p--;
1578     if (*p != ')')
1579       {
1580         free_def_dec (def_dec_p);
1581         return;
1582       }
1583   }
1584
1585   /* Now isolate a whole set of formal argument lists, one-by-one.  Normally,
1586      there will only be one list to isolate, but there could be more.  */
1587
1588   def_dec_p->f_list_count = 0;
1589
1590   for (;;)
1591     {
1592       const char *left_paren_p = find_corresponding_lparen (p);
1593 #ifndef UNPROTOIZE
1594       {
1595         f_list_chain_item *cip = xmalloc (sizeof (f_list_chain_item));
1596
1597         cip->formals_list
1598           = dupnstr (left_paren_p + 1, (size_t) (p - (left_paren_p+1)));
1599
1600         /* Add the new chain item at the head of the current list.  */
1601
1602         cip->chain_next = def_dec_p->f_list_chain;
1603         def_dec_p->f_list_chain = cip;
1604       }
1605 #endif /* !defined (UNPROTOIZE) */
1606       def_dec_p->f_list_count++;
1607
1608       p = left_paren_p - 2;
1609
1610       /* p must now point either to another right paren, or to the last
1611          character of the name of the function that was declared/defined.
1612          If p points to another right paren, then this indicates that we
1613          are dealing with multiple formals lists.  In that case, there
1614          really should be another right paren preceding this right paren.  */
1615
1616       if (*p != ')')
1617         break;
1618       else
1619         check_aux_info (*--p == ')');
1620     }
1621
1622
1623   {
1624     const char *past_fn = p + 1;
1625
1626     check_aux_info (*past_fn == ' ');
1627
1628     /* Scan leftwards over the identifier that names the function.  */
1629
1630     while (is_id_char (*p))
1631       p--;
1632     p++;
1633
1634     /* p now points to the leftmost character of the function name.  */
1635
1636     {
1637       char *fn_string = alloca (past_fn - p + 1);
1638
1639       strncpy (fn_string, p, (size_t) (past_fn - p));
1640       fn_string[past_fn-p] = '\0';
1641       def_dec_p->hash_entry = lookup (function_name_primary, fn_string);
1642     }
1643   }
1644
1645   /* Look at all of the defs and decs for this function name that we have
1646      collected so far.  If there is already one which is at the same
1647      line number in the same file, then we can discard this new def_dec_info
1648      record.
1649
1650      As an extra assurance that any such pair of (nominally) identical
1651      function declarations are in fact identical, we also compare the
1652      ansi_decl parts of the lines from the aux_info files just to be on
1653      the safe side.
1654
1655      This comparison will fail if (for instance) the user was playing
1656      messy games with the preprocessor which ultimately causes one
1657      function declaration in one header file to look differently when
1658      that file is included by two (or more) other files.  */
1659
1660   {
1661     const def_dec_info *other;
1662
1663     for (other = def_dec_p->hash_entry->ddip; other; other = other->next_for_func)
1664       {
1665         if (def_dec_p->line == other->line && def_dec_p->file == other->file)
1666           {
1667             if (strcmp (def_dec_p->ansi_decl, other->ansi_decl))
1668               {
1669                 notice ("%s:%d: declaration of function `%s' takes different forms\n",
1670                         def_dec_p->file->hash_entry->symbol,
1671                         def_dec_p->line,
1672                         def_dec_p->hash_entry->symbol);
1673                 exit (FATAL_EXIT_CODE);
1674               }
1675             free_def_dec (def_dec_p);
1676             return;
1677           }
1678       }
1679   }
1680
1681 #ifdef UNPROTOIZE
1682
1683   /* If we are doing unprotoizing, we must now setup the pointers that will
1684      point to the K&R name list and to the K&R argument declarations list.
1685
1686      Note that if this is only a function declaration, then we should not
1687      expect to find any K&R style formals list following the ANSI-style
1688      formals list.  This is because GCC knows that such information is
1689      useless in the case of function declarations (function definitions
1690      are a different story however).
1691
1692      Since we are unprotoizing, we don't need any such lists anyway.
1693      All we plan to do is to delete all characters between ()'s in any
1694      case.  */
1695
1696   def_dec_p->formal_names = NULL;
1697   def_dec_p->formal_decls = NULL;
1698
1699   if (def_dec_p->is_func_def)
1700     {
1701       p = semicolon_p;
1702       check_aux_info (*++p == ' ');
1703       check_aux_info (*++p == '/');
1704       check_aux_info (*++p == '*');
1705       check_aux_info (*++p == ' ');
1706       check_aux_info (*++p == '(');
1707
1708       {
1709         const char *kr_names_start = ++p;   /* Point just inside '('.  */
1710
1711         while (*p++ != ')')
1712           continue;
1713         p--;            /* point to closing right paren */
1714
1715         /* Make a copy of the K&R parameter names list.  */
1716
1717         def_dec_p->formal_names
1718           = dupnstr (kr_names_start, (size_t) (p - kr_names_start));
1719       }
1720
1721       check_aux_info (*++p == ' ');
1722       p++;
1723
1724       /* p now points to the first character of the K&R style declarations
1725          list (if there is one) or to the star-slash combination that ends
1726          the comment in which such lists get embedded.  */
1727
1728       /* Make a copy of the K&R formal decls list and set the def_dec record
1729          to point to it.  */
1730
1731       if (*p == '*')            /* Are there no K&R declarations? */
1732         {
1733           check_aux_info (*++p == '/');
1734           def_dec_p->formal_decls = "";
1735         }
1736       else
1737         {
1738           const char *kr_decls_start = p;
1739
1740           while (p[0] != '*' || p[1] != '/')
1741             p++;
1742           p--;
1743
1744           check_aux_info (*p == ' ');
1745
1746           def_dec_p->formal_decls
1747             = dupnstr (kr_decls_start, (size_t) (p - kr_decls_start));
1748         }
1749
1750       /* Handle a special case.  If we have a function definition marked as
1751          being in "old" style, and if its formal names list is empty, then
1752          it may actually have the string "void" in its real formals list
1753          in the original source code.  Just to make sure, we will get setup
1754          to convert such things anyway.
1755
1756          This kludge only needs to be here because of an insurmountable
1757          problem with generating .X files.  */
1758
1759       if (!def_dec_p->prototyped && !*def_dec_p->formal_names)
1760         def_dec_p->prototyped = 1;
1761     }
1762
1763   /* Since we are unprotoizing, if this item is already in old (K&R) style,
1764      we can just ignore it.  If that is true, throw away the itme now.  */
1765
1766   if (!def_dec_p->prototyped)
1767     {
1768       free_def_dec (def_dec_p);
1769       return;
1770     }
1771
1772 #endif /* defined (UNPROTOIZE) */
1773
1774   /* Add this record to the head of the list of records pertaining to this
1775      particular function name.  */
1776
1777   def_dec_p->next_for_func = def_dec_p->hash_entry->ddip;
1778   def_dec_p->hash_entry->ddip = def_dec_p;
1779
1780   /* Add this new def_dec_info record to the sorted list of def_dec_info
1781      records for this file.  Note that we don't have to worry about duplicates
1782      (caused by multiple inclusions of header files) here because we have
1783      already eliminated duplicates above.  */
1784
1785   if (!def_dec_p->file->defs_decs)
1786     {
1787       def_dec_p->file->defs_decs = def_dec_p;
1788       def_dec_p->next_in_file = NULL;
1789     }
1790   else
1791     {
1792       int line = def_dec_p->line;
1793       const def_dec_info *prev = NULL;
1794       const def_dec_info *curr = def_dec_p->file->defs_decs;
1795       const def_dec_info *next = curr->next_in_file;
1796
1797       while (next && (line < curr->line))
1798         {
1799           prev = curr;
1800           curr = next;
1801           next = next->next_in_file;
1802         }
1803       if (line >= curr->line)
1804         {
1805           def_dec_p->next_in_file = curr;
1806           if (prev)
1807             ((NONCONST def_dec_info *) prev)->next_in_file = def_dec_p;
1808           else
1809             def_dec_p->file->defs_decs = def_dec_p;
1810         }
1811       else      /* assert (next == NULL); */
1812         {
1813           ((NONCONST def_dec_info *) curr)->next_in_file = def_dec_p;
1814           /* assert (next == NULL); */
1815           def_dec_p->next_in_file = next;
1816         }
1817     }
1818 }
1819 \f
1820 /* Set up the vector COMPILE_PARAMS which is the argument list for running GCC.
1821    Also set input_file_name_index and aux_info_file_name_index
1822    to the indices of the slots where the file names should go.  */
1823
1824 /* We initialize the vector by  removing -g, -O, -S, -c, and -o options,
1825    and adding '-aux-info AUXFILE -S  -o /dev/null INFILE' at the end.  */
1826
1827 static void
1828 munge_compile_params (const char *params_list)
1829 {
1830   /* Build up the contents in a temporary vector
1831      that is so big that to has to be big enough.  */
1832   const char **temp_params
1833     = alloca ((strlen (params_list) + 8) * sizeof (char *));
1834   int param_count = 0;
1835   const char *param;
1836   struct stat st;
1837
1838   temp_params[param_count++] = compiler_file_name;
1839   for (;;)
1840     {
1841       while (ISSPACE ((const unsigned char)*params_list))
1842         params_list++;
1843       if (!*params_list)
1844         break;
1845       param = params_list;
1846       while (*params_list && !ISSPACE ((const unsigned char)*params_list))
1847         params_list++;
1848       if (param[0] != '-')
1849         temp_params[param_count++]
1850           = dupnstr (param, (size_t) (params_list - param));
1851       else
1852         {
1853           switch (param[1])
1854             {
1855             case 'g':
1856             case 'O':
1857             case 'S':
1858             case 'c':
1859               break;            /* Don't copy these.  */
1860             case 'o':
1861               while (ISSPACE ((const unsigned char)*params_list))
1862                 params_list++;
1863               while (*params_list
1864                      && !ISSPACE ((const unsigned char)*params_list))
1865                 params_list++;
1866               break;
1867             default:
1868               temp_params[param_count++]
1869                 = dupnstr (param, (size_t) (params_list - param));
1870             }
1871         }
1872       if (!*params_list)
1873         break;
1874     }
1875   temp_params[param_count++] = "-aux-info";
1876
1877   /* Leave room for the aux-info file name argument.  */
1878   aux_info_file_name_index = param_count;
1879   temp_params[param_count++] = NULL;
1880
1881   temp_params[param_count++] = "-S";
1882   temp_params[param_count++] = "-o";
1883
1884   if ((stat (HOST_BIT_BUCKET, &st) == 0)
1885       && (!S_ISDIR (st.st_mode))
1886       && (access (HOST_BIT_BUCKET, W_OK) == 0))
1887     temp_params[param_count++] = HOST_BIT_BUCKET;
1888   else
1889     /* FIXME: This is hardly likely to be right, if HOST_BIT_BUCKET is not
1890        writable.  But until this is rejigged to use make_temp_file(), this
1891        is the best we can do.  */
1892     temp_params[param_count++] = "/dev/null";
1893
1894   /* Leave room for the input file name argument.  */
1895   input_file_name_index = param_count;
1896   temp_params[param_count++] = NULL;
1897   /* Terminate the list.  */
1898   temp_params[param_count++] = NULL;
1899
1900   /* Make a copy of the compile_params in heap space.  */
1901
1902   compile_params = xmalloc (sizeof (char *) * (param_count+1));
1903   memcpy (compile_params, temp_params, sizeof (char *) * param_count);
1904 }
1905
1906 /* Do a recompilation for the express purpose of generating a new aux_info
1907    file to go with a specific base source file.
1908
1909    The result is a boolean indicating success.  */
1910
1911 static int
1912 gen_aux_info_file (const char *base_filename)
1913 {
1914   if (!input_file_name_index)
1915     munge_compile_params ("");
1916
1917   /* Store the full source file name in the argument vector.  */
1918   compile_params[input_file_name_index] = shortpath (NULL, base_filename);
1919   /* Add .X to source file name to get aux-info file name.  */
1920   compile_params[aux_info_file_name_index] =
1921     concat (compile_params[input_file_name_index], aux_info_suffix, NULL);
1922
1923   if (!quiet_flag)
1924     notice ("%s: compiling `%s'\n",
1925             pname, compile_params[input_file_name_index]);
1926
1927   {
1928     char *errmsg_fmt, *errmsg_arg;
1929     int wait_status, pid;
1930
1931     pid = pexecute (compile_params[0], (char * const *) compile_params,
1932                     pname, NULL, &errmsg_fmt, &errmsg_arg,
1933                     PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH);
1934
1935     if (pid == -1)
1936       {
1937         int errno_val = errno;
1938         fprintf (stderr, "%s: ", pname);
1939         fprintf (stderr, errmsg_fmt, errmsg_arg);
1940         fprintf (stderr, ": %s\n", xstrerror (errno_val));
1941         return 0;
1942       }
1943
1944     pid = pwait (pid, &wait_status, 0);
1945     if (pid == -1)
1946       {
1947         notice ("%s: wait: %s\n", pname, xstrerror (errno));
1948         return 0;
1949       }
1950     if (WIFSIGNALED (wait_status))
1951       {
1952         notice ("%s: subprocess got fatal signal %d\n",
1953                 pname, WTERMSIG (wait_status));
1954         return 0;
1955       }
1956     if (WIFEXITED (wait_status))
1957       {
1958         if (WEXITSTATUS (wait_status) != 0)
1959           {
1960             notice ("%s: %s exited with status %d\n",
1961                     pname, compile_params[0], WEXITSTATUS (wait_status));
1962             return 0;
1963           }
1964         return 1;
1965       }
1966     abort ();
1967   }
1968 }
1969 \f
1970 /* Read in all of the information contained in a single aux_info file.
1971    Save all of the important stuff for later.  */
1972
1973 static void
1974 process_aux_info_file (const char *base_source_filename, int keep_it,
1975                        int is_syscalls)
1976 {
1977   size_t base_len = strlen (base_source_filename);
1978   char * aux_info_filename = alloca (base_len + strlen (aux_info_suffix) + 1);
1979   char *aux_info_base;
1980   char *aux_info_limit;
1981   char *aux_info_relocated_name;
1982   const char *aux_info_second_line;
1983   time_t aux_info_mtime;
1984   size_t aux_info_size;
1985   int must_create;
1986
1987   /* Construct the aux_info filename from the base source filename.  */
1988
1989   strcpy (aux_info_filename, base_source_filename);
1990   strcat (aux_info_filename, aux_info_suffix);
1991
1992   /* Check that the aux_info file exists and is readable.  If it does not
1993      exist, try to create it (once only).  */
1994
1995   /* If file doesn't exist, set must_create.
1996      Likewise if it exists and we can read it but it is obsolete.
1997      Otherwise, report an error.  */
1998   must_create = 0;
1999
2000   /* Come here with must_create set to 1 if file is out of date.  */
2001 start_over: ;
2002
2003   if (access (aux_info_filename, R_OK) == -1)
2004     {
2005       if (errno == ENOENT)
2006         {
2007           if (is_syscalls)
2008             {
2009               notice ("%s: warning: missing SYSCALLS file `%s'\n",
2010                       pname, aux_info_filename);
2011               return;
2012             }
2013           must_create = 1;
2014         }
2015       else
2016         {
2017           int errno_val = errno;
2018           notice ("%s: can't read aux info file `%s': %s\n",
2019                   pname, shortpath (NULL, aux_info_filename),
2020                   xstrerror (errno_val));
2021           errors++;
2022           return;
2023         }
2024     }
2025 #if 0 /* There is code farther down to take care of this.  */
2026   else
2027     {
2028       struct stat s1, s2;
2029       stat (aux_info_file_name, &s1);
2030       stat (base_source_file_name, &s2);
2031       if (s2.st_mtime > s1.st_mtime)
2032         must_create = 1;
2033     }
2034 #endif /* 0 */
2035
2036   /* If we need a .X file, create it, and verify we can read it.  */
2037   if (must_create)
2038     {
2039       if (!gen_aux_info_file (base_source_filename))
2040         {
2041           errors++;
2042           return;
2043         }
2044       if (access (aux_info_filename, R_OK) == -1)
2045         {
2046           int errno_val = errno;
2047           notice ("%s: can't read aux info file `%s': %s\n",
2048                   pname, shortpath (NULL, aux_info_filename),
2049                   xstrerror (errno_val));
2050           errors++;
2051           return;
2052         }
2053     }
2054
2055   {
2056     struct stat stat_buf;
2057
2058     /* Get some status information about this aux_info file.  */
2059
2060     if (stat (aux_info_filename, &stat_buf) == -1)
2061       {
2062         int errno_val = errno;
2063         notice ("%s: can't get status of aux info file `%s': %s\n",
2064                 pname, shortpath (NULL, aux_info_filename),
2065                 xstrerror (errno_val));
2066         errors++;
2067         return;
2068       }
2069
2070     /* Check on whether or not this aux_info file is zero length.  If it is,
2071        then just ignore it and return.  */
2072
2073     if ((aux_info_size = stat_buf.st_size) == 0)
2074       return;
2075
2076     /* Get the date/time of last modification for this aux_info file and
2077        remember it.  We will have to check that any source files that it
2078        contains information about are at least this old or older.  */
2079
2080     aux_info_mtime = stat_buf.st_mtime;
2081
2082     if (!is_syscalls)
2083       {
2084         /* Compare mod time with the .c file; update .X file if obsolete.
2085            The code later on can fail to check the .c file
2086            if it did not directly define any functions.  */
2087
2088         if (stat (base_source_filename, &stat_buf) == -1)
2089           {
2090             int errno_val = errno;
2091             notice ("%s: can't get status of aux info file `%s': %s\n",
2092                     pname, shortpath (NULL, base_source_filename),
2093                     xstrerror (errno_val));
2094             errors++;
2095             return;
2096           }
2097         if (stat_buf.st_mtime > aux_info_mtime)
2098           {
2099             must_create = 1;
2100             goto start_over;
2101           }
2102       }
2103   }
2104
2105   {
2106     int aux_info_file;
2107     int fd_flags;
2108
2109     /* Open the aux_info file.  */
2110
2111     fd_flags = O_RDONLY;
2112 #ifdef O_BINARY
2113     /* Use binary mode to avoid having to deal with different EOL characters.  */
2114     fd_flags |= O_BINARY;
2115 #endif
2116     if ((aux_info_file = open (aux_info_filename, fd_flags, 0444 )) == -1)
2117       {
2118         int errno_val = errno;
2119         notice ("%s: can't open aux info file `%s' for reading: %s\n",
2120                 pname, shortpath (NULL, aux_info_filename),
2121                 xstrerror (errno_val));
2122         return;
2123       }
2124
2125     /* Allocate space to hold the aux_info file in memory.  */
2126
2127     aux_info_base = xmalloc (aux_info_size + 1);
2128     aux_info_limit = aux_info_base + aux_info_size;
2129     *aux_info_limit = '\0';
2130
2131     /* Read the aux_info file into memory.  */
2132
2133     if (safe_read (aux_info_file, aux_info_base, aux_info_size) !=
2134         (int) aux_info_size)
2135       {
2136         int errno_val = errno;
2137         notice ("%s: error reading aux info file `%s': %s\n",
2138                 pname, shortpath (NULL, aux_info_filename),
2139                 xstrerror (errno_val));
2140         free (aux_info_base);
2141         close (aux_info_file);
2142         return;
2143       }
2144
2145     /* Close the aux info file.  */
2146
2147     if (close (aux_info_file))
2148       {
2149         int errno_val = errno;
2150         notice ("%s: error closing aux info file `%s': %s\n",
2151                 pname, shortpath (NULL, aux_info_filename),
2152                 xstrerror (errno_val));
2153         free (aux_info_base);
2154         close (aux_info_file);
2155         return;
2156       }
2157   }
2158
2159   /* Delete the aux_info file (unless requested not to).  If the deletion
2160      fails for some reason, don't even worry about it.  */
2161
2162   if (must_create && !keep_it)
2163     if (unlink (aux_info_filename) == -1)
2164       {
2165         int errno_val = errno;
2166         notice ("%s: can't delete aux info file `%s': %s\n",
2167                 pname, shortpath (NULL, aux_info_filename),
2168                 xstrerror (errno_val));
2169       }
2170
2171   /* Save a pointer into the first line of the aux_info file which
2172      contains the filename of the directory from which the compiler
2173      was invoked when the associated source file was compiled.
2174      This information is used later to help create complete
2175      filenames out of the (potentially) relative filenames in
2176      the aux_info file.  */
2177
2178   {
2179     char *p = aux_info_base;
2180
2181     while (*p != ':'
2182 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
2183            || (*p == ':' && *p && *(p+1) && IS_DIR_SEPARATOR (*(p+1)))
2184 #endif
2185            )
2186       p++;
2187     p++;
2188     while (*p == ' ')
2189       p++;
2190     invocation_filename = p;    /* Save a pointer to first byte of path.  */
2191     while (*p != ' ')
2192       p++;
2193     *p++ = DIR_SEPARATOR;
2194     *p++ = '\0';
2195     while (*p++ != '\n')
2196       continue;
2197     aux_info_second_line = p;
2198     aux_info_relocated_name = 0;
2199     if (! IS_ABSOLUTE_PATH (invocation_filename))
2200       {
2201         /* INVOCATION_FILENAME is relative;
2202            append it to BASE_SOURCE_FILENAME's dir.  */
2203         char *dir_end;
2204         aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
2205         strcpy (aux_info_relocated_name, base_source_filename);
2206         dir_end = strrchr (aux_info_relocated_name, DIR_SEPARATOR);
2207 #ifdef DIR_SEPARATOR_2
2208         {
2209           char *slash;
2210
2211           slash = strrchr (dir_end ? dir_end : aux_info_relocated_name,
2212                            DIR_SEPARATOR_2);
2213           if (slash)
2214             dir_end = slash;
2215         }
2216 #endif
2217         if (dir_end)
2218           dir_end++;
2219         else
2220           dir_end = aux_info_relocated_name;
2221         strcpy (dir_end, invocation_filename);
2222         invocation_filename = aux_info_relocated_name;
2223       }
2224   }
2225
2226
2227   {
2228     const char *aux_info_p;
2229
2230     /* Do a pre-pass on the lines in the aux_info file, making sure that all
2231        of the source files referenced in there are at least as old as this
2232        aux_info file itself.  If not, go back and regenerate the aux_info
2233        file anew.  Don't do any of this for the syscalls file.  */
2234
2235     if (!is_syscalls)
2236       {
2237         current_aux_info_lineno = 2;
2238
2239         for (aux_info_p = aux_info_second_line; *aux_info_p; )
2240           {
2241             if (referenced_file_is_newer (aux_info_p, aux_info_mtime))
2242               {
2243                 free (aux_info_base);
2244                 free (aux_info_relocated_name);
2245                 if (keep_it && unlink (aux_info_filename) == -1)
2246                   {
2247                     int errno_val = errno;
2248                     notice ("%s: can't delete file `%s': %s\n",
2249                             pname, shortpath (NULL, aux_info_filename),
2250                             xstrerror (errno_val));
2251                     return;
2252                   }
2253                 must_create = 1;
2254                 goto start_over;
2255               }
2256
2257             /* Skip over the rest of this line to start of next line.  */
2258
2259             while (*aux_info_p != '\n')
2260               aux_info_p++;
2261             aux_info_p++;
2262             current_aux_info_lineno++;
2263           }
2264       }
2265
2266     /* Now do the real pass on the aux_info lines.  Save their information in
2267        the in-core data base.  */
2268
2269     current_aux_info_lineno = 2;
2270
2271     for (aux_info_p = aux_info_second_line; *aux_info_p;)
2272       {
2273         char *unexpanded_line = unexpand_if_needed (aux_info_p);
2274
2275         if (unexpanded_line)
2276           {
2277             save_def_or_dec (unexpanded_line, is_syscalls);
2278             free (unexpanded_line);
2279           }
2280         else
2281           save_def_or_dec (aux_info_p, is_syscalls);
2282
2283         /* Skip over the rest of this line and get to start of next line.  */
2284
2285         while (*aux_info_p != '\n')
2286           aux_info_p++;
2287         aux_info_p++;
2288         current_aux_info_lineno++;
2289       }
2290   }
2291
2292   free (aux_info_base);
2293   free (aux_info_relocated_name);
2294 }
2295 \f
2296 #ifndef UNPROTOIZE
2297
2298 /* Check an individual filename for a .c suffix.  If the filename has this
2299    suffix, rename the file such that its suffix is changed to .C.  This
2300    function implements the -C option.  */
2301
2302 static void
2303 rename_c_file (const hash_table_entry *hp)
2304 {
2305   const char *filename = hp->symbol;
2306   int last_char_index = strlen (filename) - 1;
2307   char *const new_filename = alloca (strlen (filename)
2308                                      + strlen (cplus_suffix) + 1);
2309
2310   /* Note that we don't care here if the given file was converted or not.  It
2311      is possible that the given file was *not* converted, simply because there
2312      was nothing in it which actually required conversion.  Even in this case,
2313      we want to do the renaming.  Note that we only rename files with the .c
2314      suffix (except for the syscalls file, which is left alone).  */
2315
2316   if (filename[last_char_index] != 'c' || filename[last_char_index-1] != '.'
2317       || IS_SAME_PATH (syscalls_absolute_filename, filename))
2318     return;
2319
2320   strcpy (new_filename, filename);
2321   strcpy (&new_filename[last_char_index], cplus_suffix);
2322
2323   if (rename (filename, new_filename) == -1)
2324     {
2325       int errno_val = errno;
2326       notice ("%s: warning: can't rename file `%s' to `%s': %s\n",
2327               pname, shortpath (NULL, filename),
2328               shortpath (NULL, new_filename), xstrerror (errno_val));
2329       errors++;
2330       return;
2331     }
2332 }
2333
2334 #endif /* !defined (UNPROTOIZE) */
2335 \f
2336 /* Take the list of definitions and declarations attached to a particular
2337    file_info node and reverse the order of the list.  This should get the
2338    list into an order such that the item with the lowest associated line
2339    number is nearest the head of the list.  When these lists are originally
2340    built, they are in the opposite order.  We want to traverse them in
2341    normal line number order later (i.e. lowest to highest) so reverse the
2342    order here.  */
2343
2344 static void
2345 reverse_def_dec_list (const hash_table_entry *hp)
2346 {
2347   file_info *file_p = hp->fip;
2348   def_dec_info *prev = NULL;
2349   def_dec_info *current = (def_dec_info *) file_p->defs_decs;
2350
2351   if (!current)
2352     return;                     /* no list to reverse */
2353
2354   prev = current;
2355   if (! (current = (def_dec_info *) current->next_in_file))
2356     return;                     /* can't reverse a single list element */
2357
2358   prev->next_in_file = NULL;
2359
2360   while (current)
2361     {
2362       def_dec_info *next = (def_dec_info *) current->next_in_file;
2363
2364       current->next_in_file = prev;
2365       prev = current;
2366       current = next;
2367     }
2368
2369   file_p->defs_decs = prev;
2370 }
2371
2372 #ifndef UNPROTOIZE
2373
2374 /* Find the (only?) extern definition for a particular function name, starting
2375    from the head of the linked list of entries for the given name.  If we
2376    cannot find an extern definition for the given function name, issue a
2377    warning and scrounge around for the next best thing, i.e. an extern
2378    function declaration with a prototype attached to it.  Note that we only
2379    allow such substitutions for extern declarations and never for static
2380    declarations.  That's because the only reason we allow them at all is
2381    to let un-prototyped function declarations for system-supplied library
2382    functions get their prototypes from our own extra SYSCALLS.c.X file which
2383    contains all of the correct prototypes for system functions.  */
2384
2385 static const def_dec_info *
2386 find_extern_def (const def_dec_info *head, const def_dec_info *user)
2387 {
2388   const def_dec_info *dd_p;
2389   const def_dec_info *extern_def_p = NULL;
2390   int conflict_noted = 0;
2391
2392   /* Don't act too stupid here.  Somebody may try to convert an entire system
2393      in one swell fwoop (rather than one program at a time, as should be done)
2394      and in that case, we may find that there are multiple extern definitions
2395      of a given function name in the entire set of source files that we are
2396      converting.  If however one of these definitions resides in exactly the
2397      same source file as the reference we are trying to satisfy then in that
2398      case it would be stupid for us to fail to realize that this one definition
2399      *must* be the precise one we are looking for.
2400
2401      To make sure that we don't miss an opportunity to make this "same file"
2402      leap of faith, we do a prescan of the list of records relating to the
2403      given function name, and we look (on this first scan) *only* for a
2404      definition of the function which is in the same file as the reference
2405      we are currently trying to satisfy.  */
2406
2407   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2408     if (dd_p->is_func_def && !dd_p->is_static && dd_p->file == user->file)
2409       return dd_p;
2410
2411   /* Now, since we have not found a definition in the same file as the
2412      reference, we scan the list again and consider all possibilities from
2413      all files.  Here we may get conflicts with the things listed in the
2414      SYSCALLS.c.X file, but if that happens it only means that the source
2415      code being converted contains its own definition of a function which
2416      could have been supplied by libc.a.  In such cases, we should avoid
2417      issuing the normal warning, and defer to the definition given in the
2418      user's own code.  */
2419
2420   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2421     if (dd_p->is_func_def && !dd_p->is_static)
2422       {
2423         if (!extern_def_p)      /* Previous definition? */
2424           extern_def_p = dd_p;  /* Remember the first definition found.  */
2425         else
2426           {
2427             /* Ignore definition just found if it came from SYSCALLS.c.X.  */
2428
2429             if (is_syscalls_file (dd_p->file))
2430               continue;
2431
2432             /* Quietly replace the definition previously found with the one
2433                just found if the previous one was from SYSCALLS.c.X.  */
2434
2435             if (is_syscalls_file (extern_def_p->file))
2436               {
2437                 extern_def_p = dd_p;
2438                 continue;
2439               }
2440
2441             /* If we get here, then there is a conflict between two function
2442                declarations for the same function, both of which came from the
2443                user's own code.  */
2444
2445             if (!conflict_noted)        /* first time we noticed? */
2446               {
2447                 conflict_noted = 1;
2448                 notice ("%s: conflicting extern definitions of '%s'\n",
2449                         pname, head->hash_entry->symbol);
2450                 if (!quiet_flag)
2451                   {
2452                     notice ("%s: declarations of '%s' will not be converted\n",
2453                             pname, head->hash_entry->symbol);
2454                     notice ("%s: conflict list for '%s' follows:\n",
2455                             pname, head->hash_entry->symbol);
2456                     fprintf (stderr, "%s:     %s(%d): %s\n",
2457                              pname,
2458                              shortpath (NULL, extern_def_p->file->hash_entry->symbol),
2459                              extern_def_p->line, extern_def_p->ansi_decl);
2460                   }
2461               }
2462             if (!quiet_flag)
2463               fprintf (stderr, "%s:     %s(%d): %s\n",
2464                        pname,
2465                        shortpath (NULL, dd_p->file->hash_entry->symbol),
2466                        dd_p->line, dd_p->ansi_decl);
2467           }
2468       }
2469
2470   /* We want to err on the side of caution, so if we found multiple conflicting
2471      definitions for the same function, treat this as being that same as if we
2472      had found no definitions (i.e. return NULL).  */
2473
2474   if (conflict_noted)
2475     return NULL;
2476
2477   if (!extern_def_p)
2478     {
2479       /* We have no definitions for this function so do the next best thing.
2480          Search for an extern declaration already in prototype form.  */
2481
2482       for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2483         if (!dd_p->is_func_def && !dd_p->is_static && dd_p->prototyped)
2484           {
2485             extern_def_p = dd_p;        /* save a pointer to the definition */
2486             if (!quiet_flag)
2487               notice ("%s: warning: using formals list from %s(%d) for function `%s'\n",
2488                       pname,
2489                       shortpath (NULL, dd_p->file->hash_entry->symbol),
2490                       dd_p->line, dd_p->hash_entry->symbol);
2491             break;
2492           }
2493
2494       /* Gripe about unprototyped function declarations that we found no
2495          corresponding definition (or other source of prototype information)
2496          for.
2497
2498          Gripe even if the unprototyped declaration we are worried about
2499          exists in a file in one of the "system" include directories.  We
2500          can gripe about these because we should have at least found a
2501          corresponding (pseudo) definition in the SYSCALLS.c.X file.  If we
2502          didn't, then that means that the SYSCALLS.c.X file is missing some
2503          needed prototypes for this particular system.  That is worth telling
2504          the user about!  */
2505
2506       if (!extern_def_p)
2507         {
2508           const char *file = user->file->hash_entry->symbol;
2509
2510           if (!quiet_flag)
2511             if (in_system_include_dir (file))
2512               {
2513                 /* Why copy this string into `needed' at all?
2514                    Why not just use user->ansi_decl without copying?  */
2515                 char *needed = alloca (strlen (user->ansi_decl) + 1);
2516                 char *p;
2517
2518                 strcpy (needed, user->ansi_decl);
2519                 p = (NONCONST char *) substr (needed, user->hash_entry->symbol)
2520                     + strlen (user->hash_entry->symbol) + 2;
2521                 /* Avoid having ??? in the string.  */
2522                 *p++ = '?';
2523                 *p++ = '?';
2524                 *p++ = '?';
2525                 strcpy (p, ");");
2526
2527                 notice ("%s: %d: `%s' used but missing from SYSCALLS\n",
2528                         shortpath (NULL, file), user->line,
2529                         needed+7);      /* Don't print "extern " */
2530               }
2531 #if 0
2532             else
2533               notice ("%s: %d: warning: no extern definition for `%s'\n",
2534                       shortpath (NULL, file), user->line,
2535                       user->hash_entry->symbol);
2536 #endif
2537         }
2538     }
2539   return extern_def_p;
2540 }
2541 \f
2542 /* Find the (only?) static definition for a particular function name in a
2543    given file.  Here we get the function-name and the file info indirectly
2544    from the def_dec_info record pointer which is passed in.  */
2545
2546 static const def_dec_info *
2547 find_static_definition (const def_dec_info *user)
2548 {
2549   const def_dec_info *head = user->hash_entry->ddip;
2550   const def_dec_info *dd_p;
2551   int num_static_defs = 0;
2552   const def_dec_info *static_def_p = NULL;
2553
2554   for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2555     if (dd_p->is_func_def && dd_p->is_static && (dd_p->file == user->file))
2556       {
2557         static_def_p = dd_p;    /* save a pointer to the definition */
2558         num_static_defs++;
2559       }
2560   if (num_static_defs == 0)
2561     {
2562       if (!quiet_flag)
2563         notice ("%s: warning: no static definition for `%s' in file `%s'\n",
2564                 pname, head->hash_entry->symbol,
2565                 shortpath (NULL, user->file->hash_entry->symbol));
2566     }
2567   else if (num_static_defs > 1)
2568     {
2569       notice ("%s: multiple static defs of `%s' in file `%s'\n",
2570               pname, head->hash_entry->symbol,
2571               shortpath (NULL, user->file->hash_entry->symbol));
2572       return NULL;
2573     }
2574   return static_def_p;
2575 }
2576
2577 /* Find good prototype style formal argument lists for all of the function
2578    declarations which didn't have them before now.
2579
2580    To do this we consider each function name one at a time.  For each function
2581    name, we look at the items on the linked list of def_dec_info records for
2582    that particular name.
2583
2584    Somewhere on this list we should find one (and only one) def_dec_info
2585    record which represents the actual function definition, and this record
2586    should have a nice formal argument list already associated with it.
2587
2588    Thus, all we have to do is to connect up all of the other def_dec_info
2589    records for this particular function name to the special one which has
2590    the full-blown formals list.
2591
2592    Of course it is a little more complicated than just that.  See below for
2593    more details.  */
2594
2595 static void
2596 connect_defs_and_decs (const hash_table_entry *hp)
2597 {
2598   const def_dec_info *dd_p;
2599   const def_dec_info *extern_def_p = NULL;
2600   int first_extern_reference = 1;
2601
2602   /* Traverse the list of definitions and declarations for this particular
2603      function name.  For each item on the list, if it is a function
2604      definition (either old style or new style) then GCC has already been
2605      kind enough to produce a prototype for us, and it is associated with
2606      the item already, so declare the item as its own associated "definition".
2607
2608      Also, for each item which is only a function declaration, but which
2609      nonetheless has its own prototype already (obviously supplied by the user)
2610      declare the item as its own definition.
2611
2612      Note that when/if there are multiple user-supplied prototypes already
2613      present for multiple declarations of any given function, these multiple
2614      prototypes *should* all match exactly with one another and with the
2615      prototype for the actual function definition.  We don't check for this
2616      here however, since we assume that the compiler must have already done
2617      this consistency checking when it was creating the .X files.  */
2618
2619   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2620     if (dd_p->prototyped)
2621       ((NONCONST def_dec_info *) dd_p)->definition = dd_p;
2622
2623   /* Traverse the list of definitions and declarations for this particular
2624      function name.  For each item on the list, if it is an extern function
2625      declaration and if it has no associated definition yet, go try to find
2626      the matching extern definition for the declaration.
2627
2628      When looking for the matching function definition, warn the user if we
2629      fail to find one.
2630
2631      If we find more that one function definition also issue a warning.
2632
2633      Do the search for the matching definition only once per unique function
2634      name (and only when absolutely needed) so that we can avoid putting out
2635      redundant warning messages, and so that we will only put out warning
2636      messages when there is actually a reference (i.e. a declaration) for
2637      which we need to find a matching definition.  */
2638
2639   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2640     if (!dd_p->is_func_def && !dd_p->is_static && !dd_p->definition)
2641       {
2642         if (first_extern_reference)
2643           {
2644             extern_def_p = find_extern_def (hp->ddip, dd_p);
2645             first_extern_reference = 0;
2646           }
2647         ((NONCONST def_dec_info *) dd_p)->definition = extern_def_p;
2648       }
2649
2650   /* Traverse the list of definitions and declarations for this particular
2651      function name.  For each item on the list, if it is a static function
2652      declaration and if it has no associated definition yet, go try to find
2653      the matching static definition for the declaration within the same file.
2654
2655      When looking for the matching function definition, warn the user if we
2656      fail to find one in the same file with the declaration, and refuse to
2657      convert this kind of cross-file static function declaration.  After all,
2658      this is stupid practice and should be discouraged.
2659
2660      We don't have to worry about the possibility that there is more than one
2661      matching function definition in the given file because that would have
2662      been flagged as an error by the compiler.
2663
2664      Do the search for the matching definition only once per unique
2665      function-name/source-file pair (and only when absolutely needed) so that
2666      we can avoid putting out redundant warning messages, and so that we will
2667      only put out warning messages when there is actually a reference (i.e. a
2668      declaration) for which we actually need to find a matching definition.  */
2669
2670   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2671     if (!dd_p->is_func_def && dd_p->is_static && !dd_p->definition)
2672       {
2673         const def_dec_info *dd_p2;
2674         const def_dec_info *static_def;
2675
2676         /* We have now found a single static declaration for which we need to
2677            find a matching definition.  We want to minimize the work (and the
2678            number of warnings), so we will find an appropriate (matching)
2679            static definition for this declaration, and then distribute it
2680            (as the definition for) any and all other static declarations
2681            for this function name which occur within the same file, and which
2682            do not already have definitions.
2683
2684            Note that a trick is used here to prevent subsequent attempts to
2685            call find_static_definition for a given function-name & file
2686            if the first such call returns NULL.  Essentially, we convert
2687            these NULL return values to -1, and put the -1 into the definition
2688            field for each other static declaration from the same file which
2689            does not already have an associated definition.
2690            This makes these other static declarations look like they are
2691            actually defined already when the outer loop here revisits them
2692            later on.  Thus, the outer loop will skip over them.  Later, we
2693            turn the -1's back to NULL's.  */
2694
2695         ((NONCONST def_dec_info *) dd_p)->definition =
2696           (static_def = find_static_definition (dd_p))
2697           ? static_def
2698           : (const def_dec_info *) -1;
2699
2700         for (dd_p2 = dd_p->next_for_func; dd_p2; dd_p2 = dd_p2->next_for_func)
2701           if (!dd_p2->is_func_def && dd_p2->is_static
2702               && !dd_p2->definition && (dd_p2->file == dd_p->file))
2703             ((NONCONST def_dec_info *) dd_p2)->definition = dd_p->definition;
2704       }
2705
2706   /* Convert any dummy (-1) definitions we created in the step above back to
2707      NULL's (as they should be).  */
2708
2709   for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2710     if (dd_p->definition == (def_dec_info *) -1)
2711       ((NONCONST def_dec_info *) dd_p)->definition = NULL;
2712 }
2713
2714 #endif /* !defined (UNPROTOIZE) */
2715
2716 /* Give a pointer into the clean text buffer, return a number which is the
2717    original source line number that the given pointer points into.  */
2718
2719 static int
2720 identify_lineno (const char *clean_p)
2721 {
2722   int line_num = 1;
2723   const char *scan_p;
2724
2725   for (scan_p = clean_text_base; scan_p <= clean_p; scan_p++)
2726     if (*scan_p == '\n')
2727       line_num++;
2728   return line_num;
2729 }
2730
2731 /* Issue an error message and give up on doing this particular edit.  */
2732
2733 static void
2734 declare_source_confusing (const char *clean_p)
2735 {
2736   if (!quiet_flag)
2737     {
2738       if (clean_p == 0)
2739         notice ("%s: %d: warning: source too confusing\n",
2740                 shortpath (NULL, convert_filename), last_known_line_number);
2741       else
2742         notice ("%s: %d: warning: source too confusing\n",
2743                 shortpath (NULL, convert_filename),
2744                 identify_lineno (clean_p));
2745     }
2746   longjmp (source_confusion_recovery, 1);
2747 }
2748
2749 /* Check that a condition which is expected to be true in the original source
2750    code is in fact true.  If not, issue an error message and give up on
2751    converting this particular source file.  */
2752
2753 static void
2754 check_source (int cond, const char *clean_p)
2755 {
2756   if (!cond)
2757     declare_source_confusing (clean_p);
2758 }
2759
2760 /* If we think of the in-core cleaned text buffer as a memory mapped
2761    file (with the variable last_known_line_start acting as sort of a
2762    file pointer) then we can imagine doing "seeks" on the buffer.  The
2763    following routine implements a kind of "seek" operation for the in-core
2764    (cleaned) copy of the source file.  When finished, it returns a pointer to
2765    the start of a given (numbered) line in the cleaned text buffer.
2766
2767    Note that protoize only has to "seek" in the forward direction on the
2768    in-core cleaned text file buffers, and it never needs to back up.
2769
2770    This routine is made a little bit faster by remembering the line number
2771    (and pointer value) supplied (and returned) from the previous "seek".
2772    This prevents us from always having to start all over back at the top
2773    of the in-core cleaned buffer again.  */
2774
2775 static const char *
2776 seek_to_line (int n)
2777 {
2778   if (n < last_known_line_number)
2779     abort ();
2780
2781   while (n > last_known_line_number)
2782     {
2783       while (*last_known_line_start != '\n')
2784         check_source (++last_known_line_start < clean_text_limit, 0);
2785       last_known_line_start++;
2786       last_known_line_number++;
2787     }
2788   return last_known_line_start;
2789 }
2790
2791 /* Given a pointer to a character in the cleaned text buffer, return a pointer
2792    to the next non-whitespace character which follows it.  */
2793
2794 static const char *
2795 forward_to_next_token_char (const char *ptr)
2796 {
2797   for (++ptr; ISSPACE ((const unsigned char)*ptr);
2798        check_source (++ptr < clean_text_limit, 0))
2799     continue;
2800   return ptr;
2801 }
2802
2803 /* Copy a chunk of text of length `len' and starting at `str' to the current
2804    output buffer.  Note that all attempts to add stuff to the current output
2805    buffer ultimately go through here.  */
2806
2807 static void
2808 output_bytes (const char *str, size_t len)
2809 {
2810   if ((repl_write_ptr + 1) + len >= repl_text_limit)
2811     {
2812       size_t new_size = (repl_text_limit - repl_text_base) << 1;
2813       char *new_buf = xrealloc (repl_text_base, new_size);
2814
2815       repl_write_ptr = new_buf + (repl_write_ptr - repl_text_base);
2816       repl_text_base = new_buf;
2817       repl_text_limit = new_buf + new_size;
2818     }
2819   memcpy (repl_write_ptr + 1, str, len);
2820   repl_write_ptr += len;
2821 }
2822
2823 /* Copy all bytes (except the trailing null) of a null terminated string to
2824    the current output buffer.  */
2825
2826 static void
2827 output_string (const char *str)
2828 {
2829   output_bytes (str, strlen (str));
2830 }
2831
2832 /* Copy some characters from the original text buffer to the current output
2833    buffer.
2834
2835    This routine takes a pointer argument `p' which is assumed to be a pointer
2836    into the cleaned text buffer.  The bytes which are copied are the `original'
2837    equivalents for the set of bytes between the last value of `clean_read_ptr'
2838    and the argument value `p'.
2839
2840    The set of bytes copied however, comes *not* from the cleaned text buffer,
2841    but rather from the direct counterparts of these bytes within the original
2842    text buffer.
2843
2844    Thus, when this function is called, some bytes from the original text
2845    buffer (which may include original comments and preprocessing directives)
2846    will be copied into the  output buffer.
2847
2848    Note that the request implied when this routine is called includes the
2849    byte pointed to by the argument pointer `p'.  */
2850
2851 static void
2852 output_up_to (const char *p)
2853 {
2854   size_t copy_length = (size_t) (p - clean_read_ptr);
2855   const char *copy_start = orig_text_base+(clean_read_ptr-clean_text_base)+1;
2856
2857   if (copy_length == 0)
2858     return;
2859
2860   output_bytes (copy_start, copy_length);
2861   clean_read_ptr = p;
2862 }
2863
2864 /* Given a pointer to a def_dec_info record which represents some form of
2865    definition of a function (perhaps a real definition, or in lieu of that
2866    perhaps just a declaration with a full prototype) return true if this
2867    function is one which we should avoid converting.  Return false
2868    otherwise.  */
2869
2870 static int
2871 other_variable_style_function (const char *ansi_header)
2872 {
2873 #ifdef UNPROTOIZE
2874
2875   /* See if we have a stdarg function, or a function which has stdarg style
2876      parameters or a stdarg style return type.  */
2877
2878   return substr (ansi_header, "...") != 0;
2879
2880 #else /* !defined (UNPROTOIZE) */
2881
2882   /* See if we have a varargs function, or a function which has varargs style
2883      parameters or a varargs style return type.  */
2884
2885   const char *p;
2886   int len = strlen (varargs_style_indicator);
2887
2888   for (p = ansi_header; p; )
2889     {
2890       const char *candidate;
2891
2892       if ((candidate = substr (p, varargs_style_indicator)) == 0)
2893         return 0;
2894       else
2895         if (!is_id_char (candidate[-1]) && !is_id_char (candidate[len]))
2896           return 1;
2897         else
2898           p = candidate + 1;
2899     }
2900   return 0;
2901 #endif /* !defined (UNPROTOIZE) */
2902 }
2903
2904 /* Do the editing operation specifically for a function "declaration".  Note
2905    that editing for function "definitions" are handled in a separate routine
2906    below.  */
2907
2908 static void
2909 edit_fn_declaration (const def_dec_info *def_dec_p,
2910                      const char *volatile clean_text_p)
2911 {
2912   const char *start_formals;
2913   const char *end_formals;
2914   const char *function_to_edit = def_dec_p->hash_entry->symbol;
2915   size_t func_name_len = strlen (function_to_edit);
2916   const char *end_of_fn_name;
2917
2918 #ifndef UNPROTOIZE
2919
2920   const f_list_chain_item *this_f_list_chain_item;
2921   const def_dec_info *definition = def_dec_p->definition;
2922
2923   /* If we are protoizing, and if we found no corresponding definition for
2924      this particular function declaration, then just leave this declaration
2925      exactly as it is.  */
2926
2927   if (!definition)
2928     return;
2929
2930   /* If we are protoizing, and if the corresponding definition that we found
2931      for this particular function declaration defined an old style varargs
2932      function, then we want to issue a warning and just leave this function
2933      declaration unconverted.  */
2934
2935   if (other_variable_style_function (definition->ansi_decl))
2936     {
2937       if (!quiet_flag)
2938         notice ("%s: %d: warning: varargs function declaration not converted\n",
2939                 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
2940                 def_dec_p->line);
2941       return;
2942     }
2943
2944 #endif /* !defined (UNPROTOIZE) */
2945
2946   /* Setup here to recover from confusing source code detected during this
2947      particular "edit".  */
2948
2949   save_pointers ();
2950   if (setjmp (source_confusion_recovery))
2951     {
2952       restore_pointers ();
2953       notice ("%s: declaration of function `%s' not converted\n",
2954               pname, function_to_edit);
2955       return;
2956     }
2957
2958   /* We are editing a function declaration.  The line number we did a seek to
2959      contains the comma or semicolon which follows the declaration.  Our job
2960      now is to scan backwards looking for the function name.  This name *must*
2961      be followed by open paren (ignoring whitespace, of course).  We need to
2962      replace everything between that open paren and the corresponding closing
2963      paren.  If we are protoizing, we need to insert the prototype-style
2964      formals lists.  If we are unprotoizing, we need to just delete everything
2965      between the pairs of opening and closing parens.  */
2966
2967   /* First move up to the end of the line.  */
2968
2969   while (*clean_text_p != '\n')
2970     check_source (++clean_text_p < clean_text_limit, 0);
2971   clean_text_p--;  /* Point to just before the newline character.  */
2972
2973   /* Now we can scan backwards for the function name.  */
2974
2975   do
2976     {
2977       for (;;)
2978         {
2979           /* Scan leftwards until we find some character which can be
2980              part of an identifier.  */
2981
2982           while (!is_id_char (*clean_text_p))
2983             check_source (--clean_text_p > clean_read_ptr, 0);
2984
2985           /* Scan backwards until we find a char that cannot be part of an
2986              identifier.  */
2987
2988           while (is_id_char (*clean_text_p))
2989             check_source (--clean_text_p > clean_read_ptr, 0);
2990
2991           /* Having found an "id break", see if the following id is the one
2992              that we are looking for.  If so, then exit from this loop.  */
2993
2994           if (!strncmp (clean_text_p+1, function_to_edit, func_name_len))
2995             {
2996               char ch = *(clean_text_p + 1 + func_name_len);
2997
2998               /* Must also check to see that the name in the source text
2999                  ends where it should (in order to prevent bogus matches
3000                  on similar but longer identifiers.  */
3001
3002               if (! is_id_char (ch))
3003                 break;                  /* exit from loop */
3004             }
3005         }
3006
3007       /* We have now found the first perfect match for the function name in
3008          our backward search.  This may or may not be the actual function
3009          name at the start of the actual function declaration (i.e. we could
3010          have easily been mislead).  We will try to avoid getting fooled too
3011          often by looking forward for the open paren which should follow the
3012          identifier we just found.  We ignore whitespace while hunting.  If
3013          the next non-whitespace byte we see is *not* an open left paren,
3014          then we must assume that we have been fooled and we start over
3015          again accordingly.  Note that there is no guarantee, that even if
3016          we do see the open paren, that we are in the right place.
3017          Programmers do the strangest things sometimes!  */
3018
3019       end_of_fn_name = clean_text_p + strlen (def_dec_p->hash_entry->symbol);
3020       start_formals = forward_to_next_token_char (end_of_fn_name);
3021     }
3022   while (*start_formals != '(');
3023
3024   /* start_of_formals now points to the opening left paren which immediately
3025      follows the name of the function.  */
3026
3027   /* Note that there may be several formals lists which need to be modified
3028      due to the possibility that the return type of this function is a
3029      pointer-to-function type.  If there are several formals lists, we
3030      convert them in left-to-right order here.  */
3031
3032 #ifndef UNPROTOIZE
3033   this_f_list_chain_item = definition->f_list_chain;
3034 #endif /* !defined (UNPROTOIZE) */
3035
3036   for (;;)
3037     {
3038       {
3039         int depth;
3040
3041         end_formals = start_formals + 1;
3042         depth = 1;
3043         for (; depth; check_source (++end_formals < clean_text_limit, 0))
3044           {
3045             switch (*end_formals)
3046               {
3047               case '(':
3048                 depth++;
3049                 break;
3050               case ')':
3051                 depth--;
3052                 break;
3053               }
3054           }
3055         end_formals--;
3056       }
3057
3058       /* end_formals now points to the closing right paren of the formals
3059          list whose left paren is pointed to by start_formals.  */
3060
3061       /* Now, if we are protoizing, we insert the new ANSI-style formals list
3062          attached to the associated definition of this function.  If however
3063          we are unprotoizing, then we simply delete any formals list which
3064          may be present.  */
3065
3066       output_up_to (start_formals);
3067 #ifndef UNPROTOIZE
3068       if (this_f_list_chain_item)
3069         {
3070           output_string (this_f_list_chain_item->formals_list);
3071           this_f_list_chain_item = this_f_list_chain_item->chain_next;
3072         }
3073       else
3074         {
3075           if (!quiet_flag)
3076             notice ("%s: warning: too many parameter lists in declaration of `%s'\n",
3077                     pname, def_dec_p->hash_entry->symbol);
3078           check_source (0, end_formals);  /* leave the declaration intact */
3079         }
3080 #endif /* !defined (UNPROTOIZE) */
3081       clean_read_ptr = end_formals - 1;
3082
3083       /* Now see if it looks like there may be another formals list associated
3084          with the function declaration that we are converting (following the
3085          formals list that we just converted.  */
3086
3087       {
3088         const char *another_r_paren = forward_to_next_token_char (end_formals);
3089
3090         if ((*another_r_paren != ')')
3091             || (*(start_formals = forward_to_next_token_char (another_r_paren)) != '('))
3092           {
3093 #ifndef UNPROTOIZE
3094             if (this_f_list_chain_item)
3095               {
3096                 if (!quiet_flag)
3097                   notice ("\n%s: warning: too few parameter lists in declaration of `%s'\n",
3098                           pname, def_dec_p->hash_entry->symbol);
3099                 check_source (0, start_formals); /* leave the decl intact */
3100               }
3101 #endif /* !defined (UNPROTOIZE) */
3102             break;
3103
3104           }
3105       }
3106
3107       /* There does appear to be yet another formals list, so loop around
3108          again, and convert it also.  */
3109     }
3110 }
3111
3112 /* Edit a whole group of formals lists, starting with the rightmost one
3113    from some set of formals lists.  This routine is called once (from the
3114    outside) for each function declaration which is converted.  It is
3115    recursive however, and it calls itself once for each remaining formal
3116    list that lies to the left of the one it was originally called to work
3117    on.  Thus, a whole set gets done in right-to-left order.
3118
3119    This routine returns nonzero if it thinks that it should not be trying
3120    to convert this particular function definition (because the name of the
3121    function doesn't match the one expected).  */
3122
3123 static int
3124 edit_formals_lists (const char *end_formals, unsigned int f_list_count,
3125                     const def_dec_info *def_dec_p)
3126 {
3127   const char *start_formals;
3128   int depth;
3129
3130   start_formals = end_formals - 1;
3131   depth = 1;
3132   for (; depth; check_source (--start_formals > clean_read_ptr, 0))
3133     {
3134       switch (*start_formals)
3135         {
3136         case '(':
3137           depth--;
3138           break;
3139         case ')':
3140           depth++;
3141           break;
3142         }
3143     }
3144   start_formals++;
3145
3146   /* start_formals now points to the opening left paren of the formals list.  */
3147
3148   f_list_count--;
3149
3150   if (f_list_count)
3151     {
3152       const char *next_end;
3153
3154       /* There should be more formal lists to the left of here.  */
3155
3156       next_end = start_formals - 1;
3157       check_source (next_end > clean_read_ptr, 0);
3158       while (ISSPACE ((const unsigned char)*next_end))
3159         check_source (--next_end > clean_read_ptr, 0);
3160       check_source (*next_end == ')', next_end);
3161       check_source (--next_end > clean_read_ptr, 0);
3162       check_source (*next_end == ')', next_end);
3163       if (edit_formals_lists (next_end, f_list_count, def_dec_p))
3164         return 1;
3165     }
3166
3167   /* Check that the function name in the header we are working on is the same
3168      as the one we would expect to find.  If not, issue a warning and return
3169      nonzero.  */
3170
3171   if (f_list_count == 0)
3172     {
3173       const char *expected = def_dec_p->hash_entry->symbol;
3174       const char *func_name_start;
3175       const char *func_name_limit;
3176       size_t func_name_len;
3177
3178       for (func_name_limit = start_formals-1;
3179            ISSPACE ((const unsigned char)*func_name_limit); )
3180         check_source (--func_name_limit > clean_read_ptr, 0);
3181
3182       for (func_name_start = func_name_limit++;
3183            is_id_char (*func_name_start);
3184            func_name_start--)
3185         check_source (func_name_start > clean_read_ptr, 0);
3186       func_name_start++;
3187       func_name_len = func_name_limit - func_name_start;
3188       if (func_name_len == 0)
3189         check_source (0, func_name_start);
3190       if (func_name_len != strlen (expected)
3191           || strncmp (func_name_start, expected, func_name_len))
3192         {
3193           notice ("%s: %d: warning: found `%s' but expected `%s'\n",
3194                   shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3195                   identify_lineno (func_name_start),
3196                   dupnstr (func_name_start, func_name_len),
3197                   expected);
3198           return 1;
3199         }
3200     }
3201
3202   output_up_to (start_formals);
3203
3204 #ifdef UNPROTOIZE
3205   if (f_list_count == 0)
3206     output_string (def_dec_p->formal_names);
3207 #else /* !defined (UNPROTOIZE) */
3208   {
3209     unsigned f_list_depth;
3210     const f_list_chain_item *flci_p = def_dec_p->f_list_chain;
3211
3212     /* At this point, the current value of f_list count says how many
3213        links we have to follow through the f_list_chain to get to the
3214        particular formals list that we need to output next.  */
3215
3216     for (f_list_depth = 0; f_list_depth < f_list_count; f_list_depth++)
3217       flci_p = flci_p->chain_next;
3218     output_string (flci_p->formals_list);
3219   }
3220 #endif /* !defined (UNPROTOIZE) */
3221
3222   clean_read_ptr = end_formals - 1;
3223   return 0;
3224 }
3225
3226 /* Given a pointer to a byte in the clean text buffer which points to
3227    the beginning of a line that contains a "follower" token for a
3228    function definition header, do whatever is necessary to find the
3229    right closing paren for the rightmost formals list of the function
3230    definition header.  */
3231
3232 static const char *
3233 find_rightmost_formals_list (const char *clean_text_p)
3234 {
3235   const char *end_formals;
3236
3237   /* We are editing a function definition.  The line number we did a seek
3238      to contains the first token which immediately follows the entire set of
3239      formals lists which are part of this particular function definition
3240      header.
3241
3242      Our job now is to scan leftwards in the clean text looking for the
3243      right-paren which is at the end of the function header's rightmost
3244      formals list.
3245
3246      If we ignore whitespace, this right paren should be the first one we
3247      see which is (ignoring whitespace) immediately followed either by the
3248      open curly-brace beginning the function body or by an alphabetic
3249      character (in the case where the function definition is in old (K&R)
3250      style and there are some declarations of formal parameters).  */
3251
3252    /* It is possible that the right paren we are looking for is on the
3253       current line (together with its following token).  Just in case that
3254       might be true, we start out here by skipping down to the right end of
3255       the current line before starting our scan.  */
3256
3257   for (end_formals = clean_text_p; *end_formals != '\n'; end_formals++)
3258     continue;
3259   end_formals--;
3260
3261 #ifdef UNPROTOIZE
3262
3263   /* Now scan backwards while looking for the right end of the rightmost
3264      formals list associated with this function definition.  */
3265
3266   {
3267     char ch;
3268     const char *l_brace_p;
3269
3270     /* Look leftward and try to find a right-paren.  */
3271
3272     while (*end_formals != ')')
3273       {
3274         if (ISSPACE ((unsigned char)*end_formals))
3275           while (ISSPACE ((unsigned char)*end_formals))
3276             check_source (--end_formals > clean_read_ptr, 0);
3277         else
3278           check_source (--end_formals > clean_read_ptr, 0);
3279       }
3280
3281     ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3282     /* Since we are unprotoizing an ANSI-style (prototyped) function
3283        definition, there had better not be anything (except whitespace)
3284        between the end of the ANSI formals list and the beginning of the
3285        function body (i.e. the '{').  */
3286
3287     check_source (ch == '{', l_brace_p);
3288   }
3289
3290 #else /* !defined (UNPROTOIZE) */
3291
3292   /* Now scan backwards while looking for the right end of the rightmost
3293      formals list associated with this function definition.  */
3294
3295   while (1)
3296     {
3297       char ch;
3298       const char *l_brace_p;
3299
3300       /* Look leftward and try to find a right-paren.  */
3301
3302       while (*end_formals != ')')
3303         {
3304           if (ISSPACE ((const unsigned char)*end_formals))
3305             while (ISSPACE ((const unsigned char)*end_formals))
3306               check_source (--end_formals > clean_read_ptr, 0);
3307           else
3308             check_source (--end_formals > clean_read_ptr, 0);
3309         }
3310
3311       ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3312
3313       /* Since it is possible that we found a right paren before the starting
3314          '{' of the body which IS NOT the one at the end of the real K&R
3315          formals list (say for instance, we found one embedded inside one of
3316          the old K&R formal parameter declarations) we have to check to be
3317          sure that this is in fact the right paren that we were looking for.
3318
3319          The one we were looking for *must* be followed by either a '{' or
3320          by an alphabetic character, while others *cannot* validly be followed
3321          by such characters.  */
3322
3323       if ((ch == '{') || ISALPHA ((unsigned char) ch))
3324         break;
3325
3326       /* At this point, we have found a right paren, but we know that it is
3327          not the one we were looking for, so backup one character and keep
3328          looking.  */
3329
3330       check_source (--end_formals > clean_read_ptr, 0);
3331     }
3332
3333 #endif /* !defined (UNPROTOIZE) */
3334
3335   return end_formals;
3336 }
3337
3338 #ifndef UNPROTOIZE
3339
3340 /* Insert into the output file a totally new declaration for a function
3341    which (up until now) was being called from within the current block
3342    without having been declared at any point such that the declaration
3343    was visible (i.e. in scope) at the point of the call.
3344
3345    We need to add in explicit declarations for all such function calls
3346    in order to get the full benefit of prototype-based function call
3347    parameter type checking.  */
3348
3349 static void
3350 add_local_decl (const def_dec_info *def_dec_p, const char *clean_text_p)
3351 {
3352   const char *start_of_block;
3353   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3354
3355   /* Don't insert new local explicit declarations unless explicitly requested
3356      to do so.  */
3357
3358   if (!local_flag)
3359     return;
3360
3361   /* Setup here to recover from confusing source code detected during this
3362      particular "edit".  */
3363
3364   save_pointers ();
3365   if (setjmp (source_confusion_recovery))
3366     {
3367       restore_pointers ();
3368       notice ("%s: local declaration for function `%s' not inserted\n",
3369               pname, function_to_edit);
3370       return;
3371     }
3372
3373   /* We have already done a seek to the start of the line which should
3374      contain *the* open curly brace which begins the block in which we need
3375      to insert an explicit function declaration (to replace the implicit one).
3376
3377      Now we scan that line, starting from the left, until we find the
3378      open curly brace we are looking for.  Note that there may actually be
3379      multiple open curly braces on the given line, but we will be happy
3380      with the leftmost one no matter what.  */
3381
3382   start_of_block = clean_text_p;
3383   while (*start_of_block != '{' && *start_of_block != '\n')
3384     check_source (++start_of_block < clean_text_limit, 0);
3385
3386   /* Note that the line from the original source could possibly
3387      contain *no* open curly braces!  This happens if the line contains
3388      a macro call which expands into a chunk of text which includes a
3389      block (and that block's associated open and close curly braces).
3390      In cases like this, we give up, issue a warning, and do nothing.  */
3391
3392   if (*start_of_block != '{')
3393     {
3394       if (!quiet_flag)
3395         notice ("\n%s: %d: warning: can't add declaration of `%s' into macro call\n",
3396           def_dec_p->file->hash_entry->symbol, def_dec_p->line,
3397           def_dec_p->hash_entry->symbol);
3398       return;
3399     }
3400
3401   /* Figure out what a nice (pretty) indentation would be for the new
3402      declaration we are adding.  In order to do this, we must scan forward
3403      from the '{' until we find the first line which starts with some
3404      non-whitespace characters (i.e. real "token" material).  */
3405
3406   {
3407     const char *ep = forward_to_next_token_char (start_of_block) - 1;
3408     const char *sp;
3409
3410     /* Now we have ep pointing at the rightmost byte of some existing indent
3411        stuff.  At least that is the hope.
3412
3413        We can now just scan backwards and find the left end of the existing
3414        indentation string, and then copy it to the output buffer.  */
3415
3416     for (sp = ep; ISSPACE ((const unsigned char)*sp) && *sp != '\n'; sp--)
3417       continue;
3418
3419     /* Now write out the open { which began this block, and any following
3420        trash up to and including the last byte of the existing indent that
3421        we just found.  */
3422
3423     output_up_to (ep);
3424
3425     /* Now we go ahead and insert the new declaration at this point.
3426
3427        If the definition of the given function is in the same file that we
3428        are currently editing, and if its full ANSI declaration normally
3429        would start with the keyword `extern', suppress the `extern'.  */
3430
3431     {
3432       const char *decl = def_dec_p->definition->ansi_decl;
3433
3434       if ((*decl == 'e') && (def_dec_p->file == def_dec_p->definition->file))
3435         decl += 7;
3436       output_string (decl);
3437     }
3438
3439     /* Finally, write out a new indent string, just like the preceding one
3440        that we found.  This will typically include a newline as the first
3441        character of the indent string.  */
3442
3443     output_bytes (sp, (size_t) (ep - sp) + 1);
3444   }
3445 }
3446
3447 /* Given a pointer to a file_info record, and a pointer to the beginning
3448    of a line (in the clean text buffer) which is assumed to contain the
3449    first "follower" token for the first function definition header in the
3450    given file, find a good place to insert some new global function
3451    declarations (which will replace scattered and imprecise implicit ones)
3452    and then insert the new explicit declaration at that point in the file.  */
3453
3454 static void
3455 add_global_decls (const file_info *file_p, const char *clean_text_p)
3456 {
3457   const def_dec_info *dd_p;
3458   const char *scan_p;
3459
3460   /* Setup here to recover from confusing source code detected during this
3461      particular "edit".  */
3462
3463   save_pointers ();
3464   if (setjmp (source_confusion_recovery))
3465     {
3466       restore_pointers ();
3467       notice ("%s: global declarations for file `%s' not inserted\n",
3468               pname, shortpath (NULL, file_p->hash_entry->symbol));
3469       return;
3470     }
3471
3472   /* Start by finding a good location for adding the new explicit function
3473      declarations.  To do this, we scan backwards, ignoring whitespace
3474      and comments and other junk until we find either a semicolon, or until
3475      we hit the beginning of the file.  */
3476
3477   scan_p = find_rightmost_formals_list (clean_text_p);
3478   for (;; --scan_p)
3479     {
3480       if (scan_p < clean_text_base)
3481         break;
3482       check_source (scan_p > clean_read_ptr, 0);
3483       if (*scan_p == ';')
3484         break;
3485     }
3486
3487   /* scan_p now points either to a semicolon, or to just before the start
3488      of the whole file.  */
3489
3490   /* Now scan forward for the first non-whitespace character.  In theory,
3491      this should be the first character of the following function definition
3492      header.  We will put in the added declarations just prior to that.  */
3493
3494   scan_p++;
3495   while (ISSPACE ((const unsigned char)*scan_p))
3496     scan_p++;
3497   scan_p--;
3498
3499   output_up_to (scan_p);
3500
3501   /* Now write out full prototypes for all of the things that had been
3502      implicitly declared in this file (but only those for which we were
3503      actually able to find unique matching definitions).  Avoid duplicates
3504      by marking things that we write out as we go.  */
3505
3506   {
3507     int some_decls_added = 0;
3508
3509     for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3510       if (dd_p->is_implicit && dd_p->definition && !dd_p->definition->written)
3511         {
3512           const char *decl = dd_p->definition->ansi_decl;
3513
3514           /* If the function for which we are inserting a declaration is
3515              actually defined later in the same file, then suppress the
3516              leading `extern' keyword (if there is one).  */
3517
3518           if (*decl == 'e' && (dd_p->file == dd_p->definition->file))
3519             decl += 7;
3520
3521           output_string ("\n");
3522           output_string (decl);
3523           some_decls_added = 1;
3524           ((NONCONST def_dec_info *) dd_p->definition)->written = 1;
3525         }
3526     if (some_decls_added)
3527       output_string ("\n\n");
3528   }
3529
3530   /* Unmark all of the definitions that we just marked.  */
3531
3532   for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3533     if (dd_p->definition)
3534       ((NONCONST def_dec_info *) dd_p->definition)->written = 0;
3535 }
3536
3537 #endif /* !defined (UNPROTOIZE) */
3538
3539 /* Do the editing operation specifically for a function "definition".  Note
3540    that editing operations for function "declarations" are handled by a
3541    separate routine above.  */
3542
3543 static void
3544 edit_fn_definition (const def_dec_info *def_dec_p, const char *clean_text_p)
3545 {
3546   const char *end_formals;
3547   const char *function_to_edit = def_dec_p->hash_entry->symbol;
3548
3549   /* Setup here to recover from confusing source code detected during this
3550      particular "edit".  */
3551
3552   save_pointers ();
3553   if (setjmp (source_confusion_recovery))
3554     {
3555       restore_pointers ();
3556       notice ("%s: definition of function `%s' not converted\n",
3557               pname, function_to_edit);
3558       return;
3559     }
3560
3561   end_formals = find_rightmost_formals_list (clean_text_p);
3562
3563   /* end_of_formals now points to the closing right paren of the rightmost
3564      formals list which is actually part of the `header' of the function
3565      definition that we are converting.  */
3566
3567   /* If the header of this function definition looks like it declares a
3568      function with a variable number of arguments, and if the way it does
3569      that is different from that way we would like it (i.e. varargs vs.
3570      stdarg) then issue a warning and leave the header unconverted.  */
3571
3572   if (other_variable_style_function (def_dec_p->ansi_decl))
3573     {
3574       if (!quiet_flag)
3575         notice ("%s: %d: warning: definition of %s not converted\n",
3576                 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3577                 identify_lineno (end_formals),
3578                 other_var_style);
3579       output_up_to (end_formals);
3580       return;
3581     }
3582
3583   if (edit_formals_lists (end_formals, def_dec_p->f_list_count, def_dec_p))
3584     {
3585       restore_pointers ();
3586       notice ("%s: definition of function `%s' not converted\n",
3587               pname, function_to_edit);
3588       return;
3589     }
3590
3591   /* Have to output the last right paren because this never gets flushed by
3592      edit_formals_list.  */
3593
3594   output_up_to (end_formals);
3595
3596 #ifdef UNPROTOIZE
3597   {
3598     const char *decl_p;
3599     const char *semicolon_p;
3600     const char *limit_p;
3601     const char *scan_p;
3602     int had_newlines = 0;
3603
3604     /* Now write out the K&R style formal declarations, one per line.  */
3605
3606     decl_p = def_dec_p->formal_decls;
3607     limit_p = decl_p + strlen (decl_p);
3608     for (;decl_p < limit_p; decl_p = semicolon_p + 2)
3609       {
3610         for (semicolon_p = decl_p; *semicolon_p != ';'; semicolon_p++)
3611           continue;
3612         output_string ("\n");
3613         output_string (indent_string);
3614         output_bytes (decl_p, (size_t) ((semicolon_p + 1) - decl_p));
3615       }
3616
3617     /* If there are no newlines between the end of the formals list and the
3618        start of the body, we should insert one now.  */
3619
3620     for (scan_p = end_formals+1; *scan_p != '{'; )
3621       {
3622         if (*scan_p == '\n')
3623           {
3624             had_newlines = 1;
3625             break;
3626           }
3627         check_source (++scan_p < clean_text_limit, 0);
3628       }
3629     if (!had_newlines)
3630       output_string ("\n");
3631   }
3632 #else /* !defined (UNPROTOIZE) */
3633   /* If we are protoizing, there may be some flotsam & jetsam (like comments
3634      and preprocessing directives) after the old formals list but before
3635      the following { and we would like to preserve that stuff while effectively
3636      deleting the existing K&R formal parameter declarations.  We do so here
3637      in a rather tricky way.  Basically, we white out any stuff *except*
3638      the comments/pp-directives in the original text buffer, then, if there
3639      is anything in this area *other* than whitespace, we output it.  */
3640   {
3641     const char *end_formals_orig;
3642     const char *start_body;
3643     const char *start_body_orig;
3644     const char *scan;
3645     const char *scan_orig;
3646     int have_flotsam = 0;
3647     int have_newlines = 0;
3648
3649     for (start_body = end_formals + 1; *start_body != '{';)
3650       check_source (++start_body < clean_text_limit, 0);
3651
3652     end_formals_orig = orig_text_base + (end_formals - clean_text_base);
3653     start_body_orig = orig_text_base + (start_body - clean_text_base);
3654     scan = end_formals + 1;
3655     scan_orig = end_formals_orig + 1;
3656     for (; scan < start_body; scan++, scan_orig++)
3657       {
3658         if (*scan == *scan_orig)
3659           {
3660             have_newlines |= (*scan_orig == '\n');
3661             /* Leave identical whitespace alone.  */
3662             if (!ISSPACE ((const unsigned char)*scan_orig))
3663               *((NONCONST char *) scan_orig) = ' '; /* identical - so whiteout */
3664           }
3665         else
3666           have_flotsam = 1;
3667       }
3668     if (have_flotsam)
3669       output_bytes (end_formals_orig + 1,
3670                     (size_t) (start_body_orig - end_formals_orig) - 1);
3671     else
3672       if (have_newlines)
3673         output_string ("\n");
3674       else
3675         output_string (" ");
3676     clean_read_ptr = start_body - 1;
3677   }
3678 #endif /* !defined (UNPROTOIZE) */
3679 }
3680
3681 /* Clean up the clean text buffer.  Do this by converting comments and
3682    preprocessing directives into spaces.   Also convert line continuations
3683    into whitespace.  Also, whiteout string and character literals.  */
3684
3685 static void
3686 do_cleaning (char *new_clean_text_base, const char *new_clean_text_limit)
3687 {
3688   char *scan_p;
3689   int non_whitespace_since_newline = 0;
3690
3691   for (scan_p = new_clean_text_base; scan_p < new_clean_text_limit; scan_p++)
3692     {
3693       switch (*scan_p)
3694         {
3695         case '/':                       /* Handle comments.  */
3696           if (scan_p[1] != '*')
3697             goto regular;
3698           non_whitespace_since_newline = 1;
3699           scan_p[0] = ' ';
3700           scan_p[1] = ' ';
3701           scan_p += 2;
3702           while (scan_p[1] != '/' || scan_p[0] != '*')
3703             {
3704               if (!ISSPACE ((const unsigned char)*scan_p))
3705                 *scan_p = ' ';
3706               if (++scan_p >= new_clean_text_limit)
3707                 abort ();
3708             }
3709           *scan_p++ = ' ';
3710           *scan_p = ' ';
3711           break;
3712
3713         case '#':                       /* Handle pp directives.  */
3714           if (non_whitespace_since_newline)
3715             goto regular;
3716           *scan_p = ' ';
3717           while (scan_p[1] != '\n' || scan_p[0] == '\\')
3718             {
3719               if (!ISSPACE ((const unsigned char)*scan_p))
3720                 *scan_p = ' ';
3721               if (++scan_p >= new_clean_text_limit)
3722                 abort ();
3723             }
3724           *scan_p++ = ' ';
3725           break;
3726
3727         case '\'':                      /* Handle character literals.  */
3728           non_whitespace_since_newline = 1;
3729           while (scan_p[1] != '\'' || scan_p[0] == '\\')
3730             {
3731               if (scan_p[0] == '\\'
3732                   && !ISSPACE ((const unsigned char) scan_p[1]))
3733                 scan_p[1] = ' ';
3734               if (!ISSPACE ((const unsigned char)*scan_p))
3735                 *scan_p = ' ';
3736               if (++scan_p >= new_clean_text_limit)
3737                 abort ();
3738             }
3739           *scan_p++ = ' ';
3740           break;
3741
3742         case '"':                       /* Handle string literals.  */
3743           non_whitespace_since_newline = 1;
3744           while (scan_p[1] != '"' || scan_p[0] == '\\')
3745             {
3746               if (scan_p[0] == '\\'
3747                   && !ISSPACE ((const unsigned char) scan_p[1]))
3748                 scan_p[1] = ' ';
3749               if (!ISSPACE ((const unsigned char)*scan_p))
3750                 *scan_p = ' ';
3751               if (++scan_p >= new_clean_text_limit)
3752                 abort ();
3753             }
3754           if (!ISSPACE ((const unsigned char)*scan_p))
3755             *scan_p = ' ';
3756           scan_p++;
3757           break;
3758
3759         case '\\':                      /* Handle line continuations.  */
3760           if (scan_p[1] != '\n')
3761             goto regular;
3762           *scan_p = ' ';
3763           break;
3764
3765         case '\n':
3766           non_whitespace_since_newline = 0;     /* Reset.  */
3767           break;
3768
3769         case ' ':
3770         case '\v':
3771         case '\t':
3772         case '\r':
3773         case '\f':
3774         case '\b':
3775           break;                /* Whitespace characters.  */
3776
3777         default:
3778 regular:
3779           non_whitespace_since_newline = 1;
3780           break;
3781         }
3782     }
3783 }
3784
3785 /* Given a pointer to the closing right parenthesis for a particular formals
3786    list (in the clean text buffer) find the corresponding left parenthesis
3787    and return a pointer to it.  */
3788
3789 static const char *
3790 careful_find_l_paren (const char *p)
3791 {
3792   const char *q;
3793   int paren_depth;
3794
3795   for (paren_depth = 1, q = p-1; paren_depth; check_source (--q >= clean_text_base, 0))
3796     {
3797       switch (*q)
3798         {
3799         case ')':
3800           paren_depth++;
3801           break;
3802         case '(':
3803           paren_depth--;
3804           break;
3805         }
3806     }
3807   return ++q;
3808 }
3809
3810 /* Scan the clean text buffer for cases of function definitions that we
3811    don't really know about because they were preprocessed out when the
3812    aux info files were created.
3813
3814    In this version of protoize/unprotoize we just give a warning for each
3815    one found.  A later version may be able to at least unprotoize such
3816    missed items.
3817
3818    Note that we may easily find all function definitions simply by
3819    looking for places where there is a left paren which is (ignoring
3820    whitespace) immediately followed by either a left-brace or by an
3821    upper or lower case letter.  Whenever we find this combination, we
3822    have also found a function definition header.
3823
3824    Finding function *declarations* using syntactic clues is much harder.
3825    I will probably try to do this in a later version though.  */
3826
3827 static void
3828 scan_for_missed_items (const file_info *file_p)
3829 {
3830   static const char *scan_p;
3831   const char *limit = clean_text_limit - 3;
3832   static const char *backup_limit;
3833
3834   backup_limit = clean_text_base - 1;
3835
3836   for (scan_p = clean_text_base; scan_p < limit; scan_p++)
3837     {
3838       if (*scan_p == ')')
3839         {
3840           static const char *last_r_paren;
3841           const char *ahead_p;
3842
3843           last_r_paren = scan_p;
3844
3845           for (ahead_p = scan_p + 1; ISSPACE ((const unsigned char)*ahead_p); )
3846             check_source (++ahead_p < limit, limit);
3847
3848           scan_p = ahead_p - 1;
3849
3850           if (ISALPHA ((const unsigned char)*ahead_p) || *ahead_p == '{')
3851             {
3852               const char *last_l_paren;
3853               const int lineno = identify_lineno (ahead_p);
3854
3855               if (setjmp (source_confusion_recovery))
3856                 continue;
3857
3858               /* We know we have a function definition header.  Now skip
3859                  leftwards over all of its associated formals lists.  */
3860
3861               do
3862                 {
3863                   last_l_paren = careful_find_l_paren (last_r_paren);
3864                   for (last_r_paren = last_l_paren-1;
3865                        ISSPACE ((const unsigned char)*last_r_paren); )
3866                     check_source (--last_r_paren >= backup_limit, backup_limit);
3867                 }
3868               while (*last_r_paren == ')');
3869
3870               if (is_id_char (*last_r_paren))
3871                 {
3872                   const char *id_limit = last_r_paren + 1;
3873                   const char *id_start;
3874                   size_t id_length;
3875                   const def_dec_info *dd_p;
3876
3877                   for (id_start = id_limit-1; is_id_char (*id_start); )
3878                     check_source (--id_start >= backup_limit, backup_limit);
3879                   id_start++;
3880                   backup_limit = id_start;
3881                   if ((id_length = (size_t) (id_limit - id_start)) == 0)
3882                     goto not_missed;
3883
3884                   {
3885                     char *func_name = alloca (id_length + 1);
3886                     static const char * const stmt_keywords[]
3887                       = { "if", "else", "do", "while", "for", "switch", "case", "return", 0 };
3888                     const char * const *stmt_keyword;
3889
3890                     strncpy (func_name, id_start, id_length);
3891                     func_name[id_length] = '\0';
3892
3893                     /* We must check here to see if we are actually looking at
3894                        a statement rather than an actual function call.  */
3895
3896                     for (stmt_keyword = stmt_keywords; *stmt_keyword; stmt_keyword++)
3897                       if (!strcmp (func_name, *stmt_keyword))
3898                         goto not_missed;
3899
3900 #if 0
3901                     notice ("%s: found definition of `%s' at %s(%d)\n",
3902                             pname,
3903                             func_name,
3904                             shortpath (NULL, file_p->hash_entry->symbol),
3905                             identify_lineno (id_start));
3906 #endif                          /* 0 */
3907                     /* We really should check for a match of the function name
3908                        here also, but why bother.  */
3909
3910                     for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3911                       if (dd_p->is_func_def && dd_p->line == lineno)
3912                         goto not_missed;
3913
3914                     /* If we make it here, then we did not know about this
3915                        function definition.  */
3916
3917                     notice ("%s: %d: warning: `%s' excluded by preprocessing\n",
3918                             shortpath (NULL, file_p->hash_entry->symbol),
3919                             identify_lineno (id_start), func_name);
3920                     notice ("%s: function definition not converted\n",
3921                             pname);
3922                   }
3923                 not_missed: ;
3924                 }
3925             }
3926         }
3927     }
3928 }
3929
3930 /* Do all editing operations for a single source file (either a "base" file
3931    or an "include" file).  To do this we read the file into memory, keep a
3932    virgin copy there, make another cleaned in-core copy of the original file
3933    (i.e. one in which all of the comments and preprocessing directives have
3934    been replaced with whitespace), then use these two in-core copies of the
3935    file to make a new edited in-core copy of the file.  Finally, rename the
3936    original file (as a way of saving it), and then write the edited version
3937    of the file from core to a disk file of the same name as the original.
3938
3939    Note that the trick of making a copy of the original sans comments &
3940    preprocessing directives make the editing a whole lot easier.  */
3941
3942 static void
3943 edit_file (const hash_table_entry *hp)
3944 {
3945   struct stat stat_buf;
3946   const file_info *file_p = hp->fip;
3947   char *new_orig_text_base;
3948   char *new_orig_text_limit;
3949   char *new_clean_text_base;
3950   char *new_clean_text_limit;
3951   size_t orig_size;
3952   size_t repl_size;
3953   int first_definition_in_file;
3954
3955   /* If we are not supposed to be converting this file, or if there is
3956      nothing in there which needs converting, just skip this file.  */
3957
3958   if (!needs_to_be_converted (file_p))
3959     return;
3960
3961   convert_filename = file_p->hash_entry->symbol;
3962
3963   /* Convert a file if it is in a directory where we want conversion
3964      and the file is not excluded.  */
3965
3966   if (!directory_specified_p (convert_filename)
3967       || file_excluded_p (convert_filename))
3968     {
3969       if (!quiet_flag
3970 #ifdef UNPROTOIZE
3971           /* Don't even mention "system" include files unless we are
3972              protoizing.  If we are protoizing, we mention these as a
3973              gentle way of prodding the user to convert his "system"
3974              include files to prototype format.  */
3975           && !in_system_include_dir (convert_filename)
3976 #endif /* defined (UNPROTOIZE) */
3977           )
3978         notice ("%s: `%s' not converted\n",
3979                 pname, shortpath (NULL, convert_filename));
3980       return;
3981     }
3982
3983   /* Let the user know what we are up to.  */
3984
3985   if (nochange_flag)
3986     notice ("%s: would convert file `%s'\n",
3987             pname, shortpath (NULL, convert_filename));
3988   else
3989     notice ("%s: converting file `%s'\n",
3990             pname, shortpath (NULL, convert_filename));
3991   fflush (stderr);
3992
3993   /* Find out the size (in bytes) of the original file.  */
3994
3995   /* The cast avoids an erroneous warning on AIX.  */
3996   if (stat (convert_filename, &stat_buf) == -1)
3997     {
3998       int errno_val = errno;
3999       notice ("%s: can't get status for file `%s': %s\n",
4000               pname, shortpath (NULL, convert_filename),
4001               xstrerror (errno_val));
4002       return;
4003     }
4004   orig_size = stat_buf.st_size;
4005
4006   /* Allocate a buffer to hold the original text.  */
4007
4008   orig_text_base = new_orig_text_base = xmalloc (orig_size + 2);
4009   orig_text_limit = new_orig_text_limit = new_orig_text_base + orig_size;
4010
4011   /* Allocate a buffer to hold the cleaned-up version of the original text.  */
4012
4013   clean_text_base = new_clean_text_base = xmalloc (orig_size + 2);
4014   clean_text_limit = new_clean_text_limit = new_clean_text_base + orig_size;
4015   clean_read_ptr = clean_text_base - 1;
4016
4017   /* Allocate a buffer that will hopefully be large enough to hold the entire
4018      converted output text.  As an initial guess for the maximum size of the
4019      output buffer, use 125% of the size of the original + some extra.  This
4020      buffer can be expanded later as needed.  */
4021
4022   repl_size = orig_size + (orig_size >> 2) + 4096;
4023   repl_text_base = xmalloc (repl_size + 2);
4024   repl_text_limit = repl_text_base + repl_size - 1;
4025   repl_write_ptr = repl_text_base - 1;
4026
4027   {
4028     int input_file;
4029     int fd_flags;
4030
4031     /* Open the file to be converted in READ ONLY mode.  */
4032
4033     fd_flags = O_RDONLY;
4034 #ifdef O_BINARY
4035     /* Use binary mode to avoid having to deal with different EOL characters.  */
4036     fd_flags |= O_BINARY;
4037 #endif
4038     if ((input_file = open (convert_filename, fd_flags, 0444)) == -1)
4039       {
4040         int errno_val = errno;
4041         notice ("%s: can't open file `%s' for reading: %s\n",
4042                 pname, shortpath (NULL, convert_filename),
4043                 xstrerror (errno_val));
4044         return;
4045       }
4046
4047     /* Read the entire original source text file into the original text buffer
4048        in one swell fwoop.  Then figure out where the end of the text is and
4049        make sure that it ends with a newline followed by a null.  */
4050
4051     if (safe_read (input_file, new_orig_text_base, orig_size) !=
4052         (int) orig_size)
4053       {
4054         int errno_val = errno;
4055         close (input_file);
4056         notice ("\n%s: error reading input file `%s': %s\n",
4057                 pname, shortpath (NULL, convert_filename),
4058                 xstrerror (errno_val));
4059         return;
4060       }
4061
4062     close (input_file);
4063   }
4064
4065   if (orig_size == 0 || orig_text_limit[-1] != '\n')
4066     {
4067       *new_orig_text_limit++ = '\n';
4068       orig_text_limit++;
4069     }
4070
4071   /* Create the cleaned up copy of the original text.  */
4072
4073   memcpy (new_clean_text_base, orig_text_base,
4074           (size_t) (orig_text_limit - orig_text_base));
4075   do_cleaning (new_clean_text_base, new_clean_text_limit);
4076
4077 #if 0
4078   {
4079     int clean_file;
4080     size_t clean_size = orig_text_limit - orig_text_base;
4081     char *const clean_filename = alloca (strlen (convert_filename) + 6 + 1);
4082
4083     /* Open (and create) the clean file.  */
4084
4085     strcpy (clean_filename, convert_filename);
4086     strcat (clean_filename, ".clean");
4087     if ((clean_file = creat (clean_filename, 0666)) == -1)
4088       {
4089         int errno_val = errno;
4090         notice ("%s: can't create/open clean file `%s': %s\n",
4091                 pname, shortpath (NULL, clean_filename),
4092                 xstrerror (errno_val));
4093         return;
4094       }
4095
4096     /* Write the clean file.  */
4097
4098     safe_write (clean_file, new_clean_text_base, clean_size, clean_filename);
4099
4100     close (clean_file);
4101   }
4102 #endif /* 0 */
4103
4104   /* Do a simplified scan of the input looking for things that were not
4105      mentioned in the aux info files because of the fact that they were
4106      in a region of the source which was preprocessed-out (via #if or
4107      via #ifdef).  */
4108
4109   scan_for_missed_items (file_p);
4110
4111   /* Setup to do line-oriented forward seeking in the clean text buffer.  */
4112
4113   last_known_line_number = 1;
4114   last_known_line_start = clean_text_base;
4115
4116   /* Now get down to business and make all of the necessary edits.  */
4117
4118   {
4119     const def_dec_info *def_dec_p;
4120
4121     first_definition_in_file = 1;
4122     def_dec_p = file_p->defs_decs;
4123     for (; def_dec_p; def_dec_p = def_dec_p->next_in_file)
4124       {
4125         const char *clean_text_p = seek_to_line (def_dec_p->line);
4126
4127         /* clean_text_p now points to the first character of the line which
4128            contains the `terminator' for the declaration or definition that
4129            we are about to process.  */
4130
4131 #ifndef UNPROTOIZE
4132
4133         if (global_flag && def_dec_p->is_func_def && first_definition_in_file)
4134           {
4135             add_global_decls (def_dec_p->file, clean_text_p);
4136             first_definition_in_file = 0;
4137           }
4138
4139         /* Don't edit this item if it is already in prototype format or if it
4140            is a function declaration and we have found no corresponding
4141            definition.  */
4142
4143         if (def_dec_p->prototyped
4144             || (!def_dec_p->is_func_def && !def_dec_p->definition))
4145           continue;
4146
4147 #endif /* !defined (UNPROTOIZE) */
4148
4149         if (def_dec_p->is_func_def)
4150           edit_fn_definition (def_dec_p, clean_text_p);
4151         else
4152 #ifndef UNPROTOIZE
4153         if (def_dec_p->is_implicit)
4154           add_local_decl (def_dec_p, clean_text_p);
4155         else
4156 #endif /* !defined (UNPROTOIZE) */
4157           edit_fn_declaration (def_dec_p, clean_text_p);
4158       }
4159   }
4160
4161   /* Finalize things.  Output the last trailing part of the original text.  */
4162
4163   output_up_to (clean_text_limit - 1);
4164
4165   /* If this is just a test run, stop now and just deallocate the buffers.  */
4166
4167   if (nochange_flag)
4168     {
4169       free (new_orig_text_base);
4170       free (new_clean_text_base);
4171       free (repl_text_base);
4172       return;
4173     }
4174
4175   /* Change the name of the original input file.  This is just a quick way of
4176      saving the original file.  */
4177
4178   if (!nosave_flag)
4179     {
4180       char *new_filename
4181         = xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
4182
4183       strcpy (new_filename, convert_filename);
4184 #ifdef __MSDOS__
4185       /* MSDOS filenames are restricted to 8.3 format, so we save `foo.c'
4186          as `foo.<save_suffix>'.  */
4187       new_filename[(strlen (convert_filename) - 1] = '\0';
4188 #endif
4189       strcat (new_filename, save_suffix);
4190
4191       /* Don't overwrite existing file.  */
4192       if (access (new_filename, F_OK) == 0)
4193         {
4194           if (!quiet_flag)
4195             notice ("%s: warning: file `%s' already saved in `%s'\n",
4196                     pname,
4197                     shortpath (NULL, convert_filename),
4198                     shortpath (NULL, new_filename));
4199         }
4200       else if (rename (convert_filename, new_filename) == -1)
4201         {
4202           int errno_val = errno;
4203           notice ("%s: can't link file `%s' to `%s': %s\n",
4204                   pname,
4205                   shortpath (NULL, convert_filename),
4206                   shortpath (NULL, new_filename),
4207                   xstrerror (errno_val));
4208           return;
4209         }
4210     }
4211
4212   if (unlink (convert_filename) == -1)
4213     {
4214       int errno_val = errno;
4215       /* The file may have already been renamed.  */
4216       if (errno_val != ENOENT)
4217         {
4218           notice ("%s: can't delete file `%s': %s\n",
4219                   pname, shortpath (NULL, convert_filename),
4220                   xstrerror (errno_val));
4221           return;
4222         }
4223     }
4224
4225   {
4226     int output_file;
4227
4228     /* Open (and create) the output file.  */
4229
4230     if ((output_file = creat (convert_filename, 0666)) == -1)
4231       {
4232         int errno_val = errno;
4233         notice ("%s: can't create/open output file `%s': %s\n",
4234                 pname, shortpath (NULL, convert_filename),
4235                 xstrerror (errno_val));
4236         return;
4237       }
4238 #ifdef O_BINARY
4239     /* Use binary mode to avoid changing the existing EOL character.  */
4240     setmode (output_file, O_BINARY);
4241 #endif
4242
4243     /* Write the output file.  */
4244
4245     {
4246       unsigned int out_size = (repl_write_ptr + 1) - repl_text_base;
4247
4248       safe_write (output_file, repl_text_base, out_size, convert_filename);
4249     }
4250
4251     close (output_file);
4252   }
4253
4254   /* Deallocate the conversion buffers.  */
4255
4256   free (new_orig_text_base);
4257   free (new_clean_text_base);
4258   free (repl_text_base);
4259
4260   /* Change the mode of the output file to match the original file.  */
4261
4262   /* The cast avoids an erroneous warning on AIX.  */
4263   if (chmod (convert_filename, stat_buf.st_mode) == -1)
4264     {
4265       int errno_val = errno;
4266       notice ("%s: can't change mode of file `%s': %s\n",
4267               pname, shortpath (NULL, convert_filename),
4268               xstrerror (errno_val));
4269     }
4270
4271   /* Note:  We would try to change the owner and group of the output file
4272      to match those of the input file here, except that may not be a good
4273      thing to do because it might be misleading.  Also, it might not even
4274      be possible to do that (on BSD systems with quotas for instance).  */
4275 }
4276
4277 /* Do all of the individual steps needed to do the protoization (or
4278    unprotoization) of the files referenced in the aux_info files given
4279    in the command line.  */
4280
4281 static void
4282 do_processing (void)
4283 {
4284   const char * const *base_pp;
4285   const char * const * const end_pps
4286     = &base_source_filenames[n_base_source_files];
4287
4288 #ifndef UNPROTOIZE
4289   int syscalls_len;
4290 #endif /* !defined (UNPROTOIZE) */
4291
4292   /* One-by-one, check (and create if necessary), open, and read all of the
4293      stuff in each aux_info file.  After reading each aux_info file, the
4294      aux_info_file just read will be automatically deleted unless the
4295      keep_flag is set.  */
4296
4297   for (base_pp = base_source_filenames; base_pp < end_pps; base_pp++)
4298     process_aux_info_file (*base_pp, keep_flag, 0);
4299
4300 #ifndef UNPROTOIZE
4301
4302   /* Also open and read the special SYSCALLS.c aux_info file which gives us
4303      the prototypes for all of the standard system-supplied functions.  */
4304
4305   if (nondefault_syscalls_dir)
4306     {
4307       syscalls_absolute_filename
4308         = xmalloc (strlen (nondefault_syscalls_dir) + 1
4309                    + sizeof (syscalls_filename));
4310       strcpy (syscalls_absolute_filename, nondefault_syscalls_dir);
4311     }
4312   else
4313     {
4314       GET_ENVIRONMENT (default_syscalls_dir, "GCC_EXEC_PREFIX");
4315       if (!default_syscalls_dir)
4316         {
4317           default_syscalls_dir = standard_exec_prefix;
4318         }
4319       syscalls_absolute_filename
4320         = xmalloc (strlen (default_syscalls_dir) + 0
4321                    + strlen (target_machine) + 1
4322                    + strlen (target_version) + 1
4323                    + sizeof (syscalls_filename));
4324       strcpy (syscalls_absolute_filename, default_syscalls_dir);
4325       strcat (syscalls_absolute_filename, target_machine);
4326       strcat (syscalls_absolute_filename, "/");
4327       strcat (syscalls_absolute_filename, target_version);
4328       strcat (syscalls_absolute_filename, "/");
4329     }
4330
4331   syscalls_len = strlen (syscalls_absolute_filename);
4332   if (! IS_DIR_SEPARATOR (*(syscalls_absolute_filename + syscalls_len - 1)))
4333     {
4334       *(syscalls_absolute_filename + syscalls_len++) = DIR_SEPARATOR;
4335       *(syscalls_absolute_filename + syscalls_len) = '\0';
4336     }
4337   strcat (syscalls_absolute_filename, syscalls_filename);
4338
4339   /* Call process_aux_info_file in such a way that it does not try to
4340      delete the SYSCALLS aux_info file.  */
4341
4342   process_aux_info_file (syscalls_absolute_filename, 1, 1);
4343
4344 #endif /* !defined (UNPROTOIZE) */
4345
4346   /* When we first read in all of the information from the aux_info files
4347      we saved in it descending line number order, because that was likely to
4348      be faster.  Now however, we want the chains of def & dec records to
4349      appear in ascending line number order as we get further away from the
4350      file_info record that they hang from.  The following line causes all of
4351      these lists to be rearranged into ascending line number order.  */
4352
4353   visit_each_hash_node (filename_primary, reverse_def_dec_list);
4354
4355 #ifndef UNPROTOIZE
4356
4357   /* Now do the "real" work.  The following line causes each declaration record
4358      to be "visited".  For each of these nodes, an attempt is made to match
4359      up the function declaration with a corresponding function definition,
4360      which should have a full prototype-format formals list with it.  Once
4361      these match-ups are made, the conversion of the function declarations
4362      to prototype format can be made.  */
4363
4364   visit_each_hash_node (function_name_primary, connect_defs_and_decs);
4365
4366 #endif /* !defined (UNPROTOIZE) */
4367
4368   /* Now convert each file that can be converted (and needs to be).  */
4369
4370   visit_each_hash_node (filename_primary, edit_file);
4371
4372 #ifndef UNPROTOIZE
4373
4374   /* If we are working in cplusplus mode, try to rename all .c files to .C
4375      files.  Don't panic if some of the renames don't work.  */
4376
4377   if (cplusplus_flag && !nochange_flag)
4378     visit_each_hash_node (filename_primary, rename_c_file);
4379
4380 #endif /* !defined (UNPROTOIZE) */
4381 }
4382 \f
4383 static const struct option longopts[] =
4384 {
4385   {"version", 0, 0, 'V'},
4386   {"file_name", 0, 0, 'p'},
4387   {"quiet", 0, 0, 'q'},
4388   {"silent", 0, 0, 'q'},
4389   {"force", 0, 0, 'f'},
4390   {"keep", 0, 0, 'k'},
4391   {"nosave", 0, 0, 'N'},
4392   {"nochange", 0, 0, 'n'},
4393   {"compiler-options", 1, 0, 'c'},
4394   {"exclude", 1, 0, 'x'},
4395   {"directory", 1, 0, 'd'},
4396 #ifdef UNPROTOIZE
4397   {"indent", 1, 0, 'i'},
4398 #else
4399   {"local", 0, 0, 'l'},
4400   {"global", 0, 0, 'g'},
4401   {"c++", 0, 0, 'C'},
4402   {"syscalls-dir", 1, 0, 'B'},
4403 #endif
4404   {0, 0, 0, 0}
4405 };
4406
4407 extern int main (int, char **const);
4408
4409 int
4410 main (int argc, char **const argv)
4411 {
4412   int longind;
4413   int c;
4414   const char *params = "";
4415
4416   pname = strrchr (argv[0], DIR_SEPARATOR);
4417 #ifdef DIR_SEPARATOR_2
4418   {
4419     char *slash;
4420
4421     slash = strrchr (pname ? pname : argv[0], DIR_SEPARATOR_2);
4422     if (slash)
4423       pname = slash;
4424   }
4425 #endif
4426   pname = pname ? pname+1 : argv[0];
4427
4428 #ifdef SIGCHLD
4429   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
4430      receive the signal.  A different setting is inheritable */
4431   signal (SIGCHLD, SIG_DFL);
4432 #endif
4433
4434   gcc_init_libintl ();
4435
4436   cwd_buffer = getpwd ();
4437   if (!cwd_buffer)
4438     {
4439       notice ("%s: cannot get working directory: %s\n",
4440               pname, xstrerror(errno));
4441       return (FATAL_EXIT_CODE);
4442     }
4443
4444   /* By default, convert the files in the current directory.  */
4445   directory_list = string_list_cons (cwd_buffer, NULL);
4446
4447   while ((c = getopt_long (argc, argv,
4448 #ifdef UNPROTOIZE
4449                            "c:d:i:knNp:qvVx:",
4450 #else
4451                            "B:c:Cd:gklnNp:qvVx:",
4452 #endif
4453                            longopts, &longind)) != EOF)
4454     {
4455       if (c == 0)               /* Long option.  */
4456         c = longopts[longind].val;
4457       switch (c)
4458         {
4459         case 'p':
4460           compiler_file_name = optarg;
4461           break;
4462         case 'd':
4463           directory_list
4464             = string_list_cons (abspath (NULL, optarg), directory_list);
4465           break;
4466         case 'x':
4467           exclude_list = string_list_cons (optarg, exclude_list);
4468           break;
4469
4470         case 'v':
4471         case 'V':
4472           version_flag = 1;
4473           break;
4474         case 'q':
4475           quiet_flag = 1;
4476           break;
4477 #if 0
4478         case 'f':
4479           force_flag = 1;
4480           break;
4481 #endif
4482         case 'n':
4483           nochange_flag = 1;
4484           keep_flag = 1;
4485           break;
4486         case 'N':
4487           nosave_flag = 1;
4488           break;
4489         case 'k':
4490           keep_flag = 1;
4491           break;
4492         case 'c':
4493           params = optarg;
4494           break;
4495 #ifdef UNPROTOIZE
4496         case 'i':
4497           indent_string = optarg;
4498           break;
4499 #else                           /* !defined (UNPROTOIZE) */
4500         case 'l':
4501           local_flag = 1;
4502           break;
4503         case 'g':
4504           global_flag = 1;
4505           break;
4506         case 'C':
4507           cplusplus_flag = 1;
4508           break;
4509         case 'B':
4510           nondefault_syscalls_dir = optarg;
4511           break;
4512 #endif                          /* !defined (UNPROTOIZE) */
4513         default:
4514           usage ();
4515         }
4516     }
4517
4518   /* Set up compile_params based on -p and -c options.  */
4519   munge_compile_params (params);
4520
4521   n_base_source_files = argc - optind;
4522
4523   /* Now actually make a list of the base source filenames.  */
4524
4525   base_source_filenames
4526     = xmalloc ((n_base_source_files + 1) * sizeof (char *));
4527   n_base_source_files = 0;
4528   for (; optind < argc; optind++)
4529     {
4530       const char *path = abspath (NULL, argv[optind]);
4531       int len = strlen (path);
4532
4533       if (path[len-1] == 'c' && path[len-2] == '.')
4534         base_source_filenames[n_base_source_files++] = path;
4535       else
4536         {
4537           notice ("%s: input file names must have .c suffixes: %s\n",
4538                   pname, shortpath (NULL, path));
4539           errors++;
4540         }
4541     }
4542
4543 #ifndef UNPROTOIZE
4544   /* We are only interested in the very first identifier token in the
4545      definition of `va_list', so if there is more junk after that first
4546      identifier token, delete it from the `varargs_style_indicator'.  */
4547   {
4548     const char *cp;
4549
4550     for (cp = varargs_style_indicator; ISIDNUM (*cp); cp++)
4551       continue;
4552     if (*cp != 0)
4553       varargs_style_indicator = savestring (varargs_style_indicator,
4554                                             cp - varargs_style_indicator);
4555   }
4556 #endif /* !defined (UNPROTOIZE) */
4557
4558   if (errors)
4559     usage ();
4560   else
4561     {
4562       if (version_flag)
4563         fprintf (stderr, "%s: %s\n", pname, version_string);
4564       do_processing ();
4565     }
4566
4567   return (errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
4568 }