OSDN Git Service

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