OSDN Git Service

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