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