OSDN Git Service

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