OSDN Git Service

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