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