OSDN Git Service

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