OSDN Git Service

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