OSDN Git Service

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