OSDN Git Service

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