OSDN Git Service

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