OSDN Git Service

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