OSDN Git Service

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