OSDN Git Service

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