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