OSDN Git Service

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