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