OSDN Git Service

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