OSDN Git Service

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