OSDN Git Service

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