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