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