OSDN Git Service

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