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