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