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