]> gcc.gnu.org Git - gcc.git/blame - gcc/protoize.c
# Fix misspellings in comments.
[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,
f72aed24 53 including SunOS 4.1.1. Which we don't classify as POSIX. */
f5188608
RS
54/* In case this is a POSIX system with an ANSI C compiler,
55 ask for definition of all POSIX facilities. */
56#undef _POSIX_SOURCE
57#define _POSIX_SOURCE
58#endif
59
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 77#include "getopt.h"
a4c17831 78#undef getopt
5f8037c4 79
5f8037c4 80extern int errno;
a2b22788
RS
81extern char *sys_errlist[];
82extern char *version_string;
5f8037c4 83
5f8037c4
RS
84/* Systems which are compatible only with POSIX 1003.1-1988 (but *not*
85 with POSIX 1003.1-1990), e.g. Ultrix 4.2, might not have
86 const qualifiers in the prototypes in the system include files.
87 Unfortunately, this can lead to GCC issuing lots of warnings for
88 calls to the following functions. To eliminate these warnings we
89 provide the following #defines. */
90
34e56753
RS
91#define my_access(file,flag) access((char *)file, flag)
92#define my_stat(file,pkt) stat((char *)file, pkt)
93#define my_execvp(prog,argv) execvp((char *)prog, (char **)argv)
94#define my_link(file1, file2) link((char *)file1, (char *)file2)
95#define my_unlink(file) unlink((char *)file)
96#define my_open(file, mode, flag) open((char *)file, mode, flag)
97#define my_chmod(file, mode) chmod((char *)file, mode)
98
f5188608 99extern char *getpwd ();
5f8037c4 100
34e56753 101/* Aliases for pointers to void.
f5188608
RS
102 These were made to facilitate compilation with old brain-dead DEC C
103 compilers which didn't properly grok `void*' types. */
5f8037c4 104
34e56753
RS
105#ifdef __STDC__
106typedef void * pointer_type;
107typedef const void * const_pointer_type;
108#else
109typedef char * pointer_type;
110typedef char * const_pointer_type;
111#endif
112
113#if defined(POSIX)
114
115#include <stdlib.h>
116#include <unistd.h>
117#include <signal.h>
118#include <fcntl.h>
119#include <string.h>
5f8037c4 120
a2b22788 121#else /* !defined(POSIX) */
5f8037c4
RS
122
123#define R_OK 4 /* Test for Read permission */
124#define W_OK 2 /* Test for Write permission */
125#define X_OK 1 /* Test for eXecute permission */
126#define F_OK 0 /* Test for existence of File */
127
128#define O_RDONLY 0
129#define O_WRONLY 1
130
a2b22788
RS
131/* Declaring stat or __flsbuf with a prototype
132 causes conflicts with system headers on some systems. */
5f8037c4 133
a2b22788 134#ifndef abort
34e56753 135extern VOLATILE void abort ();
a2b22788 136#endif
a019653e 137extern int kill ();
34e56753 138extern int creat ();
a2b22788 139#if 0 /* These conflict with stdio.h on some systems. */
5f8037c4
RS
140extern int fprintf (FILE *, const char *, ...);
141extern int printf (const char *, ...);
f5188608 142extern int open (const char *, int, ...);
a2b22788 143#endif /* 0 */
34e56753
RS
144extern void exit ();
145extern pointer_type malloc ();
146extern pointer_type realloc ();
147extern void free ();
148extern int read ();
149extern int write ();
150extern int close ();
151extern int fflush ();
152extern int atoi ();
153extern int puts ();
154extern int fputs ();
155extern int fputc ();
f5188608
RS
156extern int link ();
157extern int unlink ();
158extern int access ();
159extern int execvp ();
8241a41f 160#ifndef setjmp
34e56753 161extern int setjmp ();
8241a41f
RS
162#endif
163#ifndef longjmp
34e56753
RS
164extern void longjmp ();
165#endif
166
a019653e
RS
167extern char * strcat ();
168extern int strcmp ();
169extern char * strcpy ();
a2b22788 170#if 0 /* size_t from sys/types.h may fail to match GCC.
f5188608
RS
171 If so, we would get a warning from this. */
172extern size_t strlen ()
a2b22788 173#endif
a019653e
RS
174extern int strncmp ();
175extern char * strncpy ();
45ad788b 176extern char * rindex ();
5f8037c4 177
eb76eb5a
RS
178/* Fork is not declared because the declaration caused a conflict
179 on the HPPA. */
5f8037c4 180#if !(defined (USG) || defined (VMS))
5f8037c4 181#define fork vfork
eb76eb5a 182#endif /* (defined (USG) || defined (VMS)) */
5f8037c4 183
a019653e 184#endif /* !defined (POSIX) */
5f8037c4
RS
185
186/* Look for these where the `const' qualifier is intentionally cast aside. */
187
188#define NONCONST
189
34e56753 190/* Define a STRINGIFY macro that's right for ANSI or traditional C. */
5f8037c4 191
34e56753 192#ifdef __STDC__
5f8037c4 193#define STRINGIFY(STRING) #STRING
34e56753
RS
194#else
195#define STRINGIFY(STRING) "STRING"
196#endif
5f8037c4 197
5f8037c4
RS
198/* Define a default place to find the SYSCALLS.X file. */
199
200#ifndef STD_PROTO_DIR
201#define STD_PROTO_DIR "/usr/local/lib"
a019653e 202#endif /* !defined (STD_PROTO_DIR) */
5f8037c4 203
5f8037c4
RS
204/* Suffix of aux_info files. */
205
206static const char * const aux_info_suffix = ".X";
207
a2b22788 208/* String to attach to filenames for saved versions of original files. */
5f8037c4
RS
209
210static const char * const save_suffix = ".save";
211
212#ifndef UNPROTOIZE
213
214/* File name of the file which contains descriptions of standard system
215 routines. Note that we never actually do anything with this file per se,
216 but we do read in its corresponding aux_info file. */
217
d742f26c 218static const char syscalls_filename[] = "SYSCALLS.c";
5f8037c4
RS
219
220/* Default place to find the above file. */
221
222static const char * const default_syscalls_dir = STD_PROTO_DIR;
223
a2b22788 224/* Variable to hold the complete absolutized filename of the SYSCALLS.c.X
5f8037c4
RS
225 file. */
226
a2b22788 227static char * syscalls_absolute_filename;
5f8037c4 228
a019653e 229#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
230
231/* Type of the structure that holds information about macro unexpansions. */
232
233struct unexpansion_struct {
234 const char *expanded;
235 const char *contracted;
236};
237typedef struct unexpansion_struct unexpansion;
238
239/* A table of conversions that may need to be made for some (stupid) older
240 operating systems where these types are preprocessor macros rather than
241 typedefs (as they really ought to be).
242
243 WARNING: The contracted forms must be as small (or smaller) as the
244 expanded forms, or else havoc will ensue. */
245
246static const unexpansion unexpansions[] = {
247 { "struct _iobuf", "FILE" },
248 { 0, 0 }
249};
250
251/* The number of "primary" slots in the hash tables for filenames and for
252 function names. This can be as big or as small as you like, except that
253 it must be a power of two. */
254
255#define HASH_TABLE_SIZE (1 << 9)
256
257/* Bit mask to use when computing hash values. */
258
259static const int hash_mask = (HASH_TABLE_SIZE - 1);
260
261/* Make a table of default system include directories
262 just as it is done in cccp.c. */
263
264#ifndef STANDARD_INCLUDE_DIR
265#define STANDARD_INCLUDE_DIR "/usr/include"
266#endif
267
268#ifndef LOCAL_INCLUDE_DIR
269#define LOCAL_INCLUDE_DIR "/usr/local/include"
270#endif
271
8241a41f 272struct default_include { const char *fname; int cplusplus; } include_defaults[]
5f8037c4
RS
273#ifdef INCLUDE_DEFAULTS
274 = INCLUDE_DEFAULTS;
275#else
276 = {
277 /* Pick up GNU C++ specific include files. */
278 { GPLUSPLUS_INCLUDE_DIR, 1},
279 { GCC_INCLUDE_DIR, 0},
2a1bf18b 280 { TOOL_INCLUDE_DIR, 0},
5f8037c4
RS
281#ifdef CROSS_COMPILE
282 /* For cross-compilation, this dir name is generated
283 automatically in Makefile.in. */
284 { CROSS_INCLUDE_DIR, 0 },
285#else /* not CROSS_COMPILE */
286 { LOCAL_INCLUDE_DIR, 0},
287 /* Some systems have an extra dir of include files. */
288#ifdef SYSTEM_INCLUDE_DIR
289 { SYSTEM_INCLUDE_DIR, 0},
290#endif
5f8037c4 291 { STANDARD_INCLUDE_DIR, 0},
5f8037c4
RS
292#endif /* not CROSS_COMPILE */
293 { 0, 0}
294 };
295#endif /* no INCLUDE_DEFAULTS */
296
297/* Datatype for lists of directories or filenames. */
298struct string_list
299{
300 char *name;
301 struct string_list *next;
302};
303
304/* List of directories in which files should be converted. */
305
306struct string_list *directory_list;
307
308/* List of file names which should not be converted.
309 A file is excluded if the end of its name, following a /,
310 matches one of the names in this list. */
311
312struct string_list *exclude_list;
313
314/* The name of the other style of variable-number-of-parameters functions
315 (i.e. the style that we want to leave unconverted because we don't yet
316 know how to convert them to this style. This string is used in warning
317 messages. */
318
319/* Also define here the string that we can search for in the parameter lists
320 taken from the .X files which will unambiguously indicate that we have
321 found a varargs style function. */
322
323#ifdef UNPROTOIZE
324static const char * const other_var_style = "stdarg";
a019653e 325#else /* !defined (UNPROTOIZE) */
5f8037c4 326static const char * const other_var_style = "varargs";
a2b22788
RS
327/* Note that this is a string containing the expansion of va_alist.
328 But in `main' we discard all but the first token. */
a019653e
RS
329static const char *varargs_style_indicator = STRINGIFY (va_alist);
330#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
331
332/* The following two types are used to create hash tables. In this program,
333 there are two hash tables which are used to store and quickly lookup two
334 different classes of strings. The first type of strings stored in the
a2b22788 335 first hash table are absolute filenames of files which protoize needs to
5f8037c4
RS
336 know about. The second type of strings (stored in the second hash table)
337 are function names. It is this second class of strings which really
338 inspired the use of the hash tables, because there may be a lot of them. */
339
340typedef struct hash_table_entry_struct hash_table_entry;
341
342/* Do some typedefs so that we don't have to write "struct" so often. */
343
344typedef struct def_dec_info_struct def_dec_info;
345typedef struct file_info_struct file_info;
346typedef struct f_list_chain_item_struct f_list_chain_item;
347
348/* In the struct below, note that the "_info" field has two different uses
a2b22788
RS
349 depending on the type of hash table we are in (i.e. either the filenames
350 hash table or the function names hash table). In the filenames hash table
5f8037c4 351 the info fields of the entries point to the file_info struct which is
a2b22788 352 associated with each filename (1 per filename). In the function names
5f8037c4
RS
353 hash table, the info field points to the head of a singly linked list of
354 def_dec_info entries which are all defs or decs of the function whose
355 name is pointed to by the "symbol" field. Keeping all of the defs/decs
356 for a given function name on a special list specifically for that function
357 name makes it quick and easy to find out all of the important information
358 about a given (named) function. */
359
360struct hash_table_entry_struct {
361 hash_table_entry * hash_next; /* -> to secondary entries */
362 const char * symbol; /* -> to the hashed string */
363 union {
364 const def_dec_info * _ddip;
365 file_info * _fip;
366 } _info;
367};
368#define ddip _info._ddip
369#define fip _info._fip
370
371/* Define a type specifically for our two hash tables. */
372
373typedef hash_table_entry hash_table[HASH_TABLE_SIZE];
374
375/* The following struct holds all of the important information about any
a2b22788 376 single filename (e.g. file) which we need to know about. */
5f8037c4
RS
377
378struct file_info_struct {
379 const hash_table_entry * hash_entry; /* -> to associated hash entry */
380 const def_dec_info * defs_decs; /* -> to chain of defs/decs */
381 time_t mtime; /* Time of last modification. */
382};
383
384/* Due to the possibility that functions may return pointers to functions,
385 (which may themselves have their own parameter lists) and due to the
386 fact that returned pointers-to-functions may be of type "pointer-to-
387 function-returning-pointer-to-function" (ad nauseum) we have to keep
388 an entire chain of ANSI style formal parameter lists for each function.
389
390 Normally, for any given function, there will only be one formals list
391 on the chain, but you never know.
392
393 Note that the head of each chain of formals lists is pointed to by the
394 `f_list_chain' field of the corresponding def_dec_info record.
395
396 For any given chain, the item at the head of the chain is the *leftmost*
397 parameter list seen in the actual C language function declaration. If
398 there are other members of the chain, then these are linked in left-to-right
399 order from the head of the chain. */
400
401struct f_list_chain_item_struct {
402 const f_list_chain_item * chain_next; /* -> to next item on chain */
403 const char * formals_list; /* -> to formals list string */
404};
405
406/* The following struct holds all of the important information about any
407 single function definition or declaration which we need to know about.
408 Note that for unprotoize we don't need to know very much because we
409 never even create records for stuff that we don't intend to convert
410 (like for instance defs and decs which are already in old K&R format
411 and "implicit" function declarations). */
412
413struct def_dec_info_struct {
414 const def_dec_info * next_in_file; /* -> to rest of chain for file */
415 file_info * file; /* -> file_info for containing file */
416 int line; /* source line number of def/dec */
417 const char * ansi_decl; /* -> left end of ansi decl */
418 hash_table_entry * hash_entry; /* -> hash entry for function name */
419 unsigned int is_func_def; /* = 0 means this is a declaration */
420 const def_dec_info * next_for_func; /* -> to rest of chain for func name */
421 unsigned int f_list_count; /* count of formals lists we expect */
422 char prototyped; /* = 0 means already prototyped */
423#ifndef UNPROTOIZE
424 const f_list_chain_item * f_list_chain; /* -> chain of formals lists */
425 const def_dec_info * definition; /* -> def/dec containing related def */
6dc42e49 426 char is_static; /* = 0 means visibility is "extern" */
5f8037c4
RS
427 char is_implicit; /* != 0 for implicit func decl's */
428 char written; /* != 0 means written for implicit */
a019653e 429#else /* !defined (UNPROTOIZE) */
5f8037c4 430 const char * formal_names; /* -> to list of names of formals */
6dc42e49 431 const char * formal_decls; /* -> to string of formal declarations */
a019653e 432#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
433};
434
a2b22788 435/* Pointer to the tail component of the filename by which this program was
5f8037c4
RS
436 invoked. Used everywhere in error and warning messages. */
437
438static const char *pname;
439
440/* Error counter. Will be non-zero if we should give up at the next convenient
441 stopping point. */
442
443static int errors = 0;
444
445/* Option flags. */
446/* ??? These comments should say what the flag mean as well as the options
447 that set them. */
448
a019653e
RS
449/* File name to use for running gcc. Allows GCC 2 to be named
450 something other than gcc. */
8241a41f 451static const char *compiler_file_name = "gcc";
ef91d7e2 452
34e56753
RS
453static int version_flag = 0; /* Print our version number. */
454static int quiet_flag = 0; /* Don't print messages normally. */
455static int nochange_flag = 0; /* Don't convert, just say what files
456 we would have converted. */
457static int nosave_flag = 0; /* Don't save the old version. */
458static int keep_flag = 0; /* Don't delete the .X files. */
459static const char ** compile_params = 0; /* Option string for gcc. */
5f8037c4 460#ifdef UNPROTOIZE
34e56753
RS
461static const char *indent_string = " "; /* Indentation for newly
462 inserted parm decls. */
a019653e 463#else /* !defined (UNPROTOIZE) */
34e56753 464static int local_flag = 0; /* Insert new local decls (when?). */
5f8037c4 465static int global_flag = 0; /* set by -g option */
34e56753
RS
466static int cplusplus_flag = 0; /* Rename converted files to *.C. */
467static const char* nondefault_syscalls_dir = 0; /* Dir to look for
468 SYSCALLS.c.X in. */
a019653e 469#endif /* !defined (UNPROTOIZE) */
5f8037c4 470
bd0725f3
RS
471/* An index into the compile_params array where we should insert the source
472 file name when we are ready to exec the C compiler. A zero value indicates
a019653e 473 that we have not yet called munge_compile_params. */
5f8037c4 474
bd0725f3
RS
475static int input_file_name_index = 0;
476
477/* An index into the compile_params array where we should insert the filename
478 for the aux info file, when we run the C compiler. */
479static int aux_info_file_name_index = 0;
5f8037c4
RS
480
481/* Count of command line arguments which were "filename" arguments. */
482
a2b22788 483static int n_base_source_files = 0;
5f8037c4
RS
484
485/* Points to a malloc'ed list of pointers to all of the filenames of base
486 source files which were specified on the command line. */
487
a2b22788 488static const char **base_source_filenames;
5f8037c4
RS
489
490/* Line number of the line within the current aux_info file that we
491 are currently processing. Used for error messages in case the prototypes
492 info file is corrupted somehow. */
493
494static int current_aux_info_lineno;
495
496/* Pointer to the name of the source file currently being converted. */
497
a2b22788 498static const char *convert_filename;
5f8037c4
RS
499
500/* Pointer to relative root string (taken from aux_info file) which indicates
501 where directory the user was in when he did the compilation step that
502 produced the containing aux_info file. */
503
a2b22788 504static const char *invocation_filename;
5f8037c4
RS
505
506/* Pointer to the base of the input buffer that holds the original text for the
507 source file currently being converted. */
508
509static const char *orig_text_base;
510
511/* Pointer to the byte just beyond the end of the input buffer that holds the
512 original text for the source file currently being converted. */
513
514static const char *orig_text_limit;
515
516/* Pointer to the base of the input buffer that holds the cleaned text for the
517 source file currently being converted. */
518
519static const char *clean_text_base;
520
521/* Pointer to the byte just beyond the end of the input buffer that holds the
522 cleaned text for the source file currently being converted. */
523
524static const char *clean_text_limit;
525
526/* Pointer to the last byte in the cleaned text buffer that we have already
527 (virtually) copied to the output buffer (or decided to ignore). */
528
529static const char * clean_read_ptr;
530
531/* Pointer to the base of the output buffer that holds the replacement text
532 for the source file currently being converted. */
533
534static char *repl_text_base;
535
536/* Pointer to the byte just beyond the end of the output buffer that holds the
537 replacement text for the source file currently being converted. */
538
539static char *repl_text_limit;
540
541/* Pointer to the last byte which has been stored into the output buffer.
542 The next byte to be stored should be stored just past where this points
543 to. */
544
545static char * repl_write_ptr;
546
547/* Pointer into the cleaned text buffer for the source file we are currently
548 converting. This points to the first character of the line that we last
a019653e 549 did a "seek_to_line" to (see below). */
5f8037c4
RS
550
551static const char *last_known_line_start;
552
553/* Number of the line (in the cleaned text buffer) that we last did a
a019653e 554 "seek_to_line" to. Will be one if we just read a new source file
5f8037c4
RS
555 into the cleaned text buffer. */
556
557static int last_known_line_number;
558
a2b22788 559/* The filenames hash table. */
5f8037c4 560
a2b22788 561static hash_table filename_primary;
5f8037c4
RS
562
563/* The function names hash table. */
564
565static hash_table function_name_primary;
566
567/* The place to keep the recovery address which is used only in cases where
568 we get hopelessly confused by something in the cleaned original text. */
569
570static jmp_buf source_confusion_recovery;
571
a2b22788 572/* A pointer to the current directory filename (used by abspath). */
5f8037c4
RS
573
574static char *cwd_buffer;
575
576/* A place to save the read pointer until we are sure that an individual
577 attempt at editing will succeed. */
578
579static const char * saved_clean_read_ptr;
580
581/* A place to save the write pointer until we are sure that an individual
582 attempt at editing will succeed. */
583
584static char * saved_repl_write_ptr;
585
586/* Forward declaration. */
587
34e56753 588static const char *shortpath ();
5f8037c4
RS
589\f
590/* Allocate some space, but check that the allocation was successful. */
ff57c94e 591/* alloca.c uses this, so don't make it static. */
5f8037c4 592
ff57c94e 593pointer_type
34e56753
RS
594xmalloc (byte_count)
595 size_t byte_count;
5f8037c4
RS
596{
597 pointer_type rv;
598
34e56753
RS
599 rv = malloc (byte_count);
600 if (rv == NULL)
5f8037c4 601 {
667cc897 602 fprintf (stderr, "\n%s: virtual memory exceeded\n", pname);
5f8037c4
RS
603 exit (1);
604 return 0; /* avoid warnings */
605 }
606 else
607 return rv;
608}
609
610/* Reallocate some space, but check that the reallocation was successful. */
611
ff57c94e 612pointer_type
34e56753
RS
613xrealloc (old_space, byte_count)
614 pointer_type old_space;
615 size_t byte_count;
5f8037c4
RS
616{
617 pointer_type rv;
618
34e56753
RS
619 rv = realloc (old_space, byte_count);
620 if (rv == NULL)
5f8037c4 621 {
667cc897 622 fprintf (stderr, "\n%s: virtual memory exceeded\n", pname);
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);
45ad788b 807 dir_last_slash = rindex (dir_name, '/');
5f8037c4
RS
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);
45ad788b 841 dir_last_slash = rindex (dir_name, '/');
5f8037c4
RS
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 1408 {
667cc897 1409 fprintf (stderr, "%s: %s: can't get status: %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
858a47b1 1446 list (in an aux_info file) find the corresponding left parenthesis and
5f8037c4
RS
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 {
667cc897 1746 fprintf (stderr, "%s:%d: declaration of function `%s' takes different forms\n",
5f8037c4 1747 def_dec_p->file->hash_entry->symbol,
667cc897
RS
1748 def_dec_p->line,
1749 def_dec_p->hash_entry->symbol);
5f8037c4
RS
1750 exit (1);
1751 }
1752 free_def_dec (def_dec_p);
1753 return;
1754 }
1755 }
1756 }
1757
1758#ifdef UNPROTOIZE
1759
1760 /* If we are doing unprotoizing, we must now setup the pointers that will
1761 point to the K&R name list and to the K&R argument declarations list.
1762
1763 Note that if this is only a function declaration, then we should not
1764 expect to find any K&R style formals list following the ANSI-style
1765 formals list. This is because GCC knows that such information is
1766 useless in the case of function declarations (function definitions
1767 are a different story however).
1768
1769 Since we are unprotoizing, we don't need any such lists anyway.
1770 All we plan to do is to delete all characters between ()'s in any
1771 case. */
1772
1773 def_dec_p->formal_names = NULL;
1774 def_dec_p->formal_decls = NULL;
1775
1776 if (def_dec_p->is_func_def)
1777 {
1778 p = semicolon_p;
1779 check_aux_info (*++p == ' ');
1780 check_aux_info (*++p == '/');
1781 check_aux_info (*++p == '*');
1782 check_aux_info (*++p == ' ');
1783 check_aux_info (*++p == '(');
1784
1785 {
1786 const char *kr_names_start = ++p; /* Point just inside '('. */
1787
1788 while (*p++ != ')')
1789 continue;
1790 p--; /* point to closing right paren */
1791
1792 /* Make a copy of the K&R parameter names list. */
1793
1794 def_dec_p->formal_names
1795 = dupnstr (kr_names_start, (size_t) (p - kr_names_start));
1796 }
1797
1798 check_aux_info (*++p == ' ');
1799 p++;
1800
1801 /* p now points to the first character of the K&R style declarations
1802 list (if there is one) or to the star-slash combination that ends
1803 the comment in which such lists get embedded. */
1804
1805 /* Make a copy of the K&R formal decls list and set the def_dec record
1806 to point to it. */
1807
1808 if (*p == '*') /* Are there no K&R declarations? */
1809 {
1810 check_aux_info (*++p == '/');
1811 def_dec_p->formal_decls = "";
1812 }
1813 else
1814 {
1815 const char *kr_decls_start = p;
1816
1817 while (p[0] != '*' || p[1] != '/')
1818 p++;
1819 p--;
1820
1821 check_aux_info (*p == ' ');
1822
1823 def_dec_p->formal_decls
1824 = dupnstr (kr_decls_start, (size_t) (p - kr_decls_start));
1825 }
1826
1827 /* Handle a special case. If we have a function definition marked as
1828 being in "old" style, and if it's formal names list is empty, then
1829 it may actually have the string "void" in its real formals list
1830 in the original source code. Just to make sure, we will get setup
1831 to convert such things anyway.
1832
1833 This kludge only needs to be here because of an insurmountable
1834 problem with generating .X files. */
1835
1836 if (!def_dec_p->prototyped && !*def_dec_p->formal_names)
1837 def_dec_p->prototyped = 1;
1838 }
1839
1840 /* Since we are unprotoizing, if this item is already in old (K&R) style,
1841 we can just ignore it. If that is true, throw away the itme now. */
1842
1843 if (!def_dec_p->prototyped)
1844 {
1845 free_def_dec (def_dec_p);
1846 return;
1847 }
1848
a019653e 1849#endif /* defined (UNPROTOIZE) */
5f8037c4
RS
1850
1851 /* Add this record to the head of the list of records pertaining to this
1852 particular function name. */
1853
1854 def_dec_p->next_for_func = def_dec_p->hash_entry->ddip;
1855 def_dec_p->hash_entry->ddip = def_dec_p;
1856
1857 /* Add this new def_dec_info record to the sorted list of def_dec_info
1858 records for this file. Note that we don't have to worry about duplicates
1859 (caused by multiple inclusions of header files) here because we have
1860 already eliminated duplicates above. */
1861
1862 if (!def_dec_p->file->defs_decs)
1863 {
1864 def_dec_p->file->defs_decs = def_dec_p;
1865 def_dec_p->next_in_file = NULL;
1866 }
1867 else
1868 {
1869 int line = def_dec_p->line;
1870 const def_dec_info *prev = NULL;
1871 const def_dec_info *curr = def_dec_p->file->defs_decs;
1872 const def_dec_info *next = curr->next_in_file;
1873
1874 while (next && (line < curr->line))
1875 {
1876 prev = curr;
1877 curr = next;
1878 next = next->next_in_file;
1879 }
1880 if (line >= curr->line)
1881 {
1882 def_dec_p->next_in_file = curr;
1883 if (prev)
1884 ((NONCONST def_dec_info *) prev)->next_in_file = def_dec_p;
1885 else
1886 def_dec_p->file->defs_decs = def_dec_p;
1887 }
1888 else /* assert (next == NULL); */
1889 {
1890 ((NONCONST def_dec_info *) curr)->next_in_file = def_dec_p;
1891 /* assert (next == NULL); */
1892 def_dec_p->next_in_file = next;
1893 }
1894 }
1895}
1896\f
bd0725f3
RS
1897/* Set up the vector COMPILE_PARAMS which is the argument list for running GCC.
1898 Also set input_file_name_index and aux_info_file_name_index
1899 to the indices of the slots where the file names should go. */
1900
1901/* We initialize the vector by removing -g, -O, -S, -c, and -o options,
1902 and adding '-aux-info AUXFILE -S -o /dev/null INFILE' at the end. */
5f8037c4
RS
1903
1904static void
34e56753
RS
1905munge_compile_params (params_list)
1906 const char *params_list;
5f8037c4 1907{
bd0725f3
RS
1908 /* Build up the contents in a temporary vector
1909 that is so big that to has to be big enough. */
8241a41f 1910 const char **temp_params
6f4870cf 1911 = (const char **) alloca ((strlen (params_list) + 8) * sizeof (char *));
5f8037c4
RS
1912 int param_count = 0;
1913 const char *param;
1914
a019653e 1915 temp_params[param_count++] = compiler_file_name;
5f8037c4
RS
1916 for (;;)
1917 {
1918 while (isspace (*params_list))
1919 params_list++;
1920 if (!*params_list)
1921 break;
1922 param = params_list;
1923 while (*params_list && !isspace (*params_list))
1924 params_list++;
1925 if (param[0] != '-')
1926 temp_params[param_count++]
1927 = dupnstr (param, (size_t) (params_list - param));
1928 else
1929 {
1930 switch (param[1])
1931 {
1932 case 'g':
1933 case 'O':
1934 case 'S':
1935 case 'c':
1936 break; /* Don't copy these. */
1937 case 'o':
1938 while (isspace (*params_list))
1939 params_list++;
1940 while (*params_list && !isspace (*params_list))
1941 params_list++;
1942 break;
1943 default:
1944 temp_params[param_count++]
1945 = dupnstr (param, (size_t) (params_list - param));
1946 }
1947 }
1948 if (!*params_list)
1949 break;
1950 }
bd0725f3
RS
1951 temp_params[param_count++] = "-aux-info";
1952
1953 /* Leave room for the aux-info file name argument. */
1954 aux_info_file_name_index = param_count;
1955 temp_params[param_count++] = NULL;
1956
5f8037c4
RS
1957 temp_params[param_count++] = "-S";
1958 temp_params[param_count++] = "-o";
1959 temp_params[param_count++] = "/dev/null";
1960
bd0725f3
RS
1961 /* Leave room for the input file name argument. */
1962 input_file_name_index = param_count;
1963 temp_params[param_count++] = NULL;
1964 /* Terminate the list. */
5f8037c4
RS
1965 temp_params[param_count++] = NULL;
1966
1967 /* Make a copy of the compile_params in heap space. */
1968
34e56753 1969 compile_params
ff57c94e 1970 = (const char **) xmalloc (sizeof (char *) * (param_count+1));
5f8037c4
RS
1971 memcpy (compile_params, temp_params, sizeof (char *) * param_count);
1972}
1973
1974/* Do a recompilation for the express purpose of generating a new aux_info
1975 file to go with a specific base source file. */
1976
1977static int
34e56753
RS
1978gen_aux_info_file (base_filename)
1979 const char *base_filename;
5f8037c4
RS
1980{
1981 int child_pid;
1982
bd0725f3 1983 if (!input_file_name_index)
5f8037c4
RS
1984 munge_compile_params ("");
1985
bd0725f3
RS
1986 /* Store the full source file name in the argument vector. */
1987 compile_params[input_file_name_index] = shortpath (NULL, base_filename);
1988 /* Add .X to source file name to get aux-info file name. */
1989 compile_params[aux_info_file_name_index]
8241a41f
RS
1990 = savestring2 (compile_params[input_file_name_index],
1991 strlen (compile_params[input_file_name_index]),
1992 ".X",
1993 2);
5f8037c4
RS
1994
1995 if (!quiet_flag)
1996 fprintf (stderr, "%s: compiling `%s'\n",
bd0725f3 1997 pname, compile_params[input_file_name_index]);
5f8037c4
RS
1998
1999 if (child_pid = fork ())
2000 {
2001 if (child_pid == -1)
2002 {
667cc897 2003 fprintf (stderr, "%s: could not fork process: %s\n",
a2b22788 2004 pname, sys_errlist[errno]);
5f8037c4
RS
2005 return 0;
2006 }
2007
2008#if 0
2009 /* Print out the command line that the other process is now executing. */
2010
2011 if (!quiet_flag)
2012 {
2013 const char **arg;
2014
2015 fputs ("\t", stderr);
2016 for (arg = compile_params; *arg; arg++)
2017 {
2018 fputs (*arg, stderr);
2019 fputc (' ', stderr);
2020 }
2021 fputc ('\n', stderr);
2022 fflush (stderr);
2023 }
2024#endif /* 0 */
2025
2026 {
2027 int wait_status;
2028
2029 if (wait (&wait_status) == -1)
2030 {
b7004e53 2031 fprintf (stderr, "%s: wait failed: %s\n",
a2b22788 2032 pname, sys_errlist[errno]);
5f8037c4
RS
2033 return 0;
2034 }
b7004e53
RS
2035 if ((wait_status & 0x7F) != 0)
2036 {
2037 fprintf (stderr, "%s: subprocess got fatal signal %d",
2038 pname, (wait_status & 0x7F));
2039 return 0;
2040 }
2041 if (((wait_status & 0xFF00) >> 8) != 0)
d742f26c 2042 {
b7004e53
RS
2043 fprintf (stderr, "%s: %s exited with status %d\n",
2044 pname, base_filename, ((wait_status & 0xFF00) >> 8));
d742f26c
RS
2045 return 0;
2046 }
2047 return 1;
5f8037c4
RS
2048 }
2049 }
2050 else
2051 {
34e56753 2052 if (my_execvp (compile_params[0], (char *const *) compile_params))
5f8037c4 2053 {
d742f26c
RS
2054 int e = errno, f = fileno (stderr);
2055 write (f, pname, strlen (pname));
2056 write (f, ": ", 2);
2057 write (f, compile_params[0], strlen (compile_params[0]));
2058 write (f, ": ", 2);
2059 write (f, sys_errlist[e], strlen (sys_errlist[e]));
2060 write (f, "\n", 1);
2061 _exit (1);
5f8037c4
RS
2062 }
2063 return 1; /* Never executed. */
2064 }
2065}
2066\f
2067/* Read in all of the information contained in a single aux_info file.
2068 Save all of the important stuff for later. */
2069
2070static void
34e56753
RS
2071process_aux_info_file (base_source_filename, keep_it, is_syscalls)
2072 const char *base_source_filename;
2073 int keep_it;
2074 int is_syscalls;
5f8037c4 2075{
d742f26c
RS
2076 size_t base_len = strlen (base_source_filename);
2077 char * aux_info_filename
2078 = (char *) alloca (base_len + strlen (aux_info_suffix) + 1);
5f8037c4
RS
2079 char *aux_info_base;
2080 char *aux_info_limit;
d742f26c 2081 char *aux_info_relocated_name;
5f8037c4
RS
2082 const char *aux_info_second_line;
2083 time_t aux_info_mtime;
2084 size_t aux_info_size;
77f99bc7 2085 int must_create;
5f8037c4 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
77f99bc7
RS
2095 /* If file doesn't exist, set must_create.
2096 Likewise if it exists and we can read it but it is obsolete.
2097 Otherwise, report an error. */
2098 must_create = 0;
2cccceff
RS
2099
2100 /* Come here with must_create set to 1 if file is out of date. */
2101start_over: ;
2102
77f99bc7
RS
2103 if (my_access (aux_info_filename, R_OK) == -1)
2104 {
2105 if (errno == ENOENT)
2106 {
2107 if (is_syscalls)
2108 {
2109 fprintf (stderr, "%s: warning: missing SYSCALLS file `%s'\n",
2110 pname, aux_info_filename);
2111 return;
2112 }
2113 must_create = 1;
2114 }
2115 else
2116 {
667cc897 2117 fprintf (stderr, "%s: can't read aux info file `%s': %s\n",
77f99bc7
RS
2118 pname, shortpath (NULL, aux_info_filename),
2119 sys_errlist[errno]);
2120 errors++;
2121 return;
2122 }
2123 }
2124#if 0 /* There is code farther down to take care of this. */
2125 else
2126 {
2127 struct stat s1, s2;
2128 stat (aux_info_file_name, &s1);
2129 stat (base_source_file_name, &s2);
2130 if (s2.st_mtime > s1.st_mtime)
2131 must_create = 1;
2132 }
2133#endif /* 0 */
5f8037c4 2134
77f99bc7
RS
2135 /* If we need a .X file, create it, and verify we can read it. */
2136 if (must_create)
2137 {
2138 if (!gen_aux_info_file (base_source_filename))
2139 {
2140 errors++;
2141 return;
2142 }
2143 if (my_access (aux_info_filename, R_OK) == -1)
2144 {
667cc897 2145 fprintf (stderr, "%s: can't read aux info file `%s': %s\n",
77f99bc7
RS
2146 pname, shortpath (NULL, aux_info_filename),
2147 sys_errlist[errno]);
2148 errors++;
2149 return;
2150 }
2151 }
5f8037c4
RS
2152
2153 {
2154 struct stat stat_buf;
2155
2156 /* Get some status information about this aux_info file. */
2157
34e56753 2158 if (my_stat (aux_info_filename, &stat_buf) == -1)
5f8037c4 2159 {
667cc897 2160 fprintf (stderr, "%s: can't get status of aux info file `%s': %s\n",
a2b22788
RS
2161 pname, shortpath (NULL, aux_info_filename),
2162 sys_errlist[errno]);
5f8037c4
RS
2163 errors++;
2164 return;
2165 }
2166
2167 /* Check on whether or not this aux_info file is zero length. If it is,
2168 then just ignore it and return. */
2169
2170 if ((aux_info_size = stat_buf.st_size) == 0)
2171 return;
2172
2173 /* Get the date/time of last modification for this aux_info file and
2174 remember it. We will have to check that any source files that it
2175 contains information about are at least this old or older. */
2176
2177 aux_info_mtime = stat_buf.st_mtime;
667cc897 2178
2cccceff 2179 if (!is_syscalls)
667cc897 2180 {
2cccceff
RS
2181 /* Compare mod time with the .c file; update .X file if obsolete.
2182 The code later on can fail to check the .c file
2183 if it did not directly define any functions. */
2184
2185 if (my_stat (base_source_filename, &stat_buf) == -1)
2186 {
2187 fprintf (stderr, "%s: can't get status of aux info file `%s': %s\n",
2188 pname, shortpath (NULL, base_source_filename),
2189 sys_errlist[errno]);
2190 errors++;
2191 return;
2192 }
2193 if (stat_buf.st_mtime > aux_info_mtime)
2194 {
2195 must_create = 1;
2196 goto start_over;
2197 }
667cc897 2198 }
5f8037c4
RS
2199 }
2200
2201 {
2202 int aux_info_file;
2203
2204 /* Open the aux_info file. */
2205
34e56753 2206 if ((aux_info_file = my_open (aux_info_filename, O_RDONLY, 0444 )) == -1)
5f8037c4 2207 {
667cc897 2208 fprintf (stderr, "%s: can't open aux info file `%s' for reading: %s\n",
a2b22788
RS
2209 pname, shortpath (NULL, aux_info_filename),
2210 sys_errlist[errno]);
5f8037c4
RS
2211 return;
2212 }
2213
2214 /* Allocate space to hold the aux_info file in memory. */
2215
2216 aux_info_base = xmalloc (aux_info_size + 1);
2217 aux_info_limit = aux_info_base + aux_info_size;
2218 *aux_info_limit = '\0';
2219
2220 /* Read the aux_info file into memory. */
2221
2222 if (read (aux_info_file, aux_info_base, aux_info_size) != aux_info_size)
2223 {
667cc897 2224 fprintf (stderr, "%s: error reading aux info file `%s': %s\n",
a2b22788
RS
2225 pname, shortpath (NULL, aux_info_filename),
2226 sys_errlist[errno]);
5f8037c4
RS
2227 free (aux_info_base);
2228 close (aux_info_file);
2229 return;
2230 }
2231
2232 /* Close the aux info file. */
2233
2234 if (close (aux_info_file))
2235 {
667cc897 2236 fprintf (stderr, "%s: error closing aux info file `%s': %s\n",
a2b22788
RS
2237 pname, shortpath (NULL, aux_info_filename),
2238 sys_errlist[errno]);
5f8037c4
RS
2239 free (aux_info_base);
2240 close (aux_info_file);
2241 return;
2242 }
2243 }
2244
2245 /* Delete the aux_info file (unless requested not to). If the deletion
2246 fails for some reason, don't even worry about it. */
2247
667cc897 2248 if (must_create && !keep_it)
34e56753 2249 if (my_unlink (aux_info_filename) == -1)
667cc897 2250 fprintf (stderr, "%s: can't delete aux info file `%s': %s\n",
a2b22788
RS
2251 pname, shortpath (NULL, aux_info_filename),
2252 sys_errlist[errno]);
5f8037c4
RS
2253
2254 /* Save a pointer into the first line of the aux_info file which
a2b22788 2255 contains the filename of the directory from which the compiler
5f8037c4
RS
2256 was invoked when the associated source file was compiled.
2257 This information is used later to help create complete
a2b22788 2258 filenames out of the (potentially) relative filenames in
5f8037c4
RS
2259 the aux_info file. */
2260
2261 {
2262 char *p = aux_info_base;
2263
2264 while (*p != ':')
2265 p++;
2266 p++;
2267 while (*p == ' ')
2268 p++;
a2b22788 2269 invocation_filename = p; /* Save a pointer to first byte of path. */
5f8037c4
RS
2270 while (*p != ' ')
2271 p++;
2272 *p++ = '/';
2273 *p++ = '\0';
2274 while (*p++ != '\n')
2275 continue;
2276 aux_info_second_line = p;
d742f26c
RS
2277 aux_info_relocated_name = 0;
2278 if (invocation_filename[0] != '/')
2279 {
2280 /* INVOCATION_FILENAME is relative;
2281 append it to BASE_SOURCE_FILENAME's dir. */
2282 char *dir_end;
2283 aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
2284 strcpy (aux_info_relocated_name, base_source_filename);
45ad788b 2285 dir_end = rindex (aux_info_relocated_name, '/');
d742f26c
RS
2286 if (dir_end)
2287 dir_end++;
2288 else
2289 dir_end = aux_info_relocated_name;
2290 strcpy (dir_end, invocation_filename);
2291 invocation_filename = aux_info_relocated_name;
2292 }
5f8037c4
RS
2293 }
2294
2295
2296 {
2297 const char *aux_info_p;
2298
2299 /* Do a pre-pass on the lines in the aux_info file, making sure that all
2300 of the source files referenced in there are at least as old as this
2301 aux_info file itself. If not, go back and regenerate the aux_info
2302 file anew. Don't do any of this for the syscalls file. */
2303
2304 if (!is_syscalls)
2305 {
2306 current_aux_info_lineno = 2;
2307
2308 for (aux_info_p = aux_info_second_line; *aux_info_p; )
2309 {
2310 if (referenced_file_is_newer (aux_info_p, aux_info_mtime))
2311 {
2312 free (aux_info_base);
d742f26c
RS
2313 xfree (aux_info_relocated_name);
2314 if (keep_it && my_unlink (aux_info_filename) == -1)
5f8037c4 2315 {
667cc897 2316 fprintf (stderr, "%s: can't delete file `%s': %s\n",
a2b22788
RS
2317 pname, shortpath (NULL, aux_info_filename),
2318 sys_errlist[errno]);
5f8037c4
RS
2319 return;
2320 }
2321 goto start_over;
2322 }
2323
2324 /* Skip over the rest of this line to start of next line. */
2325
2326 while (*aux_info_p != '\n')
2327 aux_info_p++;
2328 aux_info_p++;
2329 current_aux_info_lineno++;
2330 }
2331 }
2332
2333 /* Now do the real pass on the aux_info lines. Save their information in
2334 the in-core data base. */
2335
2336 current_aux_info_lineno = 2;
2337
2338 for (aux_info_p = aux_info_second_line; *aux_info_p;)
2339 {
2340 char *unexpanded_line = unexpand_if_needed (aux_info_p);
2341
2342 if (unexpanded_line)
2343 {
2344 save_def_or_dec (unexpanded_line, is_syscalls);
2345 free (unexpanded_line);
2346 }
2347 else
2348 save_def_or_dec (aux_info_p, is_syscalls);
2349
2350 /* Skip over the rest of this line and get to start of next line. */
2351
2352 while (*aux_info_p != '\n')
2353 aux_info_p++;
2354 aux_info_p++;
2355 current_aux_info_lineno++;
2356 }
2357 }
2358
2359 free (aux_info_base);
d742f26c 2360 xfree (aux_info_relocated_name);
5f8037c4
RS
2361}
2362\f
2363#ifndef UNPROTOIZE
2364
2365/* Check an individual filename for a .c suffix. If the filename has this
2366 suffix, rename the file such that its suffix is changed to .C. This
2367 function implements the -C option. */
2368
2369static void
34e56753
RS
2370rename_c_file (hp)
2371 const hash_table_entry *hp;
5f8037c4 2372{
a2b22788
RS
2373 const char *filename = hp->symbol;
2374 int last_char_index = strlen (filename) - 1;
2375 char *const new_filename = (char *) alloca (strlen (filename) + 1);
5f8037c4
RS
2376
2377 /* Note that we don't care here if the given file was converted or not. It
2378 is possible that the given file was *not* converted, simply because there
2379 was nothing in it which actually required conversion. Even in this case,
2380 we want to do the renaming. Note that we only rename files with the .c
2381 suffix. */
2382
a2b22788 2383 if (filename[last_char_index] != 'c' || filename[last_char_index-1] != '.')
5f8037c4
RS
2384 return;
2385
a2b22788
RS
2386 strcpy (new_filename, filename);
2387 new_filename[last_char_index] = 'C';
5f8037c4 2388
34e56753 2389 if (my_link (filename, new_filename) == -1)
5f8037c4
RS
2390 {
2391 fprintf (stderr, "%s: warning: can't link file `%s' to `%s': %s\n",
a2b22788
RS
2392 pname, shortpath (NULL, filename),
2393 shortpath (NULL, new_filename), sys_errlist[errno]);
5f8037c4
RS
2394 errors++;
2395 return;
2396 }
2397
34e56753 2398 if (my_unlink (filename) == -1)
5f8037c4
RS
2399 {
2400 fprintf (stderr, "%s: warning: can't delete file `%s': %s\n",
a2b22788 2401 pname, shortpath (NULL, filename), sys_errlist[errno]);
5f8037c4
RS
2402 errors++;
2403 return;
2404 }
2405}
2406
a019653e 2407#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
2408\f
2409/* Take the list of definitions and declarations attached to a particular
2410 file_info node and reverse the order of the list. This should get the
2411 list into an order such that the item with the lowest associated line
2412 number is nearest the head of the list. When these lists are originally
2413 built, they are in the opposite order. We want to traverse them in
2414 normal line number order later (i.e. lowest to highest) so reverse the
2415 order here. */
2416
2417static void
34e56753
RS
2418reverse_def_dec_list (hp)
2419 const hash_table_entry *hp;
5f8037c4
RS
2420{
2421 file_info *file_p = hp->fip;
2422 const def_dec_info *prev = NULL;
2423 const def_dec_info *current = file_p->defs_decs;
2424
2425 if (!( current = file_p->defs_decs))
2426 return; /* no list to reverse */
2427
2428 prev = current;
2429 if (! (current = current->next_in_file))
2430 return; /* can't reverse a single list element */
2431
2432 ((NONCONST def_dec_info *) prev)->next_in_file = NULL;
2433
2434 while (current)
2435 {
2436 const def_dec_info *next = current->next_in_file;
2437
2438 ((NONCONST def_dec_info *) current)->next_in_file = prev;
2439 prev = current;
2440 current = next;
2441 }
2442
2443 file_p->defs_decs = prev;
2444}
2445
2446#ifndef UNPROTOIZE
2447
2448/* Find the (only?) extern definition for a particular function name, starting
2449 from the head of the linked list of entries for the given name. If we
2450 cannot find an extern definition for the given function name, issue a
2451 warning and scrounge around for the next best thing, i.e. an extern
2452 function declaration with a prototype attached to it. Note that we only
2453 allow such substitutions for extern declarations and never for static
2454 declarations. That's because the only reason we allow them at all is
2455 to let un-prototyped function declarations for system-supplied library
2456 functions get their prototypes from our own extra SYSCALLS.c.X file which
2457 contains all of the correct prototypes for system functions. */
2458
2459static const def_dec_info *
34e56753
RS
2460find_extern_def (head, user)
2461 const def_dec_info *head;
2462 const def_dec_info *user;
5f8037c4
RS
2463{
2464 const def_dec_info *dd_p;
2465 const def_dec_info *extern_def_p = NULL;
2466 int conflict_noted = 0;
2467
2468 /* Don't act too stupid here. Somebody may try to convert an entire system
2469 in one swell fwoop (rather than one program at a time, as should be done)
2470 and in that case, we may find that there are multiple extern definitions
2471 of a given function name in the entire set of source files that we are
2472 converting. If however one of these definitions resides in exactly the
2473 same source file as the reference we are trying to satisfy then in that
2474 case it would be stupid for us to fail to realize that this one definition
2475 *must* be the precise one we are looking for.
2476
2477 To make sure that we don't miss an opportunity to make this "same file"
2478 leap of faith, we do a prescan of the list of records relating to the
2479 given function name, and we look (on this first scan) *only* for a
2480 definition of the function which is in the same file as the reference
2481 we are currently trying to satisfy. */
2482
2483 for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2484 if (dd_p->is_func_def && !dd_p->is_static && dd_p->file == user->file)
2485 return dd_p;
2486
2487 /* Now, since we have not found a definition in the same file as the
2488 reference, we scan the list again and consider all possibilities from
2489 all files. Here we may get conflicts with the things listed in the
2490 SYSCALLS.c.X file, but if that happens it only means that the source
2491 code being converted contains its own definition of a function which
2492 could have been supplied by libc.a. In such cases, we should avoid
2493 issuing the normal warning, and defer to the definition given in the
2494 user's own code. */
2495
2496 for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2497 if (dd_p->is_func_def && !dd_p->is_static)
2498 {
2499 if (!extern_def_p) /* Previous definition? */
2500 extern_def_p = dd_p; /* Remember the first definition found. */
2501 else
2502 {
2503 /* Ignore definition just found if it came from SYSCALLS.c.X. */
2504
2505 if (is_syscalls_file (dd_p->file))
2506 continue;
2507
2508 /* Quietly replace the definition previously found with the one
2509 just found if the previous one was from SYSCALLS.c.X. */
2510
2511 if (is_syscalls_file (extern_def_p->file))
2512 {
2513 extern_def_p = dd_p;
2514 continue;
2515 }
2516
2517 /* If we get here, then there is a conflict between two function
2518 declarations for the same function, both of which came from the
2519 user's own code. */
2520
2521 if (!conflict_noted) /* first time we noticed? */
2522 {
2523 conflict_noted = 1;
667cc897 2524 fprintf (stderr, "%s: conflicting extern definitions of '%s'\n",
a2b22788 2525 pname, head->hash_entry->symbol);
5f8037c4
RS
2526 if (!quiet_flag)
2527 {
2528 fprintf (stderr, "%s: declarations of '%s' will not be converted\n",
a2b22788 2529 pname, head->hash_entry->symbol);
5f8037c4 2530 fprintf (stderr, "%s: conflict list for '%s' follows:\n",
a2b22788 2531 pname, head->hash_entry->symbol);
5f8037c4 2532 fprintf (stderr, "%s: %s(%d): %s\n",
a2b22788
RS
2533 pname,
2534 shortpath (NULL, extern_def_p->file->hash_entry->symbol),
2535 extern_def_p->line, extern_def_p->ansi_decl);
5f8037c4
RS
2536 }
2537 }
2538 if (!quiet_flag)
2539 fprintf (stderr, "%s: %s(%d): %s\n",
a2b22788
RS
2540 pname,
2541 shortpath (NULL, dd_p->file->hash_entry->symbol),
2542 dd_p->line, dd_p->ansi_decl);
5f8037c4
RS
2543 }
2544 }
2545
2546 /* We want to err on the side of caution, so if we found multiple conflicting
2547 definitions for the same function, treat this as being that same as if we
2548 had found no definitions (i.e. return NULL). */
2549
2550 if (conflict_noted)
2551 return NULL;
2552
2553 if (!extern_def_p)
2554 {
2555 /* We have no definitions for this function so do the next best thing.
2556 Search for an extern declaration already in prototype form. */
2557
2558 for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2559 if (!dd_p->is_func_def && !dd_p->is_static && dd_p->prototyped)
2560 {
2561 extern_def_p = dd_p; /* save a pointer to the definition */
2562 if (!quiet_flag)
2563 fprintf (stderr, "%s: warning: using formals list from %s(%d) for function `%s'\n",
a2b22788
RS
2564 pname,
2565 shortpath (NULL, dd_p->file->hash_entry->symbol),
2566 dd_p->line, dd_p->hash_entry->symbol);
5f8037c4
RS
2567 break;
2568 }
2569
2570 /* Gripe about unprototyped function declarations that we found no
2571 corresponding definition (or other source of prototype information)
2572 for.
2573
2574 Gripe even if the unprototyped declaration we are worried about
2575 exists in a file in one of the "system" include directories. We
2576 can gripe about these because we should have at least found a
2577 corresponding (pseudo) definition in the SYSCALLS.c.X file. If we
2578 didn't, then that means that the SYSCALLS.c.X file is missing some
2579 needed prototypes for this particular system. That is worth telling
2580 the user about! */
2581
2582 if (!extern_def_p)
2583 {
2584 const char *file = user->file->hash_entry->symbol;
2585
2586 if (!quiet_flag)
2587 if (in_system_include_dir (file))
2588 {
2589 /* Why copy this string into `needed' at all?
2590 Why not just use user->ansi_decl without copying? */
34e56753 2591 char *needed = (char *) alloca (strlen (user->ansi_decl) + 1);
5f8037c4
RS
2592 char *p;
2593
2594 strcpy (needed, user->ansi_decl);
2595 p = (NONCONST char *) substr (needed, user->hash_entry->symbol)
2596 + strlen (user->hash_entry->symbol) + 2;
a609bfc6
RS
2597 /* Avoid having ??? in the string. */
2598 *p++ = '?';
2599 *p++ = '?';
2600 *p++ = '?';
2601 strcpy (p, ");");
5f8037c4 2602
a2b22788
RS
2603 fprintf (stderr, "%s: %d: `%s' used but missing from SYSCALLS\n",
2604 shortpath (NULL, file), user->line,
2605 needed+7); /* Don't print "extern " */
5f8037c4 2606 }
8241a41f 2607#if 0
5f8037c4 2608 else
a2b22788
RS
2609 fprintf (stderr, "%s: %d: warning: no extern definition for `%s'\n",
2610 shortpath (NULL, file), user->line,
2611 user->hash_entry->symbol);
8241a41f 2612#endif
5f8037c4
RS
2613 }
2614 }
2615 return extern_def_p;
2616}
2617\f
2618/* Find the (only?) static definition for a particular function name in a
2619 given file. Here we get the function-name and the file info indirectly
2620 from the def_dec_info record pointer which is passed in. */
2621
2622static const def_dec_info *
34e56753
RS
2623find_static_definition (user)
2624 const def_dec_info *user;
5f8037c4
RS
2625{
2626 const def_dec_info *head = user->hash_entry->ddip;
2627 const def_dec_info *dd_p;
2628 int num_static_defs = 0;
2629 const def_dec_info *static_def_p = NULL;
2630
2631 for (dd_p = head; dd_p; dd_p = dd_p->next_for_func)
2632 if (dd_p->is_func_def && dd_p->is_static && (dd_p->file == user->file))
2633 {
2634 static_def_p = dd_p; /* save a pointer to the definition */
2635 num_static_defs++;
2636 }
2637 if (num_static_defs == 0)
2638 {
2639 if (!quiet_flag)
2640 fprintf (stderr, "%s: warning: no static definition for `%s' in file `%s'\n",
a2b22788
RS
2641 pname, head->hash_entry->symbol,
2642 shortpath (NULL, user->file->hash_entry->symbol));
5f8037c4
RS
2643 }
2644 else if (num_static_defs > 1)
2645 {
667cc897 2646 fprintf (stderr, "%s: multiple static defs of `%s' in file `%s'\n",
a2b22788
RS
2647 pname, head->hash_entry->symbol,
2648 shortpath (NULL, user->file->hash_entry->symbol));
5f8037c4
RS
2649 return NULL;
2650 }
2651 return static_def_p;
2652}
2653
2654/* Find good prototype style formal argument lists for all of the function
2655 declarations which didn't have them before now.
2656
2657 To do this we consider each function name one at a time. For each function
2658 name, we look at the items on the linked list of def_dec_info records for
2659 that particular name.
2660
2661 Somewhere on this list we should find one (and only one) def_dec_info
2662 record which represents the actual function definition, and this record
2663 should have a nice formal argument list already associated with it.
2664
2665 Thus, all we have to do is to connect up all of the other def_dec_info
2666 records for this particular function name to the special one which has
2667 the full-blown formals list.
2668
2669 Of course it is a little more complicated than just that. See below for
2670 more details. */
2671
2672static void
34e56753
RS
2673connect_defs_and_decs (hp)
2674 const hash_table_entry *hp;
5f8037c4
RS
2675{
2676 const def_dec_info *dd_p;
2677 const def_dec_info *extern_def_p = NULL;
2678 int first_extern_reference = 1;
2679
2680 /* Traverse the list of definitions and declarations for this particular
2681 function name. For each item on the list, if it is a function
2682 definition (either old style or new style) then GCC has already been
2683 kind enough to produce a prototype for us, and it is associated with
2684 the item already, so declare the item as its own associated "definition".
2685
2686 Also, for each item which is only a function declaration, but which
2687 nonetheless has its own prototype already (obviously supplied by the user)
2688 declare the item as it's own definition.
2689
2690 Note that when/if there are multiple user-supplied prototypes already
2691 present for multiple declarations of any given function, these multiple
2692 prototypes *should* all match exactly with one another and with the
2693 prototype for the actual function definition. We don't check for this
2694 here however, since we assume that the compiler must have already done
d45cf215 2695 this consistency checking when it was creating the .X files. */
5f8037c4
RS
2696
2697 for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2698 if (dd_p->prototyped)
2699 ((NONCONST def_dec_info *) dd_p)->definition = dd_p;
2700
2701 /* Traverse the list of definitions and declarations for this particular
2702 function name. For each item on the list, if it is an extern function
2703 declaration and if it has no associated definition yet, go try to find
2704 the matching extern definition for the declaration.
2705
2706 When looking for the matching function definition, warn the user if we
2707 fail to find one.
2708
2709 If we find more that one function definition also issue a warning.
2710
2711 Do the search for the matching definition only once per unique function
2712 name (and only when absolutely needed) so that we can avoid putting out
2713 redundant warning messages, and so that we will only put out warning
2714 messages when there is actually a reference (i.e. a declaration) for
2715 which we need to find a matching definition. */
2716
2717 for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2718 if (!dd_p->is_func_def && !dd_p->is_static && !dd_p->definition)
2719 {
2720 if (first_extern_reference)
2721 {
2722 extern_def_p = find_extern_def (hp->ddip, dd_p);
2723 first_extern_reference = 0;
2724 }
2725 ((NONCONST def_dec_info *) dd_p)->definition = extern_def_p;
2726 }
2727
2728 /* Traverse the list of definitions and declarations for this particular
2729 function name. For each item on the list, if it is a static function
2730 declaration and if it has no associated definition yet, go try to find
2731 the matching static definition for the declaration within the same file.
2732
2733 When looking for the matching function definition, warn the user if we
2734 fail to find one in the same file with the declaration, and refuse to
2735 convert this kind of cross-file static function declaration. After all,
2736 this is stupid practice and should be discouraged.
2737
2738 We don't have to worry about the possibility that there is more than one
2739 matching function definition in the given file because that would have
2740 been flagged as an error by the compiler.
2741
2742 Do the search for the matching definition only once per unique
2743 function-name/source-file pair (and only when absolutely needed) so that
2744 we can avoid putting out redundant warning messages, and so that we will
2745 only put out warning messages when there is actually a reference (i.e. a
2746 declaration) for which we actually need to find a matching definition. */
2747
2748 for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2749 if (!dd_p->is_func_def && dd_p->is_static && !dd_p->definition)
2750 {
2751 const def_dec_info *dd_p2;
2752 const def_dec_info *static_def;
2753
2754 /* We have now found a single static declaration for which we need to
2755 find a matching definition. We want to minimize the work (and the
2756 number of warnings), so we will find an appropriate (matching)
2757 static definition for this declaration, and then distribute it
2758 (as the definition for) any and all other static declarations
2759 for this function name which occur within the same file, and which
2760 do not already have definitions.
2761
2762 Note that a trick is used here to prevent subsequent attempts to
a019653e 2763 call find_static_definition for a given function-name & file
5f8037c4
RS
2764 if the first such call returns NULL. Essentially, we convert
2765 these NULL return values to -1, and put the -1 into the definition
2766 field for each other static declaration from the same file which
2767 does not already have an associated definition.
2768 This makes these other static declarations look like they are
2769 actually defined already when the outer loop here revisits them
2770 later on. Thus, the outer loop will skip over them. Later, we
2771 turn the -1's back to NULL's. */
2772
2773 ((NONCONST def_dec_info *) dd_p)->definition =
2774 (static_def = find_static_definition (dd_p))
2775 ? static_def
2776 : (const def_dec_info *) -1;
2777
2778 for (dd_p2 = dd_p->next_for_func; dd_p2; dd_p2 = dd_p2->next_for_func)
2779 if (!dd_p2->is_func_def && dd_p2->is_static
2780 && !dd_p2->definition && (dd_p2->file == dd_p->file))
2781 ((NONCONST def_dec_info *)dd_p2)->definition = dd_p->definition;
2782 }
2783
2784 /* Convert any dummy (-1) definitions we created in the step above back to
2785 NULL's (as they should be). */
2786
2787 for (dd_p = hp->ddip; dd_p; dd_p = dd_p->next_for_func)
2788 if (dd_p->definition == (def_dec_info *) -1)
2789 ((NONCONST def_dec_info *) dd_p)->definition = NULL;
2790}
2791
a019653e 2792#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
2793
2794/* Give a pointer into the clean text buffer, return a number which is the
2795 original source line number that the given pointer points into. */
2796
2797static int
34e56753
RS
2798identify_lineno (clean_p)
2799 const char *clean_p;
5f8037c4
RS
2800{
2801 int line_num = 1;
2802 const char *scan_p;
2803
2804 for (scan_p = clean_text_base; scan_p <= clean_p; scan_p++)
2805 if (*scan_p == '\n')
2806 line_num++;
2807 return line_num;
2808}
2809
2810/* Issue an error message and give up on doing this particular edit. */
2811
2812static void
34e56753
RS
2813declare_source_confusing (clean_p)
2814 const char *clean_p;
5f8037c4
RS
2815{
2816 if (!quiet_flag)
2817 {
2818 if (clean_p == 0)
a2b22788
RS
2819 fprintf (stderr, "%s: %d: warning: source too confusing\n",
2820 shortpath (NULL, convert_filename), last_known_line_number);
5f8037c4 2821 else
a2b22788
RS
2822 fprintf (stderr, "%s: %d: warning: source too confusing\n",
2823 shortpath (NULL, convert_filename),
2824 identify_lineno (clean_p));
5f8037c4
RS
2825 }
2826 longjmp (source_confusion_recovery, 1);
2827}
2828
2829/* Check that a condition which is expected to be true in the original source
2830 code is in fact true. If not, issue an error message and give up on
2831 converting this particular source file. */
2832
34e56753
RS
2833static void
2834check_source (cond, clean_p)
2835 int cond;
2836 const char *clean_p;
5f8037c4
RS
2837{
2838 if (!cond)
2839 declare_source_confusing (clean_p);
2840}
2841
2842/* If we think of the in-core cleaned text buffer as a memory mapped
2843 file (with the variable last_known_line_start acting as sort of a
2844 file pointer) then we can imagine doing "seeks" on the buffer. The
2845 following routine implements a kind of "seek" operation for the in-core
2846 (cleaned) copy of the source file. When finished, it returns a pointer to
2847 the start of a given (numbered) line in the cleaned text buffer.
2848
2849 Note that protoize only has to "seek" in the forward direction on the
2850 in-core cleaned text file buffers, and it never needs to back up.
2851
2852 This routine is made a little bit faster by remembering the line number
2853 (and pointer value) supplied (and returned) from the previous "seek".
2854 This prevents us from always having to start all over back at the top
2855 of the in-core cleaned buffer again. */
2856
2857static const char *
34e56753
RS
2858seek_to_line (n)
2859 int n;
5f8037c4
RS
2860{
2861 if (n < last_known_line_number)
2862 abort ();
2863
2864 while (n > last_known_line_number)
2865 {
2866 while (*last_known_line_start != '\n')
2867 check_source (++last_known_line_start < clean_text_limit, 0);
2868 last_known_line_start++;
2869 last_known_line_number++;
2870 }
2871 return last_known_line_start;
2872}
2873
2874/* Given a pointer to a character in the cleaned text buffer, return a pointer
2875 to the next non-whitepace character which follows it. */
2876
2877static const char *
34e56753
RS
2878forward_to_next_token_char (ptr)
2879 const char *ptr;
5f8037c4
RS
2880{
2881 for (++ptr; isspace (*ptr); check_source (++ptr < clean_text_limit, 0))
2882 continue;
2883 return ptr;
2884}
2885
2886/* Copy a chunk of text of length `len' and starting at `str' to the current
2887 output buffer. Note that all attempts to add stuff to the current output
2888 buffer ultimately go through here. */
2889
2890static void
34e56753
RS
2891output_bytes (str, len)
2892 const char *str;
2893 size_t len;
5f8037c4
RS
2894{
2895 if ((repl_write_ptr + 1) + len >= repl_text_limit)
2896 {
2897 size_t new_size = (repl_text_limit - repl_text_base) << 1;
2898 char *new_buf = (char *) xrealloc (repl_text_base, new_size);
2899
2900 repl_write_ptr = new_buf + (repl_write_ptr - repl_text_base);
2901 repl_text_base = new_buf;
2902 repl_text_limit = new_buf + new_size;
2903 }
2904 memcpy (repl_write_ptr + 1, str, len);
2905 repl_write_ptr += len;
2906}
2907
2908/* Copy all bytes (except the trailing null) of a null terminated string to
2909 the current output buffer. */
2910
2911static void
34e56753
RS
2912output_string (str)
2913 const char *str;
5f8037c4
RS
2914{
2915 output_bytes (str, strlen (str));
2916}
2917
2918/* Copy some characters from the original text buffer to the current output
2919 buffer.
2920
2921 This routine takes a pointer argument `p' which is assumed to be a pointer
2922 into the cleaned text buffer. The bytes which are copied are the `original'
2923 equivalents for the set of bytes between the last value of `clean_read_ptr'
2924 and the argument value `p'.
2925
2926 The set of bytes copied however, comes *not* from the cleaned text buffer,
2927 but rather from the direct counterparts of these bytes within the original
2928 text buffer.
2929
2930 Thus, when this function is called, some bytes from the original text
2931 buffer (which may include original comments and preprocessing directives)
2932 will be copied into the output buffer.
2933
2934 Note that the request implide when this routine is called includes the
2935 byte pointed to by the argument pointer `p'. */
2936
2937static void
34e56753
RS
2938output_up_to (p)
2939 const char *p;
5f8037c4
RS
2940{
2941 size_t copy_length = (size_t) (p - clean_read_ptr);
2942 const char *copy_start = orig_text_base+(clean_read_ptr-clean_text_base)+1;
2943
2944 if (copy_length == 0)
2945 return;
2946
2947 output_bytes (copy_start, copy_length);
2948 clean_read_ptr = p;
2949}
2950
2951/* Given a pointer to a def_dec_info record which represents some form of
2952 definition of a function (perhaps a real definition, or in lieu of that
2953 perhaps just a declaration with a full prototype) return true if this
2954 function is one which we should avoid converting. Return false
2955 otherwise. */
2956
2957static int
34e56753
RS
2958other_variable_style_function (ansi_header)
2959 const char *ansi_header;
5f8037c4
RS
2960{
2961#ifdef UNPROTOIZE
2962
2963 /* See if we have a stdarg function, or a function which has stdarg style
2964 parameters or a stdarg style return type. */
2965
2966 return (int) substr (ansi_header, "...");
2967
a019653e 2968#else /* !defined (UNPROTOIZE) */
5f8037c4
RS
2969
2970 /* See if we have a varargs function, or a function which has varargs style
2971 parameters or a varargs style return type. */
2972
2973 const char *p;
2974 int len = strlen (varargs_style_indicator);
2975
2976 for (p = ansi_header; p; )
2977 {
2978 const char *candidate;
2979
2980 if ((candidate = substr (p, varargs_style_indicator)) == 0)
2981 return 0;
2982 else
2983 if (!is_id_char (candidate[-1]) && !is_id_char (candidate[len]))
2984 return 1;
2985 else
2986 p = candidate + 1;
2987 }
2988 return 0;
a019653e 2989#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
2990}
2991
2992/* Do the editing operation specifically for a function "declaration". Note
2993 that editing for function "definitions" are handled in a separate routine
2994 below. */
2995
2996static void
34e56753
RS
2997edit_fn_declaration (def_dec_p, clean_text_p)
2998 const def_dec_info *def_dec_p;
8241a41f 2999 const char *volatile clean_text_p;
5f8037c4
RS
3000{
3001 const char *start_formals;
3002 const char *end_formals;
3003 const char *function_to_edit = def_dec_p->hash_entry->symbol;
3004 size_t func_name_len = strlen (function_to_edit);
3005 const char *end_of_fn_name;
3006
3007#ifndef UNPROTOIZE
3008
3009 const f_list_chain_item *this_f_list_chain_item;
3010 const def_dec_info *definition = def_dec_p->definition;
3011
3012 /* If we are protoizing, and if we found no corresponding definition for
3013 this particular function declaration, then just leave this declaration
3014 exactly as it is. */
3015
3016 if (!definition)
3017 return;
3018
3019 /* If we are protoizing, and if the corresponding definition that we found
3020 for this particular function declaration defined an old style varargs
3021 function, then we want to issue a warning and just leave this function
3022 declaration unconverted. */
3023
3024 if (other_variable_style_function (definition->ansi_decl))
3025 {
3026 if (!quiet_flag)
a2b22788
RS
3027 fprintf (stderr, "%s: %d: warning: varargs function declaration not converted\n",
3028 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3029 def_dec_p->line);
5f8037c4
RS
3030 return;
3031 }
3032
a019653e 3033#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3034
3035 /* Setup here to recover from confusing source code detected during this
3036 particular "edit". */
3037
3038 save_pointers ();
3039 if (setjmp (source_confusion_recovery))
3040 {
3041 restore_pointers ();
3042 fprintf (stderr, "%s: declaration of function `%s' not converted\n",
a2b22788 3043 pname, function_to_edit);
5f8037c4
RS
3044 return;
3045 }
3046
3047 /* We are editing a function declaration. The line number we did a seek to
3048 contains the comma or semicolon which follows the declaration. Our job
3049 now is to scan backwards looking for the function name. This name *must*
3050 be followed by open paren (ignoring whitespace, of course). We need to
3051 replace everything between that open paren and the corresponding closing
3052 paren. If we are protoizing, we need to insert the prototype-style
3053 formals lists. If we are unprotoizing, we need to just delete everything
3054 between the pairs of opening and closing parens. */
3055
3056 /* First move up to the end of the line. */
3057
3058 while (*clean_text_p != '\n')
3059 check_source (++clean_text_p < clean_text_limit, 0);
3060 clean_text_p--; /* Point to just before the newline character. */
3061
3062 /* Now we can scan backwards for the function name. */
3063
3064 do
3065 {
3066 for (;;)
3067 {
3068 /* Scan leftwards until we find some character which can be
3069 part of an identifier. */
3070
3071 while (!is_id_char (*clean_text_p))
3072 check_source (--clean_text_p > clean_read_ptr, 0);
3073
3074 /* Scan backwards until we find a char that cannot be part of an
3075 identifier. */
3076
3077 while (is_id_char (*clean_text_p))
3078 check_source (--clean_text_p > clean_read_ptr, 0);
3079
3080 /* Having found an "id break", see if the following id is the one
3081 that we are looking for. If so, then exit from this loop. */
3082
3083 if (!strncmp (clean_text_p+1, function_to_edit, func_name_len))
3084 {
3085 char ch = *(clean_text_p + 1 + func_name_len);
3086
3087 /* Must also check to see that the name in the source text
3088 ends where it should (in order to prevent bogus matches
3089 on similar but longer identifiers. */
3090
3091 if (! is_id_char (ch))
3092 break; /* exit from loop */
3093 }
3094 }
3095
3096 /* We have now found the first perfect match for the function name in
3097 our backward search. This may or may not be the actual function
3098 name at the start of the actual function declaration (i.e. we could
3099 have easily been mislead). We will try to avoid getting fooled too
3100 often by looking forward for the open paren which should follow the
3101 identifier we just found. We ignore whitespace while hunting. If
3102 the next non-whitespace byte we see is *not* an open left paren,
3103 then we must assume that we have been fooled and we start over
6dc42e49 3104 again accordingly. Note that there is no guarantee, that even if
5f8037c4
RS
3105 we do see the open paren, that we are in the right place.
3106 Programmers do the strangest things sometimes! */
3107
3108 end_of_fn_name = clean_text_p + strlen (def_dec_p->hash_entry->symbol);
3109 start_formals = forward_to_next_token_char (end_of_fn_name);
3110 }
3111 while (*start_formals != '(');
3112
3113 /* start_of_formals now points to the opening left paren which immediately
3114 follows the name of the function. */
3115
3116 /* Note that there may be several formals lists which need to be modified
3117 due to the possibility that the return type of this function is a
3118 pointer-to-function type. If there are several formals lists, we
3119 convert them in left-to-right order here. */
3120
3121#ifndef UNPROTOIZE
3122 this_f_list_chain_item = definition->f_list_chain;
a019653e 3123#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3124
3125 for (;;)
3126 {
3127 {
3128 int depth;
3129
3130 end_formals = start_formals + 1;
3131 depth = 1;
3132 for (; depth; check_source (++end_formals < clean_text_limit, 0))
3133 {
3134 switch (*end_formals)
3135 {
3136 case '(':
3137 depth++;
3138 break;
3139 case ')':
3140 depth--;
3141 break;
3142 }
3143 }
3144 end_formals--;
3145 }
3146
3147 /* end_formals now points to the closing right paren of the formals
3148 list whose left paren is pointed to by start_formals. */
3149
3150 /* Now, if we are protoizing, we insert the new ANSI-style formals list
3151 attached to the associated definition of this function. If however
3152 we are unprotoizing, then we simply delete any formals list which
3153 may be present. */
3154
3155 output_up_to (start_formals);
3156#ifndef UNPROTOIZE
3157 if (this_f_list_chain_item)
3158 {
3159 output_string (this_f_list_chain_item->formals_list);
3160 this_f_list_chain_item = this_f_list_chain_item->chain_next;
3161 }
3162 else
3163 {
3164 if (!quiet_flag)
3165 fprintf (stderr, "%s: warning: too many parameter lists in declaration of `%s'\n",
a2b22788 3166 pname, def_dec_p->hash_entry->symbol);
5f8037c4
RS
3167 check_source (0, end_formals); /* leave the declaration intact */
3168 }
a019653e 3169#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3170 clean_read_ptr = end_formals - 1;
3171
3172 /* Now see if it looks like there may be another formals list associated
3173 with the function declaration that we are converting (following the
3174 formals list that we just converted. */
3175
3176 {
3177 const char *another_r_paren = forward_to_next_token_char (end_formals);
3178
3179 if ((*another_r_paren != ')')
3180 || (*(start_formals = forward_to_next_token_char (another_r_paren)) != '('))
3181 {
3182#ifndef UNPROTOIZE
3183 if (this_f_list_chain_item)
3184 {
3185 if (!quiet_flag)
3186 fprintf (stderr, "\n%s: warning: too few parameter lists in declaration of `%s'\n",
a2b22788 3187 pname, def_dec_p->hash_entry->symbol);
5f8037c4
RS
3188 check_source (0, start_formals); /* leave the decl intact */
3189 }
a019653e 3190#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3191 break;
3192
3193 }
3194 }
3195
3196 /* There does appear to be yet another formals list, so loop around
3197 again, and convert it also. */
3198 }
3199}
3200
3201/* Edit a whole group of formals lists, starting with the rightmost one
3202 from some set of formals lists. This routine is called once (from the
3203 outside) for each function declaration which is converted. It is
3204 recursive however, and it calls itself once for each remaining formal
3205 list that lies to the left of the one it was originally called to work
3206 on. Thus, a whole set gets done in right-to-left order.
3207
3208 This routine returns non-zero if it thinks that it should not be trying
3209 to convert this particular function definition (because the name of the
3210 function doesn't match the one expected). */
3211
3212static int
34e56753
RS
3213edit_formals_lists (end_formals, f_list_count, def_dec_p)
3214 const char *end_formals;
3215 unsigned int f_list_count;
3216 const def_dec_info *def_dec_p;
5f8037c4
RS
3217{
3218 const char *start_formals;
3219 int depth;
3220
3221 start_formals = end_formals - 1;
3222 depth = 1;
3223 for (; depth; check_source (--start_formals > clean_read_ptr, 0))
3224 {
3225 switch (*start_formals)
3226 {
3227 case '(':
3228 depth--;
3229 break;
3230 case ')':
3231 depth++;
3232 break;
3233 }
3234 }
3235 start_formals++;
3236
3237 /* start_formals now points to the opening left paren of the formals list. */
3238
3239 f_list_count--;
3240
3241 if (f_list_count)
3242 {
3243 const char *next_end;
3244
3245 /* There should be more formal lists to the left of here. */
3246
3247 next_end = start_formals - 1;
3248 check_source (next_end > clean_read_ptr, 0);
3249 while (isspace (*next_end))
3250 check_source (--next_end > clean_read_ptr, 0);
3251 check_source (*next_end == ')', next_end);
3252 check_source (--next_end > clean_read_ptr, 0);
3253 check_source (*next_end == ')', next_end);
3254 if (edit_formals_lists (next_end, f_list_count, def_dec_p))
3255 return 1;
3256 }
3257
3258 /* Check that the function name in the header we are working on is the same
3259 as the one we would expect to find. If not, issue a warning and return
3260 non-zero. */
3261
3262 if (f_list_count == 0)
3263 {
3264 const char *expected = def_dec_p->hash_entry->symbol;
3265 const char *func_name_start;
3266 const char *func_name_limit;
3267 size_t func_name_len;
3268
3269 for (func_name_limit = start_formals-1; isspace (*func_name_limit); )
3270 check_source (--func_name_limit > clean_read_ptr, 0);
3271
3272 for (func_name_start = func_name_limit++;
3273 is_id_char (*func_name_start);
3274 func_name_start--)
3275 check_source (func_name_start > clean_read_ptr, 0);
3276 func_name_start++;
3277 func_name_len = func_name_limit - func_name_start;
3278 if (func_name_len == 0)
3279 check_source (0, func_name_start);
3280 if (func_name_len != strlen (expected)
a2b22788 3281 || strncmp (func_name_start, expected, func_name_len))
5f8037c4 3282 {
a2b22788
RS
3283 fprintf (stderr, "%s: %d: warning: found `%s' but expected `%s'\n",
3284 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3285 identify_lineno (func_name_start),
3286 dupnstr (func_name_start, func_name_len),
3287 expected);
5f8037c4
RS
3288 return 1;
3289 }
3290 }
3291
3292 output_up_to (start_formals);
3293
3294#ifdef UNPROTOIZE
3295 if (f_list_count == 0)
3296 output_string (def_dec_p->formal_names);
a019653e 3297#else /* !defined (UNPROTOIZE) */
5f8037c4
RS
3298 {
3299 unsigned f_list_depth;
3300 const f_list_chain_item *flci_p = def_dec_p->f_list_chain;
3301
3302 /* At this point, the current value of f_list count says how many
3303 links we have to follow through the f_list_chain to get to the
3304 particular formals list that we need to output next. */
3305
3306 for (f_list_depth = 0; f_list_depth < f_list_count; f_list_depth++)
3307 flci_p = flci_p->chain_next;
3308 output_string (flci_p->formals_list);
3309 }
a019653e 3310#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3311
3312 clean_read_ptr = end_formals - 1;
3313 return 0;
3314}
3315
3316/* Given a pointer to a byte in the clean text buffer which points to the
3317 beginning of a line that contains a "follower" token for a function
3318 definition header, do whatever is necessary to find the right closing
3319 paren for the rightmost formals list of the function definition header.
3320*/
3321
3322static const char *
34e56753
RS
3323find_rightmost_formals_list (clean_text_p)
3324 const char *clean_text_p;
5f8037c4
RS
3325{
3326 const char *end_formals;
3327
3328 /* We are editing a function definition. The line number we did a seek
3329 to contains the first token which immediately follows the entire set of
3330 formals lists which are part of this particular function definition
3331 header.
3332
3333 Our job now is to scan leftwards in the clean text looking for the
3334 right-paren which is at the end of the function header's rightmost
3335 formals list.
3336
3337 If we ignore whitespace, this right paren should be the first one we
3338 see which is (ignoring whitespace) immediately followed either by the
3339 open curly-brace beginning the function body or by an alphabetic
3340 character (in the case where the function definition is in old (K&R)
3341 style and there are some declarations of formal parameters). */
3342
3343 /* It is possible that the right paren we are looking for is on the
3344 current line (together with its following token). Just in case that
3345 might be true, we start out here by skipping down to the right end of
3346 the current line before starting our scan. */
3347
3348 for (end_formals = clean_text_p; *end_formals != '\n'; end_formals++)
3349 continue;
3350 end_formals--;
3351
34e56753
RS
3352#ifdef UNPROTOIZE
3353
5f8037c4
RS
3354 /* Now scan backwards while looking for the right end of the rightmost
3355 formals list associated with this function definition. */
3356
34e56753
RS
3357 {
3358 char ch;
3359 const char *l_brace_p;
3360
3361 /* Look leftward and try to find a right-paren. */
3362
3363 while (*end_formals != ')')
3364 {
3365 if (isspace (*end_formals))
3366 while (isspace (*end_formals))
3367 check_source (--end_formals > clean_read_ptr, 0);
3368 else
3369 check_source (--end_formals > clean_read_ptr, 0);
3370 }
3371
3372 ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3373 /* Since we are unprotoizing an ANSI-style (prototyped) function
3374 definition, there had better not be anything (except whitespace)
3375 between the end of the ANSI formals list and the beginning of the
3376 function body (i.e. the '{'). */
3377
3378 check_source (ch == '{', l_brace_p);
3379 }
3380
a019653e 3381#else /* !defined (UNPROTOIZE) */
34e56753
RS
3382
3383 /* Now scan backwards while looking for the right end of the rightmost
3384 formals list associated with this function definition. */
3385
3386 while (1)
5f8037c4
RS
3387 {
3388 char ch;
3389 const char *l_brace_p;
3390
3391 /* Look leftward and try to find a right-paren. */
3392
3393 while (*end_formals != ')')
3394 {
3395 if (isspace (*end_formals))
3396 while (isspace (*end_formals))
3397 check_source (--end_formals > clean_read_ptr, 0);
3398 else
3399 check_source (--end_formals > clean_read_ptr, 0);
3400 }
3401
3402 ch = *(l_brace_p = forward_to_next_token_char (end_formals));
3403
5f8037c4
RS
3404 /* Since it is possible that we found a right paren before the starting
3405 '{' of the body which IS NOT the one at the end of the real K&R
3406 formals list (say for instance, we found one embedded inside one of
3407 the old K&R formal parameter declarations) we have to check to be
3408 sure that this is in fact the right paren that we were looking for.
3409
3410 The one we were looking for *must* be followed by either a '{' or
3411 by an alphabetic character, while others *cannot* legally be followed
3412 by such characters. */
3413
3414 if ((ch == '{') || isalpha (ch))
3415 break;
3416
3417 /* At this point, we have found a right paren, but we know that it is
3418 not the one we were looking for, so backup one character and keep
3419 looking. */
3420
3421 check_source (--end_formals > clean_read_ptr, 0);
34e56753 3422 }
5f8037c4 3423
a019653e 3424#endif /* !defined (UNPROTOIZE) */
5f8037c4 3425
5f8037c4
RS
3426 return end_formals;
3427}
3428
3429#ifndef UNPROTOIZE
3430
3431/* Insert into the output file a totally new declaration for a function
3432 which (up until now) was being called from within the current block
3433 without having been declared at any point such that the declaration
3434 was visible (i.e. in scope) at the point of the call.
3435
3436 We need to add in explicit declarations for all such function calls
3437 in order to get the full benefit of prototype-based function call
3438 parameter type checking. */
3439
3440static void
34e56753
RS
3441add_local_decl (def_dec_p, clean_text_p)
3442 const def_dec_info *def_dec_p;
3443 const char *clean_text_p;
5f8037c4
RS
3444{
3445 const char *start_of_block;
3446 const char *function_to_edit = def_dec_p->hash_entry->symbol;
3447
3448 /* Don't insert new local explicit declarations unless explicitly requested
3449 to do so. */
3450
3451 if (!local_flag)
3452 return;
3453
3454 /* Setup here to recover from confusing source code detected during this
3455 particular "edit". */
3456
3457 save_pointers ();
3458 if (setjmp (source_confusion_recovery))
3459 {
3460 restore_pointers ();
3461 fprintf (stderr, "%s: local declaration for function `%s' not inserted\n",
a2b22788 3462 pname, function_to_edit);
5f8037c4
RS
3463 return;
3464 }
3465
3466 /* We have already done a seek to the start of the line which should
3467 contain *the* open curly brace which begins the block in which we need
3468 to insert an explicit function declaration (to replace the implicit one).
3469
3470 Now we scan that line, starting from the left, until we find the
3471 open curly brace we are looking for. Note that there may actually be
3472 multiple open curly braces on the given line, but we will be happy
3473 with the leftmost one no matter what. */
3474
3475 start_of_block = clean_text_p;
3476 while (*start_of_block != '{' && *start_of_block != '\n')
3477 check_source (++start_of_block < clean_text_limit, 0);
3478
3479 /* Note that the line from the original source could possibly
3480 contain *no* open curly braces! This happens if the line contains
3481 a macro call which expands into a chunk of text which includes a
3482 block (and that block's associated open and close curly braces).
3483 In cases like this, we give up, issue a warning, and do nothing. */
3484
3485 if (*start_of_block != '{')
3486 {
3487 if (!quiet_flag)
3488 fprintf (stderr,
a2b22788
RS
3489 "\n%s: %d: warning: can't add declaration of `%s' into macro call\n",
3490 def_dec_p->file->hash_entry->symbol, def_dec_p->line,
3491 def_dec_p->hash_entry->symbol);
5f8037c4
RS
3492 return;
3493 }
3494
3495 /* Figure out what a nice (pretty) indentation would be for the new
3496 declaration we are adding. In order to do this, we must scan forward
3497 from the '{' until we find the first line which starts with some
3498 non-whitespace characters (i.e. real "token" material). */
3499
3500 {
3501 const char *ep = forward_to_next_token_char (start_of_block) - 1;
3502 const char *sp;
3503
3504 /* Now we have ep pointing at the rightmost byte of some existing indent
3505 stuff. At least that is the hope.
3506
3507 We can now just scan backwards and find the left end of the existing
3508 indentation string, and then copy it to the output buffer. */
3509
3510 for (sp = ep; isspace (*sp) && *sp != '\n'; sp--)
3511 continue;
3512
3513 /* Now write out the open { which began this block, and any following
3514 trash up to and including the last byte of the existing indent that
3515 we just found. */
3516
3517 output_up_to (ep);
3518
3519 /* Now we go ahead and insert the new declaration at this point.
3520
3521 If the definition of the given function is in the same file that we
3522 are currently editing, and if its full ANSI declaration normally
3523 would start with the keyword `extern', suppress the `extern'. */
3524
3525 {
3526 const char *decl = def_dec_p->definition->ansi_decl;
3527
3528 if ((*decl == 'e') && (def_dec_p->file == def_dec_p->definition->file))
3529 decl += 7;
3530 output_string (decl);
3531 }
3532
d45cf215 3533 /* Finally, write out a new indent string, just like the preceding one
5f8037c4
RS
3534 that we found. This will typically include a newline as the first
3535 character of the indent string. */
3536
3537 output_bytes (sp, (size_t) (ep - sp) + 1);
3538 }
3539}
3540
3541/* Given a pointer to a file_info record, and a pointer to the beginning
3542 of a line (in the clean text buffer) which is assumed to contain the
3543 first "follower" token for the first function definition header in the
3544 given file, find a good place to insert some new global function
3545 declarations (which will replace scattered and imprecise implicit ones)
3546 and then insert the new explicit declaration at that point in the file. */
3547
3548static void
34e56753
RS
3549add_global_decls (file_p, clean_text_p)
3550 const file_info *file_p;
3551 const char *clean_text_p;
5f8037c4
RS
3552{
3553 const def_dec_info *dd_p;
3554 const char *scan_p;
3555
3556 /* Setup here to recover from confusing source code detected during this
3557 particular "edit". */
3558
3559 save_pointers ();
3560 if (setjmp (source_confusion_recovery))
3561 {
3562 restore_pointers ();
3563 fprintf (stderr, "%s: global declarations for file `%s' not inserted\n",
a2b22788 3564 pname, shortpath (NULL, file_p->hash_entry->symbol));
5f8037c4
RS
3565 return;
3566 }
3567
3568 /* Start by finding a good location for adding the new explicit function
3569 declarations. To do this, we scan backwards, ignoring whitespace
3570 and comments and other junk until we find either a semicolon, or until
3571 we hit the beginning of the file. */
3572
3573 scan_p = find_rightmost_formals_list (clean_text_p);
3574 for (;; --scan_p)
3575 {
3576 if (scan_p < clean_text_base)
3577 break;
3578 check_source (scan_p > clean_read_ptr, 0);
3579 if (*scan_p == ';')
3580 break;
3581 }
3582
3583 /* scan_p now points either to a semicolon, or to just before the start
3584 of the whole file. */
3585
3586 /* Now scan forward for the first non-whitespace character. In theory,
3587 this should be the first character of the following function definition
3588 header. We will put in the added declarations just prior to that. */
3589
3590 scan_p++;
3591 while (isspace (*scan_p))
3592 scan_p++;
3593 scan_p--;
3594
3595 output_up_to (scan_p);
3596
3597 /* Now write out full prototypes for all of the things that had been
3598 implicitly declared in this file (but only those for which we were
3599 actually able to find unique matching definitions). Avoid duplicates
3600 by marking things that we write out as we go. */
3601
3602 {
3603 int some_decls_added = 0;
3604
3605 for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3606 if (dd_p->is_implicit && dd_p->definition && !dd_p->definition->written)
3607 {
3608 const char *decl = dd_p->definition->ansi_decl;
3609
3610 /* If the function for which we are inserting a declaration is
3611 actually defined later in the same file, then suppress the
3612 leading `extern' keyword (if there is one). */
3613
3614 if (*decl == 'e' && (dd_p->file == dd_p->definition->file))
3615 decl += 7;
3616
3617 output_string ("\n");
3618 output_string (decl);
3619 some_decls_added = 1;
3620 ((NONCONST def_dec_info *) dd_p->definition)->written = 1;
3621 }
3622 if (some_decls_added)
3623 output_string ("\n\n");
3624 }
3625
3626 /* Unmark all of the definitions that we just marked. */
3627
3628 for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
3629 if (dd_p->definition)
3630 ((NONCONST def_dec_info *) dd_p->definition)->written = 0;
3631}
3632
a019653e 3633#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3634
3635/* Do the editing operation specifically for a function "definition". Note
3636 that editing operations for function "declarations" are handled by a
3637 separate routine above. */
3638
3639static void
34e56753
RS
3640edit_fn_definition (def_dec_p, clean_text_p)
3641 const def_dec_info *def_dec_p;
3642 const char *clean_text_p;
5f8037c4
RS
3643{
3644 const char *end_formals;
3645 const char *function_to_edit = def_dec_p->hash_entry->symbol;
3646
3647 /* Setup here to recover from confusing source code detected during this
3648 particular "edit". */
3649
3650 save_pointers ();
3651 if (setjmp (source_confusion_recovery))
3652 {
3653 restore_pointers ();
3654 fprintf (stderr, "%s: definition of function `%s' not converted\n",
a2b22788 3655 pname, function_to_edit);
5f8037c4
RS
3656 return;
3657 }
3658
3659 end_formals = find_rightmost_formals_list (clean_text_p);
3660
3661 /* end_of_formals now points to the closing right paren of the rightmost
3662 formals list which is actually part of the `header' of the function
3663 definition that we are converting. */
3664
3665 /* If the header of this function definition looks like it declares a
3666 function with a variable number of arguments, and if the way it does
3667 that is different from that way we would like it (i.e. varargs vs.
3668 stdarg) then issue a warning and leave the header unconverted. */
3669
3670 if (other_variable_style_function (def_dec_p->ansi_decl))
3671 {
3672 if (!quiet_flag)
a2b22788
RS
3673 fprintf (stderr, "%s: %d: warning: definition of %s not converted\n",
3674 shortpath (NULL, def_dec_p->file->hash_entry->symbol),
3675 identify_lineno (end_formals),
3676 other_var_style);
5f8037c4
RS
3677 output_up_to (end_formals);
3678 return;
3679 }
3680
3681 if (edit_formals_lists (end_formals, def_dec_p->f_list_count, def_dec_p))
3682 {
3683 restore_pointers ();
3684 fprintf (stderr, "%s: definition of function `%s' not converted\n",
a2b22788 3685 pname, function_to_edit);
5f8037c4
RS
3686 return;
3687 }
3688
3689 /* Have to output the last right paren because this never gets flushed by
3690 edit_formals_list. */
3691
3692 output_up_to (end_formals);
3693
3694#ifdef UNPROTOIZE
3695 {
3696 const char *decl_p;
3697 const char *semicolon_p;
3698 const char *limit_p;
3699 const char *scan_p;
3700 int had_newlines = 0;
3701
3702 /* Now write out the K&R style formal declarations, one per line. */
3703
3704 decl_p = def_dec_p->formal_decls;
3705 limit_p = decl_p + strlen (decl_p);
3706 for (;decl_p < limit_p; decl_p = semicolon_p + 2)
3707 {
3708 for (semicolon_p = decl_p; *semicolon_p != ';'; semicolon_p++)
3709 continue;
3710 output_string ("\n");
3711 output_string (indent_string);
3712 output_bytes (decl_p, (size_t) ((semicolon_p + 1) - decl_p));
3713 }
3714
3715 /* If there are no newlines between the end of the formals list and the
3716 start of the body, we should insert one now. */
3717
3718 for (scan_p = end_formals+1; *scan_p != '{'; )
3719 {
3720 if (*scan_p == '\n')
3721 {
3722 had_newlines = 1;
3723 break;
3724 }
3725 check_source (++scan_p < clean_text_limit, 0);
3726 }
3727 if (!had_newlines)
3728 output_string ("\n");
3729 }
a019653e 3730#else /* !defined (UNPROTOIZE) */
5f8037c4
RS
3731 /* If we are protoizing, there may be some flotsum & jetsum (like comments
3732 and preprocessing directives) after the old formals list but before
3733 the following { and we would like to preserve that stuff while effectively
3734 deleting the existing K&R formal parameter declarations. We do so here
3735 in a rather tricky way. Basically, we white out any stuff *except*
3736 the comments/pp-directives in the original text buffer, then, if there
3737 is anything in this area *other* than whitespace, we output it. */
3738 {
3739 const char *end_formals_orig;
3740 const char *start_body;
3741 const char *start_body_orig;
3742 const char *scan;
3743 const char *scan_orig;
3744 int have_flotsum = 0;
3745 int have_newlines = 0;
3746
3747 for (start_body = end_formals + 1; *start_body != '{';)
3748 check_source (++start_body < clean_text_limit, 0);
3749
3750 end_formals_orig = orig_text_base + (end_formals - clean_text_base);
3751 start_body_orig = orig_text_base + (start_body - clean_text_base);
3752 scan = end_formals + 1;
3753 scan_orig = end_formals_orig + 1;
3754 for (; scan < start_body; scan++, scan_orig++)
3755 {
3756 if (*scan == *scan_orig)
3757 {
3758 have_newlines |= (*scan_orig == '\n');
3759 /* Leave identical whitespace alone. */
3760 if (!isspace (*scan_orig))
3761 *((NONCONST char *)scan_orig) = ' '; /* identical - so whiteout */
3762 }
3763 else
3764 have_flotsum = 1;
3765 }
3766 if (have_flotsum)
3767 output_bytes (end_formals_orig + 1,
3768 (size_t) (start_body_orig - end_formals_orig) - 1);
3769 else
3770 if (have_newlines)
3771 output_string ("\n");
3772 else
3773 output_string (" ");
3774 clean_read_ptr = start_body - 1;
3775 }
a019653e 3776#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
3777}
3778
3779/* Clean up the clean text buffer. Do this by converting comments and
3780 preprocessor directives into spaces. Also convert line continuations
3781 into whitespace. Also, whiteout string and character literals. */
3782
3783static void
34e56753
RS
3784do_cleaning (new_clean_text_base, new_clean_text_limit)
3785 char *new_clean_text_base;
3786 char *new_clean_text_limit;
5f8037c4
RS
3787{
3788 char *scan_p;
3789 int non_whitespace_since_newline = 0;
3790
3791 for (scan_p = new_clean_text_base; scan_p < new_clean_text_limit; scan_p++)
3792 {
3793 switch (*scan_p)
3794 {
3795 case '/': /* Handle comments. */
3796 if (scan_p[1] != '*')
3797 goto regular;
3798 non_whitespace_since_newline = 1;
3799 scan_p[0] = ' ';
3800 scan_p[1] = ' ';
3801 scan_p += 2;
3802 while (scan_p[1] != '/' || scan_p[0] != '*')
3803 {
3804 if (!isspace (*scan_p))
3805 *scan_p = ' ';
3806 if (++scan_p >= new_clean_text_limit)
3807 abort ();
3808 }
3809 *scan_p++ = ' ';
3810 *scan_p = ' ';
3811 break;
3812
3813 case '#': /* Handle pp directives. */
3814 if (non_whitespace_since_newline)
3815 goto regular;
3816 *scan_p = ' ';
3817 while (scan_p[1] != '\n' || scan_p[0] == '\\')
3818 {
3819 if (!isspace (*scan_p))
3820 *scan_p = ' ';
3821 if (++scan_p >= new_clean_text_limit)
3822 abort ();
3823 }
3824 *scan_p++ = ' ';
3825 break;
3826
3827 case '\'': /* Handle character literals. */
3828 non_whitespace_since_newline = 1;
3829 while (scan_p[1] != '\'' || scan_p[0] == '\\')
3830 {
3831 if (scan_p[0] == '\\' && !isspace (scan_p[1]))
3832 scan_p[1] = ' ';
3833 if (!isspace (*scan_p))
3834 *scan_p = ' ';
3835 if (++scan_p >= new_clean_text_limit)
3836 abort ();
3837 }
3838 *scan_p++ = ' ';
3839 break;
3840
3841 case '"': /* Handle string literals. */
3842 non_whitespace_since_newline = 1;
3843 while (scan_p[1] != '"' || scan_p[0] == '\\')
3844 {
3845 if (scan_p[0] == '\\' && !isspace (scan_p[1]))
3846 scan_p[1] = ' ';
3847 if (!isspace (*scan_p))
3848 *scan_p = ' ';
3849 if (++scan_p >= new_clean_text_limit)
3850 abort ();
3851 }
3852 *scan_p++ = ' ';
3853 break;
3854
3855 case '\\': /* Handle line continuations. */
3856 if (scan_p[1] != '\n')
3857 goto regular;
3858 *scan_p = ' ';
3859 break;
3860
3861 case '\n':
3862 non_whitespace_since_newline = 0; /* Reset. */
3863 break;
3864
3865 case ' ':
3866 case '\v':
3867 case '\t':
3868 case '\r':
3869 case '\f':
3870 case '\b':
3871 break; /* Whitespace characters. */
3872
3873 default:
3874regular:
3875 non_whitespace_since_newline = 1;
3876 break;
3877 }
3878 }
3879}
3880
3881/* Given a pointer to the closing right parenthesis for a particular formals
3882 list (in the clean text buffer) find the corresponding left parenthesis
3883 and return a pointer to it. */
3884
3885static const char *
34e56753
RS
3886careful_find_l_paren (p)
3887 const char *p;
5f8037c4
RS
3888{
3889 const char *q;
3890 int paren_depth;
3891
3892 for (paren_depth = 1, q = p-1; paren_depth; check_source (--q >= clean_text_base, 0))
3893 {
3894 switch (*q)
3895 {
3896 case ')':
3897 paren_depth++;
3898 break;
3899 case '(':
3900 paren_depth--;
3901 break;
3902 }
3903 }
3904 return ++q;
3905}
3906
3907/* Scan the clean text buffer for cases of function definitions that we
3908 don't really know about because they were preprocessed out when the
3909 aux info files were created.
3910
3911 In this version of protoize/unprotoize we just give a warning for each
3912 one found. A later version may be able to at least unprotoize such
3913 missed items.
3914
3915 Note that we may easily find all function definitions simply by
3916 looking for places where there is a left paren which is (ignoring
3917 whitespace) immediately followed by either a left-brace or by an
3918 upper or lower case letter. Whenever we find this combination, we
3919 have also found a function definition header.
3920
3921 Finding function *declarations* using syntactic clues is much harder.
3922 I will probably try to do this in a later version though. */
3923
3924static void
34e56753
RS
3925scan_for_missed_items (file_p)
3926 const file_info *file_p;
5f8037c4
RS
3927{
3928 static const char *scan_p;
3929 const char *limit = clean_text_limit - 3;
3930 static const char *backup_limit;
3931
3932 backup_limit = clean_text_base - 1;
3933
3934 for (scan_p = clean_text_base; scan_p < limit; scan_p++)
3935 {
3936 if (*scan_p == ')')
3937 {
3938 static const char *last_r_paren;
3939 const char *ahead_p;
3940
3941 last_r_paren = scan_p;
3942
3943 for (ahead_p = scan_p + 1; isspace (*ahead_p); )
3944 check_source (++ahead_p < limit, limit);
3945
3946 scan_p = ahead_p - 1;
3947
3948 if (isalpha (*ahead_p) || *ahead_p == '{')
3949 {
3950 const char *last_l_paren;
3951 const int lineno = identify_lineno (ahead_p);
3952
3953 if (setjmp (source_confusion_recovery))
3954 continue;
3955
3956 /* We know we have a function definition header. Now skip
3957 leftwards over all of its associated formals lists. */
3958
3959 do
3960 {
3961 last_l_paren = careful_find_l_paren (last_r_paren);
3962 for (last_r_paren = last_l_paren-1; isspace (*last_r_paren); )
3963 check_source (--last_r_paren >= backup_limit, backup_limit);
3964 }
3965 while (*last_r_paren == ')');
3966
3967 if (is_id_char (*last_r_paren))
3968 {
3969 const char *id_limit = last_r_paren + 1;
3970 const char *id_start;
3971 size_t id_length;
3972 const def_dec_info *dd_p;
3973
3974 for (id_start = id_limit-1; is_id_char (*id_start); )
3975 check_source (--id_start >= backup_limit, backup_limit);
3976 id_start++;
3977 backup_limit = id_start;
3978 if ((id_length = (size_t) (id_limit - id_start)) == 0)
3979 goto not_missed;
3980
3981 {
34e56753 3982 char *func_name = (char *) alloca (id_length + 1);
5f8037c4
RS
3983 static const char * const stmt_keywords[]
3984 = { "if", "while", "for", "switch", "return", 0 };
3985 const char * const *stmt_keyword;
3986
3987 strncpy (func_name, id_start, id_length);
3988 func_name[id_length] = '\0';
3989
3990 /* We must check here to see if we are actually looking at
3991 a statement rather than an actual function call. */
3992
3993 for (stmt_keyword = stmt_keywords; *stmt_keyword; stmt_keyword++)
3994 if (!strcmp (func_name, *stmt_keyword))
3995 goto not_missed;
3996
3997#if 0
3998 fprintf (stderr, "%s: found definition of `%s' at %s(%d)\n",
3999 pname,
4000 func_name,
4001 shortpath (NULL, file_p->hash_entry->symbol),
4002 identify_lineno (id_start));
4003#endif /* 0 */
4004 /* We really should check for a match of the function name
4005 here also, but why bother. */
4006
4007 for (dd_p = file_p->defs_decs; dd_p; dd_p = dd_p->next_in_file)
4008 if (dd_p->is_func_def && dd_p->line == lineno)
4009 goto not_missed;
4010
4011 /* If we make it here, then we did not know about this
4012 function definition. */
4013
8241a41f 4014 fprintf (stderr, "%s: %d: warning: `%s' excluded by preprocessing\n",
5f8037c4 4015 shortpath (NULL, file_p->hash_entry->symbol),
a2b22788 4016 identify_lineno (id_start), func_name);
5f8037c4
RS
4017 fprintf (stderr, "%s: function definition not converted\n",
4018 pname);
4019 }
4020 not_missed: ;
4021 }
4022 }
4023 }
4024 }
4025}
4026
4027/* Do all editing operations for a single source file (either a "base" file
4028 or an "include" file). To do this we read the file into memory, keep a
4029 virgin copy there, make another cleaned in-core copy of the original file
4030 (i.e. one in which all of the comments and preprocessor directives have
4031 been replaced with whitespace), then use these two in-core copies of the
4032 file to make a new edited in-core copy of the file. Finally, rename the
4033 original file (as a way of saving it), and then write the edited version
4034 of the file from core to a disk file of the same name as the original.
4035
4036 Note that the trick of making a copy of the original sans comments &
4037 preprocessor directives make the editing a whole lot easier. */
4038
4039static void
34e56753
RS
4040edit_file (hp)
4041 const hash_table_entry *hp;
5f8037c4
RS
4042{
4043 struct stat stat_buf;
4044 const file_info *file_p = hp->fip;
4045 char *new_orig_text_base;
4046 char *new_orig_text_limit;
4047 char *new_clean_text_base;
4048 char *new_clean_text_limit;
4049 size_t orig_size;
4050 size_t repl_size;
4051 int first_definition_in_file;
4052
4053 /* If we are not supposed to be converting this file, or if there is
4054 nothing in there which needs converting, just skip this file. */
4055
4056 if (!needs_to_be_converted (file_p))
4057 return;
4058
a2b22788 4059 convert_filename = file_p->hash_entry->symbol;
5f8037c4
RS
4060
4061 /* Convert a file if it is in a directory where we want conversion
4062 and the file is not excluded. */
4063
a2b22788
RS
4064 if (!directory_specified_p (convert_filename)
4065 || file_excluded_p (convert_filename))
5f8037c4
RS
4066 {
4067 if (!quiet_flag
4068#ifdef UNPROTOIZE
4069 /* Don't even mention "system" include files unless we are
4070 protoizing. If we are protoizing, we mention these as a
1a2ef701 4071 gentle way of prodding the user to convert his "system"
5f8037c4 4072 include files to prototype format. */
a2b22788 4073 && !in_system_include_dir (convert_filename)
a019653e 4074#endif /* defined (UNPROTOIZE) */
5f8037c4 4075 )
8241a41f 4076 fprintf (stderr, "%s: `%s' not converted\n",
a2b22788 4077 pname, shortpath (NULL, convert_filename));
5f8037c4
RS
4078 return;
4079 }
4080
4081 /* Let the user know what we are up to. */
4082
4083 if (nochange_flag)
34e56753
RS
4084 fprintf (stderr, "%s: would convert file `%s'\n",
4085 pname, shortpath (NULL, convert_filename));
5f8037c4 4086 else
34e56753
RS
4087 fprintf (stderr, "%s: converting file `%s'\n",
4088 pname, shortpath (NULL, convert_filename));
4089 fflush (stderr);
5f8037c4
RS
4090
4091 /* Find out the size (in bytes) of the original file. */
4092
a2b22788 4093 /* The cast avoids an erroneous warning on AIX. */
34e56753 4094 if (my_stat ((char *)convert_filename, &stat_buf) == -1)
5f8037c4 4095 {
667cc897 4096 fprintf (stderr, "%s: can't get status for file `%s': %s\n",
a2b22788 4097 pname, shortpath (NULL, convert_filename), sys_errlist[errno]);
5f8037c4
RS
4098 return;
4099 }
4100 orig_size = stat_buf.st_size;
4101
4102 /* Allocate a buffer to hold the original text. */
4103
4104 orig_text_base = new_orig_text_base = (char *) xmalloc (orig_size + 2);
4105 orig_text_limit = new_orig_text_limit = new_orig_text_base + orig_size;
4106
4107 /* Allocate a buffer to hold the cleaned-up version of the original text. */
4108
4109 clean_text_base = new_clean_text_base = (char *) xmalloc (orig_size + 2);
4110 clean_text_limit = new_clean_text_limit = new_clean_text_base + orig_size;
4111 clean_read_ptr = clean_text_base - 1;
4112
4113 /* Allocate a buffer that will hopefully be large enough to hold the entire
4114 converted output text. As an initial guess for the maximum size of the
4115 output buffer, use 125% of the size of the original + some extra. This
4116 buffer can be expanded later as needed. */
4117
4118 repl_size = orig_size + (orig_size >> 2) + 4096;
4119 repl_text_base = (char *) xmalloc (repl_size + 2);
4120 repl_text_limit = repl_text_base + repl_size - 1;
4121 repl_write_ptr = repl_text_base - 1;
4122
4123 {
4124 int input_file;
4125
4126 /* Open the file to be converted in READ ONLY mode. */
4127
34e56753 4128 if ((input_file = my_open (convert_filename, O_RDONLY, 0444)) == -1)
5f8037c4 4129 {
667cc897 4130 fprintf (stderr, "%s: can't open file `%s' for reading: %s\n",
a2b22788
RS
4131 pname, shortpath (NULL, convert_filename),
4132 sys_errlist[errno]);
5f8037c4
RS
4133 return;
4134 }
4135
4136 /* Read the entire original source text file into the original text buffer
4137 in one swell fwoop. Then figure out where the end of the text is and
4138 make sure that it ends with a newline followed by a null. */
4139
4140 if (read (input_file, new_orig_text_base, orig_size) != orig_size)
4141 {
4142 close (input_file);
667cc897 4143 fprintf (stderr, "\n%s: error reading input file `%s': %s\n",
a2b22788
RS
4144 pname, shortpath (NULL, convert_filename),
4145 sys_errlist[errno]);
5f8037c4
RS
4146 return;
4147 }
4148
4149 close (input_file);
4150 }
4151
4152 if (orig_size == 0 || orig_text_limit[-1] != '\n')
4153 {
4154 *new_orig_text_limit++ = '\n';
4155 orig_text_limit++;
4156 }
4157
4158 /* Create the cleaned up copy of the original text. */
4159
4160 memcpy (new_clean_text_base, orig_text_base,
4161 (size_t) (orig_text_limit - orig_text_base));
4162 do_cleaning (new_clean_text_base, new_clean_text_limit);
4163
4164#if 0
4165 {
4166 int clean_file;
4167 size_t clean_size = orig_text_limit - orig_text_base;
a2b22788 4168 char *const clean_filename = (char *) alloca (strlen (convert_filename) + 6 + 1);
5f8037c4
RS
4169
4170 /* Open (and create) the clean file. */
4171
a2b22788
RS
4172 strcpy (clean_filename, convert_filename);
4173 strcat (clean_filename, ".clean");
4174 if ((clean_file = creat (clean_filename, 0666)) == -1)
5f8037c4 4175 {
667cc897 4176 fprintf (stderr, "%s: can't create/open clean file `%s': %s\n",
a2b22788
RS
4177 pname, shortpath (NULL, clean_filename),
4178 sys_errlist[errno]);
5f8037c4
RS
4179 return;
4180 }
4181
4182 /* Write the clean file. */
4183
4184 if (write (clean_file, new_clean_text_base, clean_size) != clean_size)
667cc897 4185 fprintf (stderr, "%s: error writing file `%s': %s\n",
a2b22788 4186 pname, shortpath (NULL, clean_filename), sys_errlist[errno]);
5f8037c4
RS
4187
4188 close (clean_file);
4189 }
4190#endif /* 0 */
4191
4192 /* Do a simplified scan of the input looking for things that were not
4193 mentioned in the aux info files because of the fact that they were
4194 in a region of the source which was preprocessed-out (via #if or
4195 via #ifdef). */
4196
4197 scan_for_missed_items (file_p);
4198
4199 /* Setup to do line-oriented forward seeking in the clean text buffer. */
4200
4201 last_known_line_number = 1;
4202 last_known_line_start = clean_text_base;
4203
4204 /* Now get down to business and make all of the necessary edits. */
4205
4206 {
4207 const def_dec_info *def_dec_p;
4208
4209 first_definition_in_file = 1;
4210 def_dec_p = file_p->defs_decs;
4211 for (; def_dec_p; def_dec_p = def_dec_p->next_in_file)
4212 {
4213 const char *clean_text_p = seek_to_line (def_dec_p->line);
4214
4215 /* clean_text_p now points to the first character of the line which
4216 contains the `terminator' for the declaration or definition that
4217 we are about to process. */
4218
4219#ifndef UNPROTOIZE
4220
4221 if (global_flag && def_dec_p->is_func_def && first_definition_in_file)
4222 {
4223 add_global_decls (def_dec_p->file, clean_text_p);
4224 first_definition_in_file = 0;
4225 }
4226
4227 /* Don't edit this item if it is already in prototype format or if it
4228 is a function declaration and we have found no corresponding
4229 definition. */
4230
4231 if (def_dec_p->prototyped
4232 || (!def_dec_p->is_func_def && !def_dec_p->definition))
4233 continue;
4234
a019653e 4235#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4236
4237 if (def_dec_p->is_func_def)
4238 edit_fn_definition (def_dec_p, clean_text_p);
4239 else
4240#ifndef UNPROTOIZE
4241 if (def_dec_p->is_implicit)
4242 add_local_decl (def_dec_p, clean_text_p);
4243 else
a019653e 4244#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4245 edit_fn_declaration (def_dec_p, clean_text_p);
4246 }
4247 }
4248
4249 /* Finalize things. Output the last trailing part of the original text. */
4250
4251 output_up_to (clean_text_limit - 1);
4252
4253 /* If this is just a test run, stop now and just deallocate the buffers. */
4254
4255 if (nochange_flag)
4256 {
4257 free (new_orig_text_base);
4258 free (new_clean_text_base);
4259 free (repl_text_base);
4260 return;
4261 }
4262
4263 /* Change the name of the original input file. This is just a quick way of
4264 saving the original file. */
4265
4266 if (!nosave_flag)
4267 {
a2b22788
RS
4268 char *new_filename =
4269 (char *) xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
5f8037c4 4270
a2b22788
RS
4271 strcpy (new_filename, convert_filename);
4272 strcat (new_filename, save_suffix);
34e56753 4273 if (my_link (convert_filename, new_filename) == -1)
5f8037c4
RS
4274 {
4275 if (errno == EEXIST)
4276 {
4277 if (!quiet_flag)
4278 fprintf (stderr, "%s: warning: file `%s' already saved in `%s'\n",
a2b22788
RS
4279 pname,
4280 shortpath (NULL, convert_filename),
4281 shortpath (NULL, new_filename));
5f8037c4
RS
4282 }
4283 else
4284 {
667cc897 4285 fprintf (stderr, "%s: can't link file `%s' to `%s': %s\n",
a2b22788
RS
4286 pname,
4287 shortpath (NULL, convert_filename),
4288 shortpath (NULL, new_filename),
4289 sys_errlist[errno]);
5f8037c4
RS
4290 return;
4291 }
4292 }
4293 }
4294
34e56753 4295 if (my_unlink (convert_filename) == -1)
5f8037c4 4296 {
667cc897 4297 fprintf (stderr, "%s: can't delete file `%s': %s\n",
a2b22788 4298 pname, shortpath (NULL, convert_filename), sys_errlist[errno]);
5f8037c4
RS
4299 return;
4300 }
4301
4302 {
4303 int output_file;
4304
4305 /* Open (and create) the output file. */
4306
a2b22788 4307 if ((output_file = creat (convert_filename, 0666)) == -1)
5f8037c4 4308 {
667cc897 4309 fprintf (stderr, "%s: can't create/open output file `%s': %s\n",
a2b22788
RS
4310 pname, shortpath (NULL, convert_filename),
4311 sys_errlist[errno]);
5f8037c4
RS
4312 return;
4313 }
4314
4315 /* Write the output file. */
4316
4317 {
4318 unsigned int out_size = (repl_write_ptr + 1) - repl_text_base;
4319
4320 if (write (output_file, repl_text_base, out_size) != out_size)
667cc897 4321 fprintf (stderr, "%s: error writing file `%s': %s\n",
a2b22788
RS
4322 pname, shortpath (NULL, convert_filename),
4323 sys_errlist[errno]);
5f8037c4
RS
4324 }
4325
4326 close (output_file);
4327 }
4328
4329 /* Deallocate the conversion buffers. */
4330
4331 free (new_orig_text_base);
4332 free (new_clean_text_base);
4333 free (repl_text_base);
4334
4335 /* Change the mode of the output file to match the original file. */
4336
a2b22788 4337 /* The cast avoids an erroneous warning on AIX. */
34e56753 4338 if (my_chmod ((char *)convert_filename, stat_buf.st_mode) == -1)
667cc897 4339 fprintf (stderr, "%s: can't change mode of file `%s': %s\n",
a2b22788 4340 pname, shortpath (NULL, convert_filename), sys_errlist[errno]);
5f8037c4
RS
4341
4342 /* Note: We would try to change the owner and group of the output file
4343 to match those of the input file here, except that may not be a good
4344 thing to do because it might be misleading. Also, it might not even
4345 be possible to do that (on BSD systems with quotas for instance). */
4346}
4347
4348/* Do all of the individual steps needed to do the protoization (or
4349 unprotoization) of the files referenced in the aux_info files given
4350 in the command line. */
4351
4352static void
34e56753 4353do_processing ()
5f8037c4
RS
4354{
4355 const char * const *base_pp;
a2b22788
RS
4356 const char * const * const end_pps
4357 = &base_source_filenames[n_base_source_files];
5f8037c4
RS
4358
4359#ifndef UNPROTOIZE
4360 int syscalls_len;
a019653e 4361#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4362
4363 /* One-by-one, check (and create if necessary), open, and read all of the
4364 stuff in each aux_info file. After reading each aux_info file, the
4365 aux_info_file just read will be automatically deleted unless the
4366 keep_flag is set. */
4367
a2b22788 4368 for (base_pp = base_source_filenames; base_pp < end_pps; base_pp++)
5f8037c4
RS
4369 process_aux_info_file (*base_pp, keep_flag, 0);
4370
4371#ifndef UNPROTOIZE
4372
4373 /* Also open and read the special SYSCALLS.c aux_info file which gives us
4374 the prototypes for all of the standard system-supplied functions. */
4375
4376 if (nondefault_syscalls_dir)
4377 {
a2b22788 4378 syscalls_absolute_filename
5f8037c4 4379 = (char *) xmalloc (strlen (nondefault_syscalls_dir)
d742f26c 4380 + sizeof (syscalls_filename) + 1);
a2b22788 4381 strcpy (syscalls_absolute_filename, nondefault_syscalls_dir);
5f8037c4
RS
4382 }
4383 else
4384 {
a2b22788 4385 syscalls_absolute_filename
5f8037c4 4386 = (char *) xmalloc (strlen (default_syscalls_dir)
d742f26c 4387 + sizeof (syscalls_filename) + 1);
a2b22788 4388 strcpy (syscalls_absolute_filename, default_syscalls_dir);
5f8037c4
RS
4389 }
4390
34e56753 4391 syscalls_len = strlen (syscalls_absolute_filename);
a2b22788 4392 if (*(syscalls_absolute_filename + syscalls_len - 1) != '/')
5f8037c4 4393 {
a2b22788
RS
4394 *(syscalls_absolute_filename + syscalls_len++) = '/';
4395 *(syscalls_absolute_filename + syscalls_len) = '\0';
5f8037c4 4396 }
a2b22788 4397 strcat (syscalls_absolute_filename, syscalls_filename);
5f8037c4
RS
4398
4399 /* Call process_aux_info_file in such a way that it does not try to
4400 delete the SYSCALLS aux_info file. */
4401
a2b22788 4402 process_aux_info_file (syscalls_absolute_filename, 1, 1);
5f8037c4 4403
a019653e 4404#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4405
4406 /* When we first read in all of the information from the aux_info files
6dc42e49 4407 we saved in it descending line number order, because that was likely to
5f8037c4
RS
4408 be faster. Now however, we want the chains of def & dec records to
4409 appear in ascending line number order as we get further away from the
4410 file_info record that they hang from. The following line causes all of
4411 these lists to be rearranged into ascending line number order. */
4412
a2b22788 4413 visit_each_hash_node (filename_primary, reverse_def_dec_list);
5f8037c4
RS
4414
4415#ifndef UNPROTOIZE
4416
4417 /* Now do the "real" work. The following line causes each declaration record
4418 to be "visited". For each of these nodes, an attempt is made to match
4419 up the function declaration with a corresponding function definition,
4420 which should have a full prototype-format formals list with it. Once
4421 these match-ups are made, the conversion of the function declarations
4422 to prototype format can be made. */
4423
4424 visit_each_hash_node (function_name_primary, connect_defs_and_decs);
4425
a019653e 4426#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4427
4428 /* Now convert each file that can be converted (and needs to be). */
4429
a2b22788 4430 visit_each_hash_node (filename_primary, edit_file);
5f8037c4
RS
4431
4432#ifndef UNPROTOIZE
4433
4434 /* If we are working in cplusplus mode, try to rename all .c files to .C
4435 files. Don't panic if some of the renames don't work. */
4436
4437 if (cplusplus_flag && !nochange_flag)
a2b22788 4438 visit_each_hash_node (filename_primary, rename_c_file);
5f8037c4 4439
a019653e 4440#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4441}
4442\f
4443static struct option longopts[] =
4444{
4445 {"version", 0, 0, 'V'},
a019653e 4446 {"file_name", 0, 0, 'p'},
5f8037c4
RS
4447 {"quiet", 0, 0, 'q'},
4448 {"silent", 0, 0, 'q'},
4449 {"force", 0, 0, 'f'},
4450 {"keep", 0, 0, 'k'},
4451 {"nosave", 0, 0, 'N'},
4452 {"nochange", 0, 0, 'n'},
4453 {"compiler-options", 1, 0, 'c'},
4454 {"exclude", 1, 0, 'x'},
4455 {"directory", 1, 0, 'd'},
4456#ifdef UNPROTOIZE
4457 {"indent", 1, 0, 'i'},
4458#else
4459 {"local", 0, 0, 'l'},
4460 {"global", 0, 0, 'g'},
4461 {"c++", 0, 0, 'C'},
4462 {"syscalls-dir", 1, 0, 'B'},
4463#endif
4464 {0, 0, 0, 0}
4465};
4466
4467int
34e56753
RS
4468main (argc, argv)
4469 int argc;
4470 char **const argv;
5f8037c4
RS
4471{
4472 int longind;
4473 int c;
f5188608 4474 const char *params = "";
5f8037c4 4475
45ad788b 4476 pname = rindex (argv[0], '/');
5f8037c4
RS
4477 pname = pname ? pname+1 : argv[0];
4478
2e494f70
RS
4479 cwd_buffer = getpwd ();
4480 if (!cwd_buffer)
5f8037c4 4481 {
2e494f70
RS
4482 fprintf (stderr, "%s: cannot get working directory: %s\n",
4483 pname, sys_errlist[errno]);
4484 exit (1);
5f8037c4
RS
4485 }
4486
4487 /* By default, convert the files in the current directory. */
4488 directory_list = string_list_cons (cwd_buffer, NULL);
4489
4490 while ((c = getopt_long (argc, argv,
4491#ifdef UNPROTOIZE
ea8fd45e 4492 "c:d:i:knNp:qvVx:",
5f8037c4 4493#else
ea8fd45e 4494 "B:c:Cd:gklnNp:qvVx:",
5f8037c4
RS
4495#endif
4496 longopts, &longind)) != EOF)
4497 {
4498 if (c == 0) /* Long option. */
4499 c = longopts[longind].val;
4500 switch (c)
4501 {
ef91d7e2 4502 case 'p':
a019653e 4503 compiler_file_name = optarg;
ef91d7e2 4504 break;
5f8037c4
RS
4505 case 'd':
4506 directory_list
4507 = string_list_cons (abspath (NULL, optarg), directory_list);
4508 break;
4509 case 'x':
4510 exclude_list = string_list_cons (optarg, exclude_list);
4511 break;
4512
ea8fd45e 4513 case 'v':
5f8037c4
RS
4514 case 'V':
4515 version_flag = 1;
4516 break;
4517 case 'q':
4518 quiet_flag = 1;
4519 break;
4520#if 0
4521 case 'f':
4522 force_flag = 1;
4523 break;
4524#endif
4525 case 'n':
4526 nochange_flag = 1;
4527 keep_flag = 1;
4528 break;
4529 case 'N':
4530 nosave_flag = 1;
4531 break;
4532 case 'k':
4533 keep_flag = 1;
4534 break;
4535 case 'c':
a609bfc6 4536 params = optarg;
5f8037c4
RS
4537 break;
4538#ifdef UNPROTOIZE
4539 case 'i':
4540 indent_string = optarg;
4541 break;
a019653e 4542#else /* !defined (UNPROTOIZE) */
5f8037c4
RS
4543 case 'l':
4544 local_flag = 1;
4545 break;
4546 case 'g':
4547 global_flag = 1;
4548 break;
4549 case 'C':
4550 cplusplus_flag = 1;
4551 break;
4552 case 'B':
4553 nondefault_syscalls_dir = optarg;
4554 break;
a019653e 4555#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4556 default:
4557 usage ();
4558 }
4559 }
4560
a609bfc6
RS
4561 /* Set up compile_params based on -p and -c options. */
4562 munge_compile_params (params);
4563
a2b22788 4564 n_base_source_files = argc - optind;
5f8037c4 4565
a2b22788 4566 /* Now actually make a list of the base source filenames. */
5f8037c4 4567
a2b22788
RS
4568 base_source_filenames =
4569 (const char **) xmalloc ((n_base_source_files + 1) * sizeof (char *));
4570 n_base_source_files = 0;
5f8037c4
RS
4571 for (; optind < argc; optind++)
4572 {
4573 const char *path = abspath (NULL, argv[optind]);
4574 int len = strlen (path);
4575
4576 if (path[len-1] == 'c' && path[len-2] == '.')
a2b22788 4577 base_source_filenames[n_base_source_files++] = path;
5f8037c4
RS
4578 else
4579 {
a2b22788 4580 fprintf (stderr, "%s: input file names must have .c suffixes: %s\n",
5f8037c4
RS
4581 pname, shortpath (NULL, path));
4582 errors++;
4583 }
4584 }
4585
4586#ifndef UNPROTOIZE
4587 /* We are only interested in the very first identifier token in the
4588 definition of `va_list', so if there is more junk after that first
4589 identifier token, delete it from the `varargs_style_indicator'. */
4590 {
4591 const char *cp;
4592
4593 for (cp = varargs_style_indicator; isalnum (*cp) || *cp == '_'; cp++)
4594 continue;
4595 if (*cp != 0)
4596 varargs_style_indicator = savestring (varargs_style_indicator,
4597 cp - varargs_style_indicator);
4598 }
a019653e 4599#endif /* !defined (UNPROTOIZE) */
5f8037c4
RS
4600
4601 if (errors)
4602 usage ();
4603 else
4604 {
4605 if (version_flag)
4606 fprintf (stderr, "%s: %s\n", pname, version_string);
4607 do_processing ();
4608 }
4609 if (errors)
4610 exit (1);
4611 else
4612 exit (0);
4613 return 1;
4614}
This page took 0.628457 seconds and 5 git commands to generate.