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