OSDN Git Service

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