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