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