OSDN Git Service

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