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