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