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