OSDN Git Service

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