OSDN Git Service

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