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