OSDN Git Service

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