421 lines
12 KiB
Plaintext
421 lines
12 KiB
Plaintext
$NetBSD: patch-ai,v 1.1 2003/07/12 11:39:53 jtb Exp $
|
|
|
|
--- ../gcc-2.95.3/gcc/p/gpc.c.orig
|
|
+++ ../gcc-2.95.3/gcc/p/gpc.c
|
|
@@ -245,9 +245,13 @@
|
|
static void clear_failure_queue PROTO((void));
|
|
static int check_live_switch PROTO((int, int));
|
|
static const char *handle_braces PROTO((const char *));
|
|
+static const struct spec_function *lookup_spec_function PROTO((const char *));
|
|
+static const char *eval_spec_function PROTO((const char *, const char *));
|
|
+static const char *handle_spec_function PROTO((const char *));
|
|
static char *save_string PROTO((const char *, int));
|
|
extern int do_spec PROTO((const char *));
|
|
static int do_spec_1 PROTO((const char *, int, const char *));
|
|
+static int do_spec_2 PROTO((const char *));
|
|
static const char *find_file PROTO((const char *));
|
|
static int is_directory PROTO((const char *, const char *, int));
|
|
static void validate_switches PROTO((const char *));
|
|
@@ -280,6 +284,7 @@
|
|
static void process_command PROTO ((int, char **));
|
|
static int execute PROTO ((void));
|
|
static void unused_prefix_warnings PROTO ((struct path_prefix *));
|
|
+static void alloc_args PROTO ((void));
|
|
static void clear_args PROTO ((void));
|
|
static void fatal_error PROTO ((int));
|
|
|
|
@@ -290,6 +295,9 @@
|
|
extern char *xrealloc PROTO((void *, size_t));
|
|
#endif
|
|
|
|
+
|
|
+static const char *if_exists_spec_function PROTO ((int, const char **));
|
|
+
|
|
/* Specs are strings containing lines, each of which (if not blank)
|
|
is made up of a program name, and arguments separated by spaces.
|
|
The program name must be exact and start from root, since no path
|
|
@@ -373,6 +381,12 @@
|
|
%* substitute the variable part of a matched option. (See below.)
|
|
Note that each comma in the substituted string is replaced by
|
|
a single space.
|
|
+ %:function(args)
|
|
+ Call the named function FUNCTION, passing it ARGS. ARGS is
|
|
+ first processed as a nested spec string, then split into an
|
|
+ argument vector in the usual fashion. The function returns
|
|
+ a string which is processed as if it had appeared literally
|
|
+ as part of the current spec.
|
|
%{S} substitutes the -S switch, if that switch was given to CC.
|
|
If that switch was not specified, this substitutes nothing.
|
|
Here S is a metasyntactic variable.
|
|
@@ -1370,6 +1384,24 @@
|
|
static struct spec_list *specs = (struct spec_list *)0;
|
|
|
|
|
|
+/* The mapping of a spec function name to the C function that
|
|
+ implements it. */
|
|
+struct spec_function
|
|
+{
|
|
+ const char *name;
|
|
+ const char *(*func) PROTO ((int, const char **));
|
|
+};
|
|
+
|
|
+/* List of static spec functions. */
|
|
+
|
|
+static const struct spec_function static_spec_functions[] =
|
|
+{
|
|
+ { "if-exists", if_exists_spec_function },
|
|
+ { 0, 0 }
|
|
+};
|
|
+
|
|
+static int processing_spec_function;
|
|
+
|
|
/* Initialize the specs lookup routines. */
|
|
|
|
static void
|
|
@@ -1598,6 +1630,15 @@
|
|
|
|
static char *multilib_dir;
|
|
|
|
+/* Allocate the argument vector. */
|
|
+
|
|
+static void
|
|
+alloc_args ()
|
|
+{
|
|
+ argbuf_length = 10;
|
|
+ argbuf = (char **) xmalloc (argbuf_length * sizeof (char *));
|
|
+}
|
|
+
|
|
#ifdef GPC
|
|
/* Print a help screen and exit */
|
|
static void print_message_and_exit PROTO((void));
|
|
@@ -2482,6 +2523,9 @@
|
|
|
|
struct command *commands; /* each command buffer with above info. */
|
|
|
|
+ if (processing_spec_function)
|
|
+ abort ();
|
|
+
|
|
/* Count # of piped commands. */
|
|
for (n_commands = 1, i = 0; i < argbuf_index; i++)
|
|
if (strcmp (argbuf[i], "|") == 0)
|
|
@@ -2665,6 +2709,11 @@
|
|
|
|
static int n_infiles;
|
|
|
|
+/* This counts the number of libraries added by lang_specific_driver, so that
|
|
+ we can tell if there were any user supplied any files or libraries. */
|
|
+
|
|
+static int added_libraries;
|
|
+
|
|
/* And a vector of corresponding output files is made up later. */
|
|
|
|
static const char **outfiles;
|
|
@@ -2851,7 +2900,7 @@
|
|
strncpy (nstore, startp, endp-startp);
|
|
if (endp == startp)
|
|
strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
|
|
- else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
|
|
+ else if (!IS_DIR_SEPARATOR (endp[-1]))
|
|
{
|
|
nstore[endp-startp] = DIR_SEPARATOR;
|
|
nstore[endp-startp+1] = 0;
|
|
@@ -2882,7 +2931,7 @@
|
|
strncpy (nstore, startp, endp-startp);
|
|
if (endp == startp)
|
|
strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
|
|
- else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
|
|
+ else if (!IS_DIR_SEPARATOR (endp[-1]))
|
|
{
|
|
nstore[endp-startp] = DIR_SEPARATOR;
|
|
nstore[endp-startp+1] = 0;
|
|
@@ -2915,7 +2964,7 @@
|
|
strncpy (nstore, startp, endp-startp);
|
|
if (endp == startp)
|
|
strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
|
|
- else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
|
|
+ else if (!IS_DIR_SEPARATOR (endp[-1]))
|
|
{
|
|
nstore[endp-startp] = DIR_SEPARATOR;
|
|
nstore[endp-startp+1] = 0;
|
|
@@ -3518,14 +3567,7 @@
|
|
{
|
|
int value;
|
|
|
|
- clear_args ();
|
|
- arg_going = 0;
|
|
- delete_this_arg = 0;
|
|
- this_is_output_file = 0;
|
|
- this_is_library_file = 0;
|
|
- input_from_pipe = 0;
|
|
-
|
|
- value = do_spec_1 (spec, 0, NULL_PTR);
|
|
+ value = do_spec_2 (spec);
|
|
|
|
/* Force out any unfinished command.
|
|
If -pipe, this forces out the last command if it ended in `|'. */
|
|
@@ -3541,6 +3583,20 @@
|
|
return value;
|
|
}
|
|
|
|
+static int
|
|
+do_spec_2 (spec)
|
|
+ const char *spec;
|
|
+{
|
|
+ clear_args ();
|
|
+ arg_going = 0;
|
|
+ delete_this_arg = 0;
|
|
+ this_is_output_file = 0;
|
|
+ this_is_library_file = 0;
|
|
+ input_from_pipe = 0;
|
|
+
|
|
+ return do_spec_1 (spec, 0, NULL_PTR);
|
|
+}
|
|
+
|
|
/* Process the sub-spec SPEC as a portion of a larger spec.
|
|
This is like processing a whole spec except that we do
|
|
not initialize at the beginning and we do not supply a
|
|
@@ -4258,6 +4314,12 @@
|
|
return -1;
|
|
break;
|
|
|
|
+ case ':':
|
|
+ p = handle_spec_function (p);
|
|
+ if (p == 0)
|
|
+ return -1;
|
|
+ break;
|
|
+
|
|
case '%':
|
|
obstack_1grow (&obstack, '%');
|
|
break;
|
|
@@ -4414,7 +4476,173 @@
|
|
arg_going = 1;
|
|
}
|
|
|
|
- return 0; /* End of string */
|
|
+ /* End of string. If we are processing a spec function, we need to
|
|
+ end any pending argument. */
|
|
+ if (processing_spec_function && arg_going)
|
|
+ {
|
|
+ obstack_1grow (&obstack, 0);
|
|
+ string = obstack_finish (&obstack);
|
|
+ if (this_is_library_file)
|
|
+ string = find_file (string);
|
|
+ store_arg (string, delete_this_arg, this_is_output_file);
|
|
+ if (this_is_output_file)
|
|
+ outfiles[input_file_number] = string;
|
|
+ arg_going = 0;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Look up a spec function. */
|
|
+
|
|
+static const struct spec_function *
|
|
+lookup_spec_function (name)
|
|
+ const char *name;
|
|
+{
|
|
+ static const struct spec_function * const spec_function_tables[] =
|
|
+ {
|
|
+ static_spec_functions,
|
|
+ };
|
|
+ const struct spec_function *sf;
|
|
+ unsigned int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE (spec_function_tables); i++)
|
|
+ {
|
|
+ for (sf = spec_function_tables[i]; sf->name != NULL; sf++)
|
|
+ if (strcmp (sf->name, name) == 0)
|
|
+ return sf;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/* Evaluate a spec function. */
|
|
+
|
|
+static const char *
|
|
+eval_spec_function (func, args)
|
|
+ const char *func, *args;
|
|
+{
|
|
+ const struct spec_function *sf;
|
|
+ const char *funcval;
|
|
+
|
|
+ /* Saved spec processing context. */
|
|
+ int save_argbuf_index;
|
|
+ int save_argbuf_length;
|
|
+ char **save_argbuf;
|
|
+
|
|
+ int save_arg_going;
|
|
+ int save_delete_this_arg;
|
|
+ int save_this_is_output_file;
|
|
+ int save_this_is_library_file;
|
|
+ int save_input_from_pipe;
|
|
+
|
|
+
|
|
+ sf = lookup_spec_function (func);
|
|
+ if (sf == NULL)
|
|
+ fatal ("unknown spec function `%s'", func);
|
|
+
|
|
+ /* Push the spec processing context. */
|
|
+ save_argbuf_index = argbuf_index;
|
|
+ save_argbuf_length = argbuf_length;
|
|
+ save_argbuf = argbuf;
|
|
+
|
|
+ save_arg_going = arg_going;
|
|
+ save_delete_this_arg = delete_this_arg;
|
|
+ save_this_is_output_file = this_is_output_file;
|
|
+ save_this_is_library_file = this_is_library_file;
|
|
+ save_input_from_pipe = input_from_pipe;
|
|
+
|
|
+ /* Create a new spec processing context, and build the function
|
|
+ arguments. */
|
|
+
|
|
+ alloc_args ();
|
|
+ if (do_spec_2 (args) < 0)
|
|
+ fatal ("error in args to spec function `%s'", func);
|
|
+
|
|
+ /* argbuf_index is an index for the next argument to be inserted, and
|
|
+ so contains the count of the args already inserted. */
|
|
+
|
|
+ funcval = (*sf->func) (argbuf_index, (const char **) argbuf);
|
|
+
|
|
+ /* Pop the spec processing context. */
|
|
+ argbuf_index = save_argbuf_index;
|
|
+ argbuf_length = save_argbuf_length;
|
|
+ free (argbuf);
|
|
+ argbuf = save_argbuf;
|
|
+
|
|
+ arg_going = save_arg_going;
|
|
+ delete_this_arg = save_delete_this_arg;
|
|
+ this_is_output_file = save_this_is_output_file;
|
|
+ this_is_library_file = save_this_is_library_file;
|
|
+ input_from_pipe = save_input_from_pipe;
|
|
+
|
|
+ return funcval;
|
|
+}
|
|
+
|
|
+/* Handle a spec function call of the form:
|
|
+
|
|
+ %:function(args)
|
|
+
|
|
+ ARGS is processed as a spec in a separate context and split into an
|
|
+ argument vector in the normal fashion. The function returns a string
|
|
+ containing a spec which we then process in the caller's context, or
|
|
+ NULL if no processing is required. */
|
|
+
|
|
+static const char *
|
|
+handle_spec_function (p)
|
|
+ const char *p;
|
|
+{
|
|
+ char *func, *args;
|
|
+ const char *endp, *funcval;
|
|
+ int count;
|
|
+
|
|
+ processing_spec_function++;
|
|
+
|
|
+ /* Get the function name. */
|
|
+ for (endp = p; *endp != '\0'; endp++)
|
|
+ {
|
|
+ if (*endp == '(') /* ) */
|
|
+ break;
|
|
+ /* Only allow [A-Za-z0-9], -, and _ in function names. */
|
|
+ if (!ISALNUM (*endp) && !(*endp == '-' || *endp == '_'))
|
|
+ fatal ("malformed spec function name");
|
|
+ }
|
|
+ if (*endp != '(') /* ) */
|
|
+ fatal ("no arguments for spec function");
|
|
+ func = save_string (p, endp - p);
|
|
+ p = ++endp;
|
|
+
|
|
+ /* Get the arguments. */
|
|
+ for (count = 0; *endp != '\0'; endp++)
|
|
+ {
|
|
+ /* ( */
|
|
+ if (*endp == ')')
|
|
+ {
|
|
+ if (count == 0)
|
|
+ break;
|
|
+ count--;
|
|
+ }
|
|
+ else if (*endp == '(') /* ) */
|
|
+ count++;
|
|
+ }
|
|
+ /* ( */
|
|
+ if (*endp != ')')
|
|
+ fatal ("malformed spec function arguments");
|
|
+ args = save_string (p, endp - p);
|
|
+ p = ++endp;
|
|
+
|
|
+ /* p now points to just past the end of the spec function expression. */
|
|
+
|
|
+ funcval = eval_spec_function (func, args);
|
|
+ if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
|
|
+ p = NULL;
|
|
+
|
|
+ free (func);
|
|
+ free (args);
|
|
+
|
|
+ processing_spec_function--;
|
|
+
|
|
+ return p;
|
|
}
|
|
|
|
/* Return 0 if we call do_spec_1 and that returns -1. */
|
|
@@ -5146,7 +5374,8 @@
|
|
#endif /* GPC */
|
|
|
|
p = argv[0] + strlen (argv[0]);
|
|
- while (p != argv[0] && p[-1] != '/' && p[-1] != DIR_SEPARATOR) --p;
|
|
+ while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
|
|
+ --p;
|
|
programname = p;
|
|
|
|
#ifdef GPC
|
|
@@ -5166,8 +5395,8 @@
|
|
signal (SIGPIPE, fatal_error);
|
|
#endif
|
|
|
|
- argbuf_length = 10;
|
|
- argbuf = (char **) xmalloc (argbuf_length * sizeof (char *));
|
|
+ /* Allocate the argument vector. */
|
|
+ alloc_args ();
|
|
|
|
obstack_init (&obstack);
|
|
|
|
@@ -5469,7 +5698,7 @@
|
|
#endif
|
|
}
|
|
|
|
- if (n_infiles == 0)
|
|
+ if (n_infiles == added_libraries)
|
|
fatal ("No input files");
|
|
|
|
/* Make a place to record the compiler output file names
|
|
@@ -6380,3 +6609,25 @@
|
|
++p;
|
|
}
|
|
}
|
|
+
|
|
+/* if-exists built-in spec function.
|
|
+
|
|
+ Checks to see if the file specified by the absolute pathname in
|
|
+ ARGS exists. Returns that pathname if found.
|
|
+
|
|
+ The usual use for this function is to check for a library file
|
|
+ (whose name has been expanded with %s). */
|
|
+
|
|
+#define IS_ABSOLUTE_PATHNAME(cp) ((cp)[0] == '/')
|
|
+
|
|
+static const char *
|
|
+if_exists_spec_function (argc, argv)
|
|
+ int argc;
|
|
+ const char **argv;
|
|
+{
|
|
+ /* Must have only one argument. */
|
|
+ if (argc == 1 && IS_ABSOLUTE_PATHNAME (argv[0]) && ! access (argv[0], R_OK))
|
|
+ return argv[0];
|
|
+
|
|
+ return NULL;
|
|
+}
|