OSDN Git Service

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