OSDN Git Service

Initial revision
[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 #if !(defined (USG) || defined (VMS))
202 extern int vfork ();
203 #define fork vfork
204 #else
205 extern int fork ();
206 #endif /* !(defined (USG) || defined (VMS)) */
207
208 #endif /* !defined (POSIX) */
209
210 /* Look for these where the `const' qualifier is intentionally cast aside.  */
211
212 #define NONCONST
213
214 /* Define a STRINGIFY macro that's right for ANSI or traditional C.  */
215
216 #ifdef __STDC__
217 #define STRINGIFY(STRING) #STRING
218 #else
219 #define STRINGIFY(STRING) "STRING"
220 #endif
221
222 /* POSIX systems will not have definitions for WIFEXITED or WEXITSTATUS.
223    Define them correctly and so that they work for all environments.  */
224
225 #undef WIFEXITED
226 #define WIFEXITED(status_word) ((*((int *)&status_word) & 0xff) == 0x00)
227
228 #undef WEXITSTATUS
229 #define WEXITSTATUS(status_word) ((*((int *)&status_word) & 0xff00) >> 8)
230
231 /* Define a default place to find the SYSCALLS.X file.  */
232
233 #ifndef STD_PROTO_DIR
234 #define STD_PROTO_DIR "/usr/local/lib"
235 #endif /* !defined (STD_PROTO_DIR) */
236
237 /* Suffix of aux_info files.  */
238
239 static const char * const aux_info_suffix = ".X";
240
241 /* String to attach to filenames for saved versions of original files.  */
242
243 static const char * const save_suffix = ".save";
244
245 #ifndef UNPROTOIZE
246
247 /* File name of the file which contains descriptions of standard system
248    routines.  Note that we never actually do anything with this file per se,
249    but we do read in its corresponding aux_info file.  */
250
251 static const char * const syscalls_filename = "SYSCALLS.c";
252
253 /* Default place to find the above file.  */
254
255 static const char * const default_syscalls_dir = STD_PROTO_DIR;
256
257 /* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
258    file.  */
259
260 static char * syscalls_absolute_filename;
261
262 #endif /* !defined (UNPROTOIZE) */
263
264 /* Type of the structure that holds information about macro unexpansions. */
265
266 struct unexpansion_struct {
267   const char *expanded;
268   const char *contracted;
269 };
270 typedef struct unexpansion_struct unexpansion;
271
272 /* A table of conversions that may need to be made for some (stupid) older
273    operating systems where these types are preprocessor macros rather than
274    typedefs (as they really ought to be).
275
276    WARNING: The contracted forms must be as small (or smaller) as the
277    expanded forms, or else havoc will ensue.  */
278
279 static const unexpansion unexpansions[] = {
280   { "struct _iobuf", "FILE" },
281   { 0, 0 }
282 };
283
284 /* The number of "primary" slots in the hash tables for filenames and for
285    function names.  This can be as big or as small as you like, except that
286    it must be a power of two.  */
287
288 #define HASH_TABLE_SIZE         (1 << 9)
289
290 /* Bit mask to use when computing hash values.  */
291
292 static const int hash_mask = (HASH_TABLE_SIZE - 1);
293
294 /* Make a table of default system include directories
295    just as it is done in cccp.c.  */
296
297 #ifndef STANDARD_INCLUDE_DIR
298 #define STANDARD_INCLUDE_DIR "/usr/include"
299 #endif
300
301 #ifndef LOCAL_INCLUDE_DIR
302 #define LOCAL_INCLUDE_DIR "/usr/local/include"
303 #endif
304
305 struct default_include { char *fname; int cplusplus; } include_defaults[]
306 #ifdef INCLUDE_DEFAULTS
307   = INCLUDE_DEFAULTS;
308 #else
309   = {
310     /* Pick up GNU C++ specific include files.  */
311     { GPLUSPLUS_INCLUDE_DIR, 1},
312     { GCC_INCLUDE_DIR, 0},
313 #ifdef CROSS_COMPILE
314     /* For cross-compilation, this dir name is generated
315        automatically in Makefile.in.  */
316     { CROSS_INCLUDE_DIR, 0 },
317 #else /* not CROSS_COMPILE */
318     { LOCAL_INCLUDE_DIR, 0},
319     /* Some systems have an extra dir of include files.  */
320 #ifdef SYSTEM_INCLUDE_DIR
321     { SYSTEM_INCLUDE_DIR, 0},
322 #endif
323     { STANDARD_INCLUDE_DIR, 0},
324 #endif /* not CROSS_COMPILE */
325     { 0, 0}
326     };
327 #endif /* no INCLUDE_DEFAULTS */
328
329 /* Datatype for lists of directories or filenames.  */
330 struct string_list
331 {
332   char *name;
333   struct string_list *next;
334 };
335
336 /* List of directories in which files should be converted.  */
337
338 struct string_list *directory_list;
339
340 /* List of file names which should not be converted.
341    A file is excluded if the end of its name, following a /,
342    matches one of the names in this list.  */
343
344 struct string_list *exclude_list;
345
346 /* The name of the other style of variable-number-of-parameters functions
347    (i.e. the style that we want to leave unconverted because we don't yet
348    know how to convert them to this style.  This string is used in warning
349    messages.  */
350
351 /* Also define here the string that we can search for in the parameter lists
352    taken from the .X files which will unambiguously indicate that we have
353    found a varargs style function.  */
354
355 #ifdef UNPROTOIZE
356 static const char * const other_var_style = "stdarg";
357 #else /* !defined (UNPROTOIZE) */
358 static const char * const other_var_style = "varargs";
359 /* Note that this is a string containing the expansion of va_alist.
360    But in `main' we discard all but the first token.  */
361 static const char *varargs_style_indicator = STRINGIFY (va_alist);
362 #endif /* !defined (UNPROTOIZE) */
363
364 /* The following two types are used to create hash tables.  In this program,
365    there are two hash tables which are used to store and quickly lookup two
366    different classes of strings.  The first type of strings stored in the
367    first hash table are absolute filenames of files which protoize needs to
368    know about.  The second type of strings (stored in the second hash table)
369    are function names.  It is this second class of strings which really
370    inspired the use of the hash tables, because there may be a lot of them.  */
371
372 typedef struct hash_table_entry_struct hash_table_entry;
373
374 /* Do some typedefs so that we don't have to write "struct" so often.  */
375
376 typedef struct def_dec_info_struct def_dec_info;
377 typedef struct file_info_struct file_info;
378 typedef struct f_list_chain_item_struct f_list_chain_item;
379
380 /* In the struct below, note that the "_info" field has two different uses
381    depending on the type of hash table we are in (i.e. either the filenames
382    hash table or the function names hash table).  In the filenames hash table
383    the info fields of the entries point to the file_info struct which is
384    associated with each filename (1 per filename).  In the function names
385    hash table, the info field points to the head of a singly linked list of
386    def_dec_info entries which are all defs or decs of the function whose
387    name is pointed to by the "symbol" field.  Keeping all of the defs/decs
388    for a given function name on a special list specifically for that function
389    name makes it quick and easy to find out all of the important information
390    about a given (named) function.  */
391
392 struct hash_table_entry_struct {
393   hash_table_entry *            hash_next;      /* -> to secondary entries */
394   const char *                  symbol;         /* -> to the hashed string */
395   union {
396     const def_dec_info *        _ddip;
397     file_info *                 _fip;
398   } _info;
399 };
400 #define ddip _info._ddip
401 #define fip _info._fip
402
403 /* Define a type specifically for our two hash tables.  */
404
405 typedef hash_table_entry hash_table[HASH_TABLE_SIZE];
406
407 /* The following struct holds all of the important information about any
408    single filename (e.g. file) which we need to know about.  */
409
410 struct file_info_struct {
411   const hash_table_entry *      hash_entry; /* -> to associated hash entry */
412   const def_dec_info *          defs_decs;  /* -> to chain of defs/decs */
413   time_t                        mtime;      /* Time of last modification.  */
414 };
415
416 /* Due to the possibility that functions may return pointers to functions,
417    (which may themselves have their own parameter lists) and due to the
418    fact that returned pointers-to-functions may be of type "pointer-to-
419    function-returning-pointer-to-function" (ad nauseum) we have to keep
420    an entire chain of ANSI style formal parameter lists for each function.
421
422    Normally, for any given function, there will only be one formals list
423    on the chain, but you never know.
424
425    Note that the head of each chain of formals lists is pointed to by the
426    `f_list_chain' field of the corresponding def_dec_info record.
427
428    For any given chain, the item at the head of the chain is the *leftmost*
429    parameter list seen in the actual C language function declaration.  If
430    there are other members of the chain, then these are linked in left-to-right
431    order from the head of the chain.  */
432
433 struct f_list_chain_item_struct {
434   const f_list_chain_item *     chain_next;     /* -> to next item on chain */
435   const char *                  formals_list;   /* -> to formals list string */
436 };
437
438 /* The following struct holds all of the important information about any
439    single function definition or declaration which we need to know about.
440    Note that for unprotoize we don't need to know very much because we
441    never even create records for stuff that we don't intend to convert
442    (like for instance defs and decs which are already in old K&R format
443    and "implicit" function declarations).  */
444
445 struct def_dec_info_struct {
446   const def_dec_info *  next_in_file;   /* -> to rest of chain for file */
447   file_info *           file;           /* -> file_info for containing file */
448   int                   line;           /* source line number of def/dec */
449   const char *          ansi_decl;      /* -> left end of ansi decl */
450   hash_table_entry *    hash_entry;     /* -> hash entry for function name */
451   unsigned int          is_func_def;    /* = 0 means this is a declaration */
452   const def_dec_info *  next_for_func;  /* -> to rest of chain for func name */
453   unsigned int          f_list_count;   /* count of formals lists we expect */
454   char                  prototyped;     /* = 0 means already prototyped */
455 #ifndef UNPROTOIZE
456   const f_list_chain_item * f_list_chain;       /* -> chain of formals lists */
457   const def_dec_info *  definition;     /* -> def/dec containing related def */
458   char                  is_static;      /* = 0 means visiblilty is "extern"  */
459   char                  is_implicit;    /* != 0 for implicit func decl's */
460   char                  written;        /* != 0 means written for implicit */
461 #else /* !defined (UNPROTOIZE) */
462   const char *          formal_names;   /* -> to list of names of formals */
463   const char *          formal_decls;   /* -> to string of formal declartions */
464 #endif /* !defined (UNPROTOIZE) */
465 };
466
467 /* Pointer to the tail component of the filename by which this program was
468    invoked.  Used everywhere in error and warning messages.  */
469
470 static const char *pname;
471
472 /* Error counter.  Will be non-zero if we should give up at the next convenient
473    stopping point.  */
474
475 static int errors = 0;
476
477 /* Option flags.  */
478 /* ??? These comments should say what the flag mean as well as the options
479    that set them.  */
480
481 /* File name to use for running gcc.  Allows GCC 2 to be named
482    something other than gcc.  */
483 static char *compiler_file_name = "gcc";
484
485 static int version_flag = 0;            /* Print our version number.  */
486 static int quiet_flag = 0;              /* Don't print messages normally.  */
487 static int nochange_flag = 0;           /* Don't convert, just say what files
488                                            we would have converted.  */
489 static int nosave_flag = 0;             /* Don't save the old version.  */
490 static int keep_flag = 0;               /* Don't delete the .X files.  */
491 static const char ** compile_params = 0;        /* Option string for gcc.  */
492 #ifdef UNPROTOIZE
493 static const char *indent_string = "     ";     /* Indentation for newly
494                                                    inserted parm decls.  */
495 #else /* !defined (UNPROTOIZE) */
496 static int local_flag = 0;              /* Insert new local decls (when?).  */
497 static int global_flag = 0;             /* set by -g option */
498 static int cplusplus_flag = 0;          /* Rename converted files to *.C.  */
499 static const char* nondefault_syscalls_dir = 0; /* Dir to look for
500                                                    SYSCALLS.c.X in.  */
501 #endif /* !defined (UNPROTOIZE) */
502
503 /* An index into the compile_params array where we should insert the filename
504    parameter when we are ready to exec the C compiler.  A zero value indicates
505    that we have not yet called munge_compile_params.  */
506
507 static int filename_index = 0;
508
509 /* Count of command line arguments which were "filename" arguments.  */
510
511 static int n_base_source_files = 0;
512
513 /* Points to a malloc'ed list of pointers to all of the filenames of base
514    source files which were specified on the command line.  */
515
516 static const char **base_source_filenames;
517
518 /* Line number of the line within the current aux_info file that we
519    are currently processing.  Used for error messages in case the prototypes
520    info file is corrupted somehow.  */
521
522 static int current_aux_info_lineno;
523
524 /* Pointer to the name of the source file currently being converted.  */
525
526 static const char *convert_filename;
527
528 /* Pointer to relative root string (taken from aux_info file) which indicates
529    where directory the user was in when he did the compilation step that
530    produced the containing aux_info file. */
531
532 static const char *invocation_filename;
533
534 /* Pointer to the base of the input buffer that holds the original text for the
535    source file currently being converted.  */
536
537 static const char *orig_text_base;
538
539 /* Pointer to the byte just beyond the end of the input buffer that holds the
540    original text for the source file currently being converted.  */
541
542 static const char *orig_text_limit;
543
544 /* Pointer to the base of the input buffer that holds the cleaned text for the
545    source file currently being converted.  */
546
547 static const char *clean_text_base;
548
549 /* Pointer to the byte just beyond the end of the input buffer that holds the
550    cleaned text for the source file currently being converted.  */
551
552 static const char *clean_text_limit;
553
554 /* Pointer to the last byte in the cleaned text buffer that we have already
555    (virtually) copied to the output buffer (or decided to ignore).  */
556
557 static const char * clean_read_ptr;
558
559 /* Pointer to the base of the output buffer that holds the replacement text
560    for the source file currently being converted.  */
561
562 static char *repl_text_base;
563
564 /* Pointer to the byte just beyond the end of the output buffer that holds the
565    replacement text for the source file currently being converted.  */
566
567 static char *repl_text_limit;
568
569 /* Pointer to the last byte which has been stored into the output buffer.
570    The next byte to be stored should be stored just past where this points
571    to.  */
572
573 static char * repl_write_ptr;
574
575 /* Pointer into the cleaned text buffer for the source file we are currently
576    converting.  This points to the first character of the line that we last
577    did a "seek_to_line" to (see below).  */
578
579 static const char *last_known_line_start;
580
581 /* Number of the line (in the cleaned text buffer) that we last did a
582    "seek_to_line" to.  Will be one if we just read a new source file
583    into the cleaned text buffer.  */
584
585 static int last_known_line_number;
586
587 /* The filenames hash table.  */
588
589 static hash_table filename_primary;
590
591 /* The function names hash table.  */
592
593 static hash_table function_name_primary;
594
595 /* The place to keep the recovery address which is used only in cases where
596    we get hopelessly confused by something in the cleaned original text.  */
597
598 static jmp_buf source_confusion_recovery;
599
600 /* A pointer to the current directory filename (used by abspath).  */
601
602 static char *cwd_buffer;
603
604 /* A place to save the read pointer until we are sure that an individual
605    attempt at editing will succeed.  */
606
607 static const char * saved_clean_read_ptr;
608
609 /* A place to save the write pointer until we are sure that an individual
610    attempt at editing will succeed.  */
611
612 static char * saved_repl_write_ptr;
613
614 /* Forward declaration.  */
615
616 static const char *shortpath ();
617 \f
618 /* Allocate some space, but check that the allocation was successful.  */
619 /* alloca.c uses this, so don't make it static.  */
620
621 pointer_type
622 xmalloc (byte_count)
623      size_t byte_count;
624 {
625   pointer_type rv;
626
627   rv = malloc (byte_count);
628   if (rv == NULL)
629     {
630       fprintf (stderr, "\n%s: fatal error: can't allocate %u more bytes of memory\n",
631                pname, byte_count);
632       exit (1);
633       return 0;         /* avoid warnings */
634     }
635   else
636     return rv;
637 }
638
639 /* Reallocate some space, but check that the reallocation was successful.  */
640
641 pointer_type
642 xrealloc (old_space, byte_count)
643      pointer_type old_space;
644      size_t byte_count;
645 {
646   pointer_type rv;
647
648   rv = realloc (old_space, byte_count);
649   if (rv == NULL)
650     {
651       fprintf (stderr, "\n%s: fatal error: can't allocate %u more bytes of memory\n",
652                pname, byte_count);
653       exit (1);
654       return 0;         /* avoid warnings */
655     }
656   else
657     return rv;
658 }
659
660 /* Deallocate the area pointed to by an arbitrary pointer, but first, strip
661    the `const' qualifier from it and also make sure that the pointer value
662    is non-null.  */
663
664 void
665 xfree (p)
666      const_pointer_type p;
667 {
668   if (p)
669     free ((NONCONST pointer_type) p);
670 }
671
672 /* Make a copy of a string INPUT with size SIZE.  */
673
674 static char *
675 savestring (input, size)
676      const char *input;
677      int size;
678 {
679   char *output = (char *) xmalloc (size + 1);
680   strcpy (output, input);
681   return output;
682 }
683
684 /* More 'friendly' abort that prints the line and file.
685    config.h can #define abort fancy_abort if you like that sort of thing.  */
686
687 void
688 fancy_abort ()
689 {
690   fprintf (stderr, "%s: internal abort\n", pname);
691   exit (1);
692 }
693 \f
694 /* Make a duplicate of a given string in a newly allocated area.  */
695
696 static char *
697 dupstr (s)
698      const char *s;
699 {
700   return strcpy ((char *) xmalloc (strlen (s) + 1), s);
701 }
702
703 /* Make a duplicate of the first N bytes of a given string in a newly
704    allocated area.  */
705
706 static char *
707 dupnstr (s, n)
708      const char *s;
709      size_t n;
710 {
711   char *ret_val = strncpy ((char *) xmalloc (n + 1), s, n);
712
713   ret_val[n] = '\0';
714   return ret_val;
715 }
716
717 /* Return a pointer to the first occurance of s2 within s1 or NULL if s2
718    does not occur within s1.  Assume neither s1 nor s2 are null pointers.  */
719
720 static const char *
721 substr (s1, s2)
722      const char *s1;
723      const char *const s2;
724 {
725   for (; *s1 ; s1++)
726     {
727       const char *p1;
728       const char *p2;
729       int c;
730
731       for (p1 = s1, p2 = s2; c = *p2; p1++, p2++)
732         if (*p1 != c)
733           goto outer;
734       return s1;
735 outer:
736       ;
737     }
738   return 0;
739 }
740 \f
741 /* Get setup to recover in case the edit we are about to do goes awry.  */
742
743 void
744 save_pointers ()
745 {
746   saved_clean_read_ptr = clean_read_ptr;
747   saved_repl_write_ptr = repl_write_ptr;
748 }
749
750 /* Call this routine to recover our previous state whenever something looks
751    too confusing in the source code we are trying to edit.  */
752
753 void
754 restore_pointers ()
755 {
756   clean_read_ptr = saved_clean_read_ptr;
757   repl_write_ptr = saved_repl_write_ptr;
758 }
759
760 /* Return true if the given character is a legal identifier character.  */
761
762 static int
763 is_id_char (ch)
764      char ch;
765 {
766   return (isalnum (ch) || (ch == '_') || (ch == '$'));
767 }
768
769 /* Give a message indicating the proper way to invoke this program and then
770    exit with non-zero status.  */
771
772 static void
773 usage ()
774 {
775 #ifdef UNPROTOIZE
776   fprintf (stderr, "%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
777            pname, pname);
778 #else /* !defined (UNPROTOIZE) */
779   fprintf (stderr, "%s: usage '%s [ -VqfnkNlgC ] [ -B <diname> ] [ filename ... ]'\n",
780            pname, pname);
781 #endif /* !defined (UNPROTOIZE) */
782   exit (1);
783 }
784
785 /* Return true if the given filename (assumed to be an absolute filename)
786    designates a file residing anywhere beneath any one of the "system"
787    include directories.  */
788
789 static int
790 in_system_include_dir (path)
791      const char *path;
792 {
793   struct default_include *p;
794
795   if (path[0] != '/')
796     abort ();           /* Must be an absolutized filename.  */
797
798   for (p = include_defaults; p->fname; p++)
799     if (!strncmp (path, p->fname, strlen (p->fname))
800         && path[strlen (p->fname)] == '/')
801       return 1;
802   return 0;
803 }
804 \f
805 #if 0
806 /* Return true if the given filename designates a file that the user has
807    read access to and for which the user has write access to the containing
808    directory.  */
809
810 static int
811 file_could_be_converted (const char *path)
812 {
813   char *const dir_name = (char *) alloca (strlen (path) + 1);
814
815   if (my_access (path, R_OK))
816     return 0;
817
818   {
819     char *dir_last_slash;
820
821     strcpy (dir_name, path);
822     dir_last_slash = strrchr (dir_name, '/');
823     if (dir_last_slash)
824       *dir_last_slash = '\0';
825     else
826       abort ();  /* Should have been an absolutized filename.  */
827   }
828
829   if (my_access (path, W_OK))
830     return 0;
831
832   return 1;
833 }
834
835 /* Return true if the given filename designates a file that we are allowed
836    to modify.  Files which we should not attempt to modify are (a) "system"
837    include files, and (b) files which the user doesn't have write access to,
838    and (c) files which reside in directories which the user doesn't have
839    write access to.  Unless requested to be quiet, give warnings about
840    files that we will not try to convert for one reason or another.  An
841    exception is made for "system" include files, which we never try to
842    convert and for which we don't issue the usual warnings.  */
843
844 static int
845 file_normally_convertable (const char *path)
846 {
847   char *const dir_name = alloca (strlen (path) + 1);
848
849   if (in_system_include_dir (path))
850     return 0;
851
852   {
853     char *dir_last_slash;
854
855     strcpy (dir_name, path);
856     dir_last_slash = strrchr (dir_name, '/');
857     if (dir_last_slash)
858       *dir_last_slash = '\0';
859     else
860       abort ();  /* Should have been an absolutized filename.  */
861   }
862
863   if (my_access (path, R_OK))
864     {
865       if (!quiet_flag)
866         fprintf (stderr, "%s: warning: no read access for file `%s'\n",
867                  pname, shortpath (NULL, path));
868       return 0;
869     }
870
871   if (my_access (path, W_OK))
872     {
873       if (!quiet_flag)
874         fprintf (stderr, "%s: warning: no write access for file `%s'\n",
875                  pname, shortpath (NULL, path));
876       return 0;
877     }
878
879   if (my_access (dir_name, W_OK))
880     {
881       if (!quiet_flag)
882         fprintf (stderr, "%s: warning: no write access for dir containing `%s'\n",
883                  pname, shortpath (NULL, path));
884       return 0;
885     }
886
887   return 1;
888 }
889 #endif /* 0 */
890 \f
891 #ifndef UNPROTOIZE
892
893 /* Return true if the given file_info struct refers to the special SYSCALLS.c.X
894    file.  Return false otherwise.  */
895
896 static int
897 is_syscalls_file (fi_p)
898      const file_info *fi_p;
899 {
900   return (substr (fi_p->hash_entry->symbol, syscalls_filename) != NULL);
901 }
902
903 #endif /* !defined (UNPROTOIZE) */
904
905 /* Check to see if this file will need to have anything done to it on this
906    run.  If there is nothing in the given file which both needs conversion
907    and for which we have the necessary stuff to do the conversion, return
908    false.  Otherwise, return true.
909
910    Note that (for protoize) it is only valid to call this function *after*
911    the connections between declarations and definitions have all been made
912    by connect_defs_and_decs.  */
913
914 static int
915 needs_to_be_converted (file_p)
916      const file_info *file_p;
917 {
918   const def_dec_info *ddp;
919
920 #ifndef UNPROTOIZE
921
922   if (is_syscalls_file (file_p))
923     return 0;
924
925 #endif /* !defined (UNPROTOIZE) */
926
927   for (ddp = file_p->defs_decs; ddp; ddp = ddp->next_in_file)
928
929     if (
930
931 #ifndef UNPROTOIZE
932
933       /* ... and if we a protoizing and this function is in old style ... */
934       !ddp->prototyped
935       /* ... and if this a definition or is a decl with an associated def ... */
936       && (ddp->is_func_def || (!ddp->is_func_def && ddp->definition))
937
938 #else /* defined (UNPROTOIZE) */
939
940       /* ... and if we are unprotoizing and this function is in new style ... */
941       ddp->prototyped
942
943 #endif /* defined (UNPROTOIZE) */
944       )
945           /* ... then the containing file needs converting.  */
946           return -1;
947   return 0;
948 }
949
950 /* Return 1 if the file name NAME is in a directory
951    that should be converted.  */
952
953 static int
954 directory_specified_p (name)
955      const char *name;
956 {
957   struct string_list *p;
958
959   for (p = directory_list; p; p = p->next)
960     if (!strncmp (name, p->name, strlen (p->name))
961         && name[strlen (p->name)] == '/')
962       {
963         const char *q = name + strlen (p->name) + 1;
964
965         /* If there are more slashes, it's in a subdir, so
966            this match doesn't count.  */
967         while (*q)
968           if (*q++ == '/')
969             goto lose;
970         return 1;
971
972       lose: ;
973       }
974
975   return 0;
976 }
977
978 /* Return 1 if the file named NAME should be excluded from conversion.  */
979
980 static int
981 file_excluded_p (name)
982      const char *name;
983 {
984   struct string_list *p;
985   int len = strlen (name);
986
987   for (p = exclude_list; p; p = p->next)
988     if (!strcmp (name + len - strlen (p->name), p->name)
989         && name[len - strlen (p->name) - 1] == '/')
990       return 1;
991
992   return 0;
993 }
994
995 /* Construct a new element of a string_list.
996    STRING is the new element value, and REST holds the remaining elements.  */
997
998 static struct string_list *
999 string_list_cons (string, rest)
1000      char *string;
1001      struct string_list *rest;      
1002 {
1003   struct string_list *temp
1004     = (struct string_list *) xmalloc (sizeof (struct string_list));
1005
1006   temp->next = rest;
1007   temp->name = string;
1008   return temp;
1009 }
1010 \f
1011 /* ??? The GNU convention for mentioning function args in its comments
1012    is to capitalize them.  So change "hash_tab_p" to HASH_TAB_P below.
1013    Likewise for all the other functions.  */
1014
1015 /* Given a hash table, apply some function to each node in the table. The
1016    table to traverse is given as the "hash_tab_p" argument, and the
1017    function to be applied to each node in the table is given as "func"
1018    argument.  */
1019
1020 static void
1021 visit_each_hash_node (hash_tab_p, func)
1022      const hash_table_entry *hash_tab_p;
1023      void (*func)();
1024 {
1025   const hash_table_entry *primary;
1026
1027   for (primary = hash_tab_p; primary < &hash_tab_p[HASH_TABLE_SIZE]; primary++)
1028     if (primary->symbol)
1029       {
1030         hash_table_entry *second;
1031
1032         (*func)(primary);
1033         for (second = primary->hash_next; second; second = second->hash_next)
1034           (*func) (second);
1035       }
1036 }
1037
1038 /* Initialize all of the fields of a new hash table entry, pointed
1039    to by the "p" parameter.  Note that the space to hold the entry
1040    is assumed to have already been allocated before this routine is
1041    called.  */
1042
1043 static hash_table_entry *
1044 add_symbol (p, s)
1045      hash_table_entry *p;
1046      const char *s;
1047 {
1048   p->hash_next = NULL;
1049   p->symbol = dupstr (s);
1050   p->ddip = NULL;
1051   p->fip = NULL;
1052   return p;
1053 }
1054
1055 /* Look for a particular function name or filename in the particular
1056    hash table indicated by "hash_tab_p".  If the name is not in the
1057    given hash table, add it.  Either way, return a pointer to the
1058    hash table entry for the given name.  */
1059
1060 static hash_table_entry *
1061 lookup (hash_tab_p, search_symbol)
1062      hash_table_entry *hash_tab_p;
1063      const char *search_symbol;
1064 {
1065   int hash_value = 0;
1066   const char *search_symbol_char_p = search_symbol;
1067   hash_table_entry *p;
1068
1069   while (*search_symbol_char_p)
1070     hash_value += *search_symbol_char_p++;
1071   hash_value &= hash_mask;
1072   p = &hash_tab_p[hash_value];
1073   if (! p->symbol)
1074       return add_symbol (p, search_symbol);
1075   if (!strcmp (p->symbol, search_symbol))
1076     return p;
1077   while (p->hash_next)
1078     {
1079       p = p->hash_next;
1080       if (!strcmp (p->symbol, search_symbol))
1081         return p;
1082     }
1083   p->hash_next = (hash_table_entry *) xmalloc (sizeof (hash_table_entry));
1084   p = p->hash_next;
1085   return add_symbol (p, search_symbol);
1086 }
1087 \f
1088 /* Throw a def/dec record on the junk heap.
1089
1090    Also, since we are not using this record anymore, free up all of the
1091    stuff it pointed to.  */
1092
1093 static void
1094 free_def_dec (p)
1095      def_dec_info *p;
1096 {
1097   xfree (p->ansi_decl);
1098
1099 #ifndef UNPROTOIZE
1100   {
1101     const f_list_chain_item * curr;
1102     const f_list_chain_item * next;
1103
1104     for (curr = p->f_list_chain; curr; curr = next)
1105       {
1106         next = curr->chain_next;
1107         xfree (curr);
1108       }
1109   }
1110 #endif /* !defined (UNPROTOIZE) */
1111
1112   xfree (p);
1113 }
1114
1115 /* Unexpand as many macro symbol as we can find.
1116
1117    If the given line must be unexpanded, make a copy of it in the heap and
1118    return a pointer to the unexpanded copy.  Otherwise return NULL.  */
1119
1120 static char *
1121 unexpand_if_needed (aux_info_line)
1122      const char *aux_info_line;
1123 {
1124   static char *line_buf = 0;
1125   static int line_buf_size = 0;
1126   const unexpansion* unexp_p;
1127   int got_unexpanded = 0;
1128   const char *s;
1129   char *copy_p = line_buf;
1130
1131   if (line_buf == 0)
1132     {
1133       line_buf_size = 1024;
1134       line_buf = (char *) xmalloc (line_buf_size);
1135     }
1136
1137   copy_p = line_buf;
1138
1139   /* Make a copy of the input string in line_buf, expanding as necessary.  */
1140
1141   for (s = aux_info_line; *s != '\n'; )
1142     {
1143       for (unexp_p = unexpansions; unexp_p->expanded; unexp_p++)
1144         {
1145           const char *in_p = unexp_p->expanded;
1146           size_t len = strlen (in_p);
1147
1148           if (*s == *in_p && !strncmp (s, in_p, len) && !is_id_char (s[len]))
1149             {
1150               int size = strlen (unexp_p->contracted);
1151               got_unexpanded = 1;
1152               if (copy_p + size - line_buf >= line_buf_size)
1153                 {
1154                   int offset = copy_p - line_buf;
1155                   line_buf_size *= 2;
1156                   line_buf_size += size;
1157                   line_buf = (char *) xrealloc (line_buf, line_buf_size);
1158                   copy_p = line_buf + offset;
1159                 }
1160               strcpy (copy_p, unexp_p->contracted);
1161               copy_p += size;
1162
1163               /* Assume the there will not be another replacement required
1164                  within the text just replaced.  */
1165
1166               s += len;
1167               goto continue_outer;
1168             }
1169         }
1170       if (copy_p - line_buf == line_buf_size)
1171         {
1172           int offset = copy_p - line_buf;
1173           line_buf_size *= 2;
1174           line_buf = (char *) xrealloc (line_buf, line_buf_size);
1175           copy_p = line_buf + offset;
1176         }
1177       *copy_p++ = *s++;
1178 continue_outer: ;
1179     }
1180   if (copy_p + 2 - line_buf >= line_buf_size)
1181     {
1182       int offset = copy_p - line_buf;
1183       line_buf_size *= 2;
1184       line_buf = (char *) xrealloc (line_buf, line_buf_size);
1185       copy_p = line_buf + offset;
1186     }
1187   *copy_p++ = '\n';
1188   *copy_p++ = '\0';
1189
1190   return (got_unexpanded ? dupstr (line_buf) : 0);
1191 }
1192 \f
1193 /* Return the absolutized filename for the given relative
1194    filename.  Note that if that filename is already absolute, it may
1195    still be returned in a modified form because this routine also
1196    eliminates redundant slashes and single dots and eliminates double
1197    dots to get a shortest possible filename from the given input
1198    filename.  The absolutization of relative filenames is made by
1199    assuming that the given filename is to be taken as relative to
1200    the first argument (cwd) or to the current directory if cwd is
1201    NULL.  */
1202
1203 static char *
1204 abspath (cwd, rel_filename)
1205      const char *cwd;
1206      const char *rel_filename;
1207 {
1208   /* Setup the current working directory as needed.  */
1209   const char *cwd2 = (cwd) ? cwd : cwd_buffer;
1210   char *const abs_buffer
1211     = (char *) alloca (strlen (cwd2) + strlen (rel_filename) + 1);
1212   char *endp = abs_buffer;
1213   char *outp, *inp;
1214
1215   /* Copy the  filename (possibly preceeded by the current working
1216      directory name) into the absolutization buffer.  */
1217
1218   {
1219     const char *src_p;
1220
1221     if (rel_filename[0] != '/')
1222       {
1223         src_p = cwd2;
1224         while (*endp++ = *src_p++)
1225           continue;
1226         *(endp-1) = '/';                        /* overwrite null */
1227       }
1228     src_p = rel_filename;
1229     while (*endp++ = *src_p++)
1230       continue;
1231     if (endp[-1] == '/')
1232       *endp = '\0';
1233   }
1234
1235   /* Now make a copy of abs_buffer into abs_buffer, shortening the
1236      filename (by taking out slashes and dots) as we go.  */
1237
1238   outp = inp = abs_buffer;
1239   *outp++ = *inp++;             /* copy first slash */
1240   for (;;)
1241     {
1242       if (!inp[0])
1243         break;
1244       else if (inp[0] == '/' && outp[-1] == '/')
1245         {
1246           inp++;
1247           continue;
1248         }
1249       else if (inp[0] == '.' && outp[-1] == '/')
1250         {
1251           if (!inp[1])
1252                   break;
1253           else if (inp[1] == '/')
1254             {
1255                     inp += 2;
1256                     continue;
1257             }
1258           else if ((inp[1] == '.') && (inp[2] == 0 || inp[2] == '/'))
1259             {
1260                     inp += (inp[2] == '/') ? 3 : 2;
1261                     outp -= 2;
1262                     while (outp >= abs_buffer && *outp != '/')
1263                 outp--;
1264                     if (outp < abs_buffer)
1265                 {
1266                   /* Catch cases like /.. where we try to backup to a
1267                      point above the absolute root of the logical file
1268                      system.  */
1269
1270                   fprintf (stderr, "%s: invalid file name: %s\n",
1271                            pname, rel_filename);
1272                   exit (1);
1273                 }
1274                     *++outp = '\0';
1275                     continue;
1276             }
1277         }
1278       *outp++ = *inp++;
1279     }
1280
1281   /* On exit, make sure that there is a trailing null, and make sure that
1282      the last character of the returned string is *not* a slash.  */
1283
1284   *outp = '\0';
1285   if (outp[-1] == '/')
1286     *--outp  = '\0';
1287
1288   /* Make a copy (in the heap) of the stuff left in the absolutization
1289      buffer and return a pointer to the copy.  */
1290
1291   return dupstr (abs_buffer);
1292 }
1293 \f
1294 /* Given a filename (and possibly a directory name from which the filename
1295    is relative) return a string which is the shortest possible
1296    equivalent for the corresponding full (absolutized) filename.  The
1297    shortest possible equivalent may be constructed by converting the
1298    absolutized filename to be a relative filename (i.e. relative to
1299    the actual current working directory).  However if a relative filename
1300    is longer, then the full absolute filename is returned.
1301
1302    KNOWN BUG:
1303
1304    Note that "simple-minded" conversion of any given type of filename (either
1305    relative or absolute) may not result in a valid equivalent filename if any
1306    subpart of the original filename is actually a symbolic link.  */
1307
1308 static const char *
1309 shortpath (cwd, filename)
1310      const char *cwd;
1311      const char *filename;
1312 {
1313   char *rel_buffer;
1314   char *rel_buf_p;
1315   char *cwd_p = cwd_buffer;
1316   char *path_p;
1317   int unmatched_slash_count = 0;
1318
1319   path_p = abspath (cwd, filename);
1320   rel_buf_p = rel_buffer = (char *) xmalloc (strlen (path_p) + 1);
1321
1322   while (*cwd_p && (*cwd_p == *path_p))
1323     {
1324       cwd_p++;
1325       path_p++;
1326     }
1327   if (!*cwd_p)                  /* whole pwd matched */
1328     {
1329       if (!*path_p)             /* input *is* the current path! */
1330         return ".";
1331       else
1332         return ++path_p;
1333     }
1334   else
1335     {
1336       if (*path_p)
1337         {
1338           --cwd_p;
1339           --path_p;
1340           while (*cwd_p != '/')         /* backup to last slash */
1341             {
1342               --cwd_p;
1343               --path_p;
1344             }
1345           cwd_p++;
1346           path_p++;
1347           unmatched_slash_count++;
1348         }
1349       while (*cwd_p)
1350         if (*cwd_p++ == '/')
1351                 unmatched_slash_count++;
1352       while (unmatched_slash_count--)
1353         {
1354           *rel_buf_p++ = '.';
1355           *rel_buf_p++ = '.';
1356           *rel_buf_p++ = '/';
1357         }
1358       while (*rel_buf_p++ = *path_p++)
1359         continue;
1360       --rel_buf_p;
1361       if (*(rel_buf_p-1) == '/')
1362         *--rel_buf_p = '\0';
1363       if (strlen (rel_buffer) > (unsigned) strlen (filename))
1364         strcpy (rel_buffer, filename);
1365       return rel_buffer;
1366     }
1367 }
1368 \f
1369 /* Lookup the given filename in the hash table for filenames.  If it is a
1370    new one, then the hash table info pointer will be null.  In this case,
1371    we create a new file_info record to go with the filename, and we initialize
1372    that record with some reasonable values.  */
1373
1374 static file_info *
1375 find_file (filename, do_not_stat)
1376      char *filename;
1377      int do_not_stat;
1378 /* FILENAME was const, but that causes a warning on AIX when calling stat.
1379    That is probably a bug in AIX, but might as well avoid the warning.  */
1380 {
1381   hash_table_entry *hash_entry_p;
1382
1383   hash_entry_p = lookup (filename_primary, filename);
1384   if (hash_entry_p->fip)
1385     return hash_entry_p->fip;
1386   else
1387     {
1388       struct stat stat_buf;
1389       file_info *file_p = (file_info *) xmalloc (sizeof (file_info));
1390
1391       /* If we cannot get status on any given source file, give a warning
1392          and then just set its time of last modification to infinity.  */
1393
1394       if (do_not_stat)
1395         stat_buf.st_mtime = (time_t) 0;
1396       else
1397         {
1398           if (my_stat (filename, &stat_buf) == -1)
1399             {
1400               fprintf (stderr, "%s: error: can't get status of `%s': %s\n",
1401                        pname, shortpath (NULL, filename), sys_errlist[errno]);
1402               stat_buf.st_mtime = (time_t) -1;
1403             }
1404         }
1405
1406       hash_entry_p->fip = file_p;
1407       file_p->hash_entry = hash_entry_p;
1408       file_p->defs_decs = NULL;
1409       file_p->mtime = stat_buf.st_mtime;
1410       return file_p;
1411     }
1412 }
1413
1414 /* Generate a fatal error because some part of the aux_info file is
1415    messed up.  */
1416
1417 static void
1418 aux_info_corrupted ()
1419 {
1420   fprintf (stderr, "\n%s: fatal error: aux info file corrupted at line %d\n",
1421            pname, current_aux_info_lineno);
1422   exit (1);
1423 }
1424
1425 /* ??? This comment is vague.  Say what the condition is for.  */
1426 /* Check to see that a condition is true.  This is kind of like an assert.  */
1427
1428 static void
1429 check_aux_info (cond)
1430      int cond;
1431 {
1432   if (! cond)
1433     aux_info_corrupted ();
1434 }
1435
1436 /* Given a pointer to the closing right parenthesis for a particular formals
1437    list (in a aux_info file) find the corresponding left parenthesis and
1438    return a pointer to it.  */
1439
1440 static const char *
1441 find_corresponding_lparen (p)
1442      const char *p;
1443 {
1444   const char *q;
1445   int paren_depth;
1446
1447   for (paren_depth = 1, q = p-1; paren_depth; q--)
1448     {
1449       switch (*q)
1450         {
1451           case ')':
1452             paren_depth++;
1453             break;
1454           case '(':
1455             paren_depth--;
1456             break;
1457         }
1458     }
1459   return ++q;
1460 }
1461 \f
1462 /* Given a line from  an aux info file, and a time at which the aux info
1463    file it came from was created, check to see if the item described in
1464    the line comes from a file which has been modified since the aux info
1465    file was created.  If so, return non-zero, else return zero.  */
1466
1467 static int
1468 referenced_file_is_newer (l, aux_info_mtime)
1469      const char *l;
1470      time_t aux_info_mtime;
1471 {
1472   const char *p;
1473   file_info *fi_p;
1474   char *filename;
1475
1476   check_aux_info (l[0] == '/');
1477   check_aux_info (l[1] == '*');
1478   check_aux_info (l[2] == ' ');
1479
1480   {
1481     const char *filename_start = p = l + 3;
1482
1483     while (*p != ':')
1484       p++;
1485     filename = (char *) alloca ((size_t) (p - filename_start) + 1);
1486     strncpy (filename, filename_start, (size_t) (p - filename_start));
1487     filename[p-filename_start] = '\0';
1488   }
1489
1490   /* Call find_file to find the file_info record associated with the file
1491      which contained this particular def or dec item.  Note that this call
1492      may cause a new file_info record to be created if this is the first time
1493      that we have ever known about this particular file.  */
1494
1495   fi_p = find_file (abspath (invocation_filename, filename), 0);
1496
1497   return (fi_p->mtime > aux_info_mtime);
1498 }
1499 \f
1500 /* Given a line of info from the aux_info file, create a new
1501    def_dec_info record to remember all of the important information about
1502    a function definition or declaration.
1503
1504    Link this record onto the list of such records for the particular file in
1505    which it occured in proper (descending) line number order (for now).
1506
1507    If there is an identical record already on the list for the file, throw
1508    this one away.  Doing so takes care of the (useless and troublesome)
1509    duplicates which are bound to crop up due to multiple inclusions of any
1510    given individual header file.
1511
1512    Finally, link the new def_dec record onto the list of such records
1513    pertaining to this particular function name.  */
1514
1515 static void
1516 save_def_or_dec (l, is_syscalls)
1517      const char *l;
1518      int is_syscalls;
1519 {
1520   const char *p;
1521   const char *semicolon_p;
1522   def_dec_info *def_dec_p = (def_dec_info *) xmalloc (sizeof (def_dec_info));
1523
1524 #ifndef UNPROTOIZE
1525   def_dec_p->written = 0;
1526 #endif /* !defined (UNPROTOIZE) */
1527
1528   /* Start processing the line by picking off 5 pieces of information from
1529      the left hand end of the line.  These are filename, line number,
1530      new/old/implicit flag (new = ANSI prototype format), definition or
1531      declaration flag, and extern/static flag).  */
1532
1533   check_aux_info (l[0] == '/');
1534   check_aux_info (l[1] == '*');
1535   check_aux_info (l[2] == ' ');
1536
1537   {
1538     const char *filename_start = p = l + 3;
1539     char *filename;
1540
1541     while (*p != ':')
1542       p++;
1543     filename = (char *) alloca ((size_t) (p - filename_start) + 1);
1544     strncpy (filename, filename_start, (size_t) (p - filename_start));
1545     filename[p-filename_start] = '\0';
1546
1547     /* Call find_file to find the file_info record associated with the file
1548        which contained this particular def or dec item.  Note that this call
1549        may cause a new file_info record to be created if this is the first time
1550        that we have ever known about this particular file.
1551   
1552        Note that we started out by forcing all of the base source file names
1553        (i.e. the names of the aux_info files with the .X stripped off) into the
1554        filenames hash table, and we simultaneously setup file_info records for
1555        all of these base file names (even if they may be useless later).
1556        The file_info records for all of these "base" file names (properly)
1557        act as file_info records for the "original" (i.e. un-included) files
1558        which were submitted to gcc for compilation (when the -fgen-aux-info
1559        option was used).  */
1560   
1561     def_dec_p->file = find_file (abspath (invocation_filename, filename), is_syscalls);
1562   }
1563
1564   {
1565     const char *line_number_start = ++p;
1566     char line_number[10];
1567
1568     while (*p != ':')
1569       p++;
1570     strncpy (line_number, line_number_start, (size_t) (p - line_number_start));
1571     line_number[p-line_number_start] = '\0';
1572     def_dec_p->line = atoi (line_number);
1573   }
1574
1575   /* Check that this record describes a new-style, old-style, or implicit
1576      definition or declaration.  */
1577
1578   p++;  /* Skip over the `:'. */
1579   check_aux_info ((*p == 'N') || (*p == 'O') || (*p == 'I'));
1580
1581   /* Is this a new style (ANSI prototyped) definition or declaration? */
1582
1583   def_dec_p->prototyped = (*p == 'N');
1584
1585 #ifndef UNPROTOIZE
1586
1587   /* Is this an implicit declaration? */
1588
1589   def_dec_p->is_implicit = (*p == 'I');
1590
1591 #endif /* !defined (UNPROTOIZE) */
1592
1593   p++;
1594
1595   check_aux_info ((*p == 'C') || (*p == 'F'));
1596
1597   /* Is this item a function definition (F) or a declaration (C).  Note that
1598      we treat item taken from the syscalls file as though they were function
1599      definitions regardless of what the stuff in the file says.  */
1600
1601   def_dec_p->is_func_def = ((*p++ == 'F') || is_syscalls);
1602
1603 #ifndef UNPROTOIZE
1604   def_dec_p->definition = 0;    /* Fill this in later if protoizing.  */
1605 #endif /* !defined (UNPROTOIZE) */
1606
1607   check_aux_info (*p++ == ' ');
1608   check_aux_info (*p++ == '*');
1609   check_aux_info (*p++ == '/');
1610   check_aux_info (*p++ == ' ');
1611
1612 #ifdef UNPROTOIZE
1613   check_aux_info ((!strncmp (p, "static", 6)) || (!strncmp (p, "extern", 6)));
1614 #else /* !defined (UNPROTOIZE) */
1615   if (!strncmp (p, "static", 6))
1616     def_dec_p->is_static = -1;
1617   else if (!strncmp (p, "extern", 6))
1618     def_dec_p->is_static = 0;
1619   else
1620     check_aux_info (0); /* Didn't find either `extern' or `static'.  */
1621 #endif /* !defined (UNPROTOIZE) */
1622
1623   {
1624     const char *ansi_start = p;
1625
1626     p += 6;     /* Pass over the "static" or "extern".  */
1627
1628     /* We are now past the initial stuff.  Search forward from here to find
1629        the terminating semicolon that should immediately follow the entire
1630        ANSI format function declaration.  */
1631
1632     while (*++p != ';')
1633       continue;
1634
1635     semicolon_p = p;
1636
1637     /* Make a copy of the ansi declaration part of the line from the aux_info
1638        file.  */
1639
1640     def_dec_p->ansi_decl
1641       = dupnstr (ansi_start, (size_t) ((semicolon_p+1) - ansi_start));
1642   }
1643
1644   /* Backup and point at the final right paren of the final argument list.  */
1645
1646   p--;
1647
1648   /* Now isolate a whole set of formal argument lists, one-by-one.  Normally,
1649      there will only be one list to isolate, but there could be more.  */
1650
1651   def_dec_p->f_list_count = 0;
1652
1653 #ifndef UNPROTOIZE
1654   def_dec_p->f_list_chain = NULL;
1655 #endif /* !defined (UNPROTOIZE) */
1656
1657   for (;;)
1658     {
1659       const char *left_paren_p = find_corresponding_lparen (p);
1660 #ifndef UNPROTOIZE
1661       {
1662         f_list_chain_item *cip =
1663           (f_list_chain_item *) xmalloc (sizeof (f_list_chain_item));
1664
1665         cip->formals_list
1666           = dupnstr (left_paren_p + 1, (size_t) (p - (left_paren_p+1)));
1667       
1668         /* Add the new chain item at the head of the current list.  */
1669
1670         cip->chain_next = def_dec_p->f_list_chain;
1671         def_dec_p->f_list_chain = cip;
1672       }
1673 #endif /* !defined (UNPROTOIZE) */
1674       def_dec_p->f_list_count++;
1675
1676       p = left_paren_p - 2;
1677
1678       /* p must now point either to another right paren, or to the last
1679          character of the name of the function that was declared/defined.
1680          If p points to another right paren, then this indicates that we
1681          are dealing with multiple formals lists.  In that case, there
1682          really should be another right paren preceeding this right paren.  */
1683
1684       if (*p != ')')
1685         break;
1686       else
1687         check_aux_info (*--p == ')');
1688     }
1689
1690
1691   {
1692     const char *past_fn = p + 1;
1693
1694     check_aux_info (*past_fn == ' ');
1695
1696     /* Scan leftwards over the identifier that names the function.  */
1697
1698     while (is_id_char (*p))
1699       p--;
1700     p++;
1701
1702     /* p now points to the leftmost character of the function name.  */
1703
1704     {
1705       char *fn_string = (char *) alloca (past_fn - p + 1);
1706
1707       strncpy (fn_string, p, (size_t) (past_fn - p));
1708       fn_string[past_fn-p] = '\0';
1709       def_dec_p->hash_entry = lookup (function_name_primary, fn_string);
1710     }
1711   }
1712
1713   /* Look at all of the defs and decs for this function name that we have
1714      collected so far.  If there is already one which is at the same
1715      line number in the same file, then we can discard this new def_dec_info
1716      record.
1717
1718      As an extra assurance that any such pair of (nominally) identical
1719      function declarations are in fact identical, we also compare the
1720      ansi_decl parts of the lines from the aux_info files just to be on
1721      the safe side.
1722
1723      This comparison will fail if (for instance) the user was playing
1724      messy games with the preprocessor which ultimately causes one
1725      function declaration in one header file to look differently when
1726      that file is included by two (or more) other files.  */
1727
1728   {
1729     const def_dec_info *other;
1730
1731     for (other = def_dec_p->hash_entry->ddip; other; other = other->next_for_func)
1732       {
1733         if (def_dec_p->line == other->line && def_dec_p->file == other->file)
1734           {
1735             if (strcmp (def_dec_p->ansi_decl, other->ansi_decl))
1736               {
1737                 fprintf (stderr, "%s: error: declaration of function `%s' at %s(%d) takes different forms\n",
1738                          pname,
1739                          def_dec_p->hash_entry->symbol,
1740                          def_dec_p->file->hash_entry->symbol,
1741                          def_dec_p->line);
1742                 exit (1);
1743               }
1744             free_def_dec (def_dec_p);
1745             return;
1746           }
1747       }
1748   }
1749
1750 #ifdef UNPROTOIZE
1751
1752   /* If we are doing unprotoizing, we must now setup the pointers that will
1753      point to the K&R name list and to the K&R argument declarations list.
1754
1755      Note that if this is only a function declaration, then we should not
1756      expect to find any K&R style formals list following the ANSI-style
1757      formals list.  This is because GCC knows that such information is
1758      useless in the case of function declarations (function definitions
1759      are a different story however).
1760
1761      Since we are unprotoizing, we don't need any such lists anyway.
1762      All we plan to do is to delete all characters between ()'s in any
1763      case.  */
1764
1765   def_dec_p->formal_names = NULL;
1766   def_dec_p->formal_decls = NULL;
1767
1768   if (def_dec_p->is_func_def)
1769     {
1770       p = semicolon_p;
1771       check_aux_info (*++p == ' ');
1772       check_aux_info (*++p == '/');
1773       check_aux_info (*++p == '*');
1774       check_aux_info (*++p == ' ');
1775       check_aux_info (*++p == '(');
1776
1777       {
1778         const char *kr_names_start = ++p;   /* Point just inside '('. */
1779
1780         while (*p++ != ')')
1781           continue;
1782         p--;            /* point to closing right paren */
1783
1784         /* Make a copy of the K&R parameter names list.  */
1785
1786         def_dec_p->formal_names
1787           = dupnstr (kr_names_start, (size_t) (p - kr_names_start));
1788       }
1789
1790       check_aux_info (*++p == ' ');
1791       p++;
1792
1793       /* p now points to the first character of the K&R style declarations
1794          list (if there is one) or to the star-slash combination that ends
1795          the comment in which such lists get embedded.  */
1796
1797       /* Make a copy of the K&R formal decls list and set the def_dec record
1798          to point to it.  */
1799
1800       if (*p == '*')            /* Are there no K&R declarations? */
1801         {
1802           check_aux_info (*++p == '/');
1803           def_dec_p->formal_decls = "";
1804         }
1805       else
1806         {
1807           const char *kr_decls_start = p;
1808
1809           while (p[0] != '*' || p[1] != '/')
1810             p++;
1811           p--;
1812
1813           check_aux_info (*p == ' ');
1814
1815           def_dec_p->formal_decls
1816             = dupnstr (kr_decls_start, (size_t) (p - kr_decls_start));
1817         }
1818
1819       /* Handle a special case.  If we have a function definition marked as
1820          being in "old" style, and if it's formal names list is empty, then
1821          it may actually have the string "void" in its real formals list
1822          in the original source code.  Just to make sure, we will get setup
1823          to convert such things anyway.
1824
1825          This kludge only needs to be here because of an insurmountable
1826          problem with generating .X files.  */
1827
1828       if (!def_dec_p->prototyped && !*def_dec_p->formal_names)
1829         def_dec_p->prototyped = 1;
1830     }
1831
1832   /* Since we are unprotoizing, if this item is already in old (K&R) style,
1833      we can just ignore it.  If that is true, throw away the itme now.  */
1834
1835   if (!def_dec_p->prototyped)
1836     {
1837       free_def_dec (def_dec_p);
1838       return;
1839     }
1840
1841 #endif /* defined (UNPROTOIZE) */
1842
1843   /* Add this record to the head of the list of records pertaining to this
1844      particular function name.  */
1845
1846   def_dec_p->next_for_func = def_dec_p->hash_entry->ddip;
1847   def_dec_p->hash_entry->ddip = def_dec_p;
1848
1849   /* Add this new def_dec_info record to the sorted list of def_dec_info
1850      records for this file.  Note that we don't have to worry about duplicates
1851      (caused by multiple inclusions of header files) here because we have
1852      already eliminated duplicates above.  */
1853
1854   if (!def_dec_p->file->defs_decs)
1855     {
1856       def_dec_p->file->defs_decs = def_dec_p;
1857       def_dec_p->next_in_file = NULL;
1858     }
1859   else
1860     {
1861       int line = def_dec_p->line;
1862       const def_dec_info *prev = NULL;
1863       const def_dec_info *curr = def_dec_p->file->defs_decs;
1864       const def_dec_info *next = curr->next_in_file;
1865
1866       while (next && (line < curr->line))
1867         {
1868           prev = curr;
1869           curr = next;
1870           next = next->next_in_file;
1871         }
1872       if (line >= curr->line)
1873         {
1874           def_dec_p->next_in_file = curr;
1875           if (prev)
1876             ((NONCONST def_dec_info *) prev)->next_in_file = def_dec_p;
1877           else
1878             def_dec_p->file->defs_decs = def_dec_p;
1879         }
1880       else      /* assert (next == NULL); */
1881         {
1882           ((NONCONST def_dec_info *) curr)->next_in_file = def_dec_p;
1883           /* assert (next == NULL); */
1884           def_dec_p->next_in_file = next;
1885         }
1886     }
1887 }
1888 \f
1889 /* Rewrite the options list used to recompile base source files.  All we are
1890    really doing here is removing -g, -O, -S, -c, and -o options, and then
1891    adding a final group of options like '-fgen-aux-info -S  -o /dev/null'.  */
1892
1893 static void
1894 munge_compile_params (params_list)
1895      const char *params_list;
1896 {
1897   char **temp_params = (char **) alloca (strlen (params_list) + 10);
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 }