OSDN Git Service

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