OSDN Git Service

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