OSDN Git Service

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