X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgcc.c;h=9522611773f8116639bf5ba83c1aef52fbcd2af4;hb=839904a0e3a1859cdfeb5ff23e5263c332f347fa;hp=0820bd7cac065fad7e80664df6c35082340ca95c;hpb=1ba852a1a349ccd1dbb01454b4f1445731aa375e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gcc.c b/gcc/gcc.c index 0820bd7cac0..9522611773f 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -17,8 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. This paragraph is here to try to keep Sun CC from dying. The number of chars here seems crucial!!!! */ @@ -80,6 +80,7 @@ compilation is specified by a string called a "spec". */ #if ! defined( SIGCHLD ) && defined( SIGCLD ) # define SIGCHLD SIGCLD #endif +#include "xregex.h" #include "obstack.h" #include "intl.h" #include "prefix.h" @@ -349,6 +350,7 @@ static const char *convert_filename (const char *, int, int); static const char *if_exists_spec_function (int, const char **); static const char *if_exists_else_spec_function (int, const char **); static const char *replace_outfile_spec_function (int, const char **); +static const char *version_compare_spec_function (int, const char **); /* The Specs Language @@ -596,11 +598,11 @@ proper position among the other output files. */ #define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \ --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc\ --wrap=mmap --wrap=munmap --wrap=alloca\ -} %{fmudflapth: --wrap=pthread_create --wrap=pthread_join --wrap=pthread_exit\ +} %{fmudflapth: --wrap=pthread_create\ }} %{fmudflap|fmudflapth: --wrap=main}" #endif #ifndef MFLIB_SPEC -#define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}" +#define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}" #endif /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is @@ -668,6 +670,14 @@ proper position among the other output files. */ #define LINK_GCC_C_SEQUENCE_SPEC "%G %L %G" #endif +#ifndef LINK_SSP_SPEC +#ifdef TARGET_LIBC_PROVIDES_SSP +#define LINK_SSP_SPEC "%{fstack-protector:}" +#else +#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}" +#endif +#endif + #ifndef LINK_PIE_SPEC #ifdef HAVE_LD_PIE #define LINK_PIE_SPEC "%{pie:-pie} " @@ -689,7 +699,7 @@ proper position among the other output files. */ %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ %{static:} %{L*} %(mfwrap) %(link_libgcc) %o %(mflib)\ %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\ - %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\ + %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\ %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}" #endif @@ -719,6 +729,7 @@ static const char *cpp_spec = CPP_SPEC; static const char *cc1_spec = CC1_SPEC; static const char *cc1plus_spec = CC1PLUS_SPEC; static const char *link_gcc_c_sequence_spec = LINK_GCC_C_SEQUENCE_SPEC; +static const char *link_ssp_spec = LINK_SSP_SPEC; static const char *asm_spec = ASM_SPEC; static const char *asm_final_spec = ASM_FINAL_SPEC; static const char *link_spec = LINK_SPEC; @@ -909,16 +920,16 @@ static const struct compiler default_compilers[] = {".m", "#Objective-C", 0, 0, 0}, {".mi", "#Objective-C", 0, 0, 0}, {".mm", "#Objective-C++", 0, 0, 0}, {".M", "#Objective-C++", 0, 0, 0}, {".mii", "#Objective-C++", 0, 0, 0}, - {".cc", "#C++", 0, 0, 0}, {".cxx", "#C++", 0, 0, 0}, - {".cpp", "#C++", 0, 0, 0}, {".cp", "#C++", 0, 0, 0}, + {".cc", "#C++", 0, 0, 0}, {".cxx", "#C++", 0, 0, 0}, + {".cpp", "#C++", 0, 0, 0}, {".cp", "#C++", 0, 0, 0}, {".c++", "#C++", 0, 0, 0}, {".C", "#C++", 0, 0, 0}, {".CPP", "#C++", 0, 0, 0}, {".ii", "#C++", 0, 0, 0}, {".ads", "#Ada", 0, 0, 0}, {".adb", "#Ada", 0, 0, 0}, - {".f", "#Fortran", 0, 0, 0}, {".for", "#Fortran", 0, 0, 0}, + {".f", "#Fortran", 0, 0, 0}, {".for", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0}, {".FOR", "#Fortran", 0, 0, 0}, {".FPP", "#Fortran", 0, 0, 0}, {".f90", "#Fortran 95", 0, 0, 0}, {".f95", "#Fortran 95", 0, 0, 0}, - {".fpp", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0}, + {".fpp", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0}, {".FOR", "#Fortran", 0, 0, 0}, {".FPP", "#Fortran", 0, 0, 0}, {".r", "#Ratfor", 0, 0, 0}, {".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0}, @@ -1109,6 +1120,7 @@ static const struct option_map option_map[] = {"--static", "-static", 0}, {"--std", "-std=", "aj"}, {"--symbolic", "-symbolic", 0}, + {"--sysroot", "--sysroot=", "aj"}, {"--time", "-time", 0}, {"--trace-includes", "-H", 0}, {"--traditional", "-traditional", 0}, @@ -1429,7 +1441,7 @@ static const char *gcc_libexec_prefix; #ifndef STANDARD_STARTFILE_PREFIX_2 #define STANDARD_STARTFILE_PREFIX_2 "/usr/lib/" #endif - + #ifdef CROSS_COMPILE /* Don't use these prefixes for a cross compiler. */ #undef MD_EXEC_PREFIX #undef MD_STARTFILE_PREFIX @@ -1516,6 +1528,7 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("cc1_options", &cc1_options), INIT_STATIC_SPEC ("cc1plus", &cc1plus_spec), INIT_STATIC_SPEC ("link_gcc_c_sequence", &link_gcc_c_sequence_spec), + INIT_STATIC_SPEC ("link_ssp", &link_ssp_spec), INIT_STATIC_SPEC ("endfile", &endfile_spec), INIT_STATIC_SPEC ("link", &link_spec), INIT_STATIC_SPEC ("lib", &lib_spec), @@ -1567,6 +1580,7 @@ static const struct spec_function static_spec_functions[] = { "if-exists", if_exists_spec_function }, { "if-exists-else", if_exists_else_spec_function }, { "replace-outfile", replace_outfile_spec_function }, + { "version-compare", version_compare_spec_function }, { 0, 0 } }; @@ -1736,7 +1750,7 @@ init_spec (void) } obstack_1grow (&obstack, '\0'); - libgcc_spec = obstack_finish (&obstack); + libgcc_spec = XOBFINISH (&obstack, const char *); } #endif #ifdef USE_AS_TRADITIONAL_FORMAT @@ -1745,14 +1759,14 @@ init_spec (void) static const char tf[] = "--traditional-format "; obstack_grow (&obstack, tf, sizeof(tf) - 1); obstack_grow0 (&obstack, asm_spec, strlen (asm_spec)); - asm_spec = obstack_finish (&obstack); + asm_spec = XOBFINISH (&obstack, const char *); } #endif #ifdef LINK_EH_SPEC /* Prepend LINK_EH_SPEC to whatever link_spec we had before. */ obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1); obstack_grow0 (&obstack, link_spec, strlen (link_spec)); - link_spec = obstack_finish (&obstack); + link_spec = XOBFINISH (&obstack, const char *); #endif specs = sl; @@ -2393,7 +2407,7 @@ build_search_list (struct path_prefix *paths, const char *prefix, } obstack_1grow (&collect_obstack, '\0'); - return obstack_finish (&collect_obstack); + return XOBFINISH (&collect_obstack, char *); } /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables @@ -2923,6 +2937,13 @@ static struct switchstr *switches; static int n_switches; +/* Language is one of three things: + + 1) The name of a real programming language. + 2) NULL, indicating that no one has figured out + what it is yet. + 3) '*', indicating that the file should be passed + to the linker. */ struct infile { const char *name; @@ -2980,7 +3001,7 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED, { obstack_grow (&obstack, name, len - 2); obstack_grow0 (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX)); - name = obstack_finish (&obstack); + name = XOBFINISH (&obstack, const char *); } #endif @@ -3001,7 +3022,7 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED, obstack_grow (&obstack, name, len); obstack_grow0 (&obstack, TARGET_EXECUTABLE_SUFFIX, strlen (TARGET_EXECUTABLE_SUFFIX)); - name = obstack_finish (&obstack); + name = XOBFINISH (&obstack, const char *); #endif return name; @@ -3044,6 +3065,9 @@ display_help (void) fputs (_(" -time Time the execution of each subprocess\n"), stdout); fputs (_(" -specs= Override built-in specs with the contents of \n"), stdout); fputs (_(" -std= Assume that the input sources are for \n"), stdout); + fputs (_("\ + --sysroot= Use as the root directory for headers\n\ + for headers and libraries\n"), stdout); fputs (_(" -B Add to the compiler's search paths\n"), stdout); fputs (_(" -b Run gcc for target , if installed\n"), stdout); fputs (_(" -V Run gcc version number , if installed\n"), stdout); @@ -3151,9 +3175,12 @@ process_command (int argc, const char **argv) } /* If there is a -V or -b option (or both), process it now, before - trying to interpret the rest of the command line. */ + trying to interpret the rest of the command line. + Use heuristic that all configuration names must have at least + one dash '-'. This allows us to pass options starting with -b. */ if (argc > 1 && argv[1][0] == '-' - && (argv[1][1] == 'V' || argv[1][1] == 'b')) + && (argv[1][1] == 'V' || + ((argv[1][1] == 'b') && (NULL != strchr(argv[1] + 2,'-'))))) { const char *new_version = DEFAULT_TARGET_VERSION; const char *new_machine = DEFAULT_TARGET_MACHINE; @@ -3163,7 +3190,8 @@ process_command (int argc, const char **argv) int baselen; while (argc > 1 && argv[1][0] == '-' - && (argv[1][1] == 'V' || argv[1][1] == 'b')) + && (argv[1][1] == 'V' || + ((argv[1][1] == 'b') && ( NULL != strchr(argv[1] + 2,'-'))))) { char opt = argv[1][1]; const char *arg; @@ -3215,7 +3243,7 @@ process_command (int argc, const char **argv) { gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix, standard_exec_prefix); - gcc_libexec_prefix = make_relative_prefix (argv[0], + gcc_libexec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix, standard_libexec_prefix); if (gcc_exec_prefix) @@ -3584,6 +3612,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" switch (c) { case 'b': + if (NULL == strchr(argv[i] + 2, '-')) break; case 'V': fatal ("'-%c' must come at the start of the command line", c); break; @@ -3906,6 +3935,11 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" ; else if (! strcmp (argv[i], "-fhelp")) ; + else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot="))) + { + target_system_root = argv[i] + strlen ("--sysroot="); + target_system_root_changed = 1; + } else if (argv[i][0] == '+' && argv[i][1] == 'e') { /* Compensate for the +e options to the C++ front-end; @@ -4154,7 +4188,7 @@ set_collect_gcc_options (void) } } obstack_grow (&collect_obstack, "\0", 1); - putenv (obstack_finish (&collect_obstack)); + putenv (XOBFINISH (&collect_obstack, char *)); } /* Process a spec string, accumulating and running commands. */ @@ -4253,7 +4287,7 @@ do_spec_2 (const char *spec) if (arg_going) { obstack_1grow (&obstack, 0); - string = obstack_finish (&obstack); + string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4488,7 +4522,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = obstack_finish (&obstack); + string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4533,7 +4567,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = obstack_finish (&obstack); + string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4552,7 +4586,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = obstack_finish (&obstack); + string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -4768,7 +4802,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) bool files_differ = strcmp (input_realname, temp_realname); free (input_realname); free (temp_realname); - if (files_differ) + if (files_differ) #endif { temp_filename = save_string (temp_filename, @@ -4914,7 +4948,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (arg_going) { obstack_1grow (&obstack, 0); - string = obstack_finish (&obstack); + string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -5243,7 +5277,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (processing_spec_function && arg_going) { obstack_1grow (&obstack, 0); - string = obstack_finish (&obstack); + string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); store_arg (string, delete_this_arg, this_is_output_file); @@ -5627,10 +5661,10 @@ handle_braces (const char *p) while (*p++ != '}'); return p; - + invalid: fatal ("braced spec '%s' is invalid at '%c'", orig, *p); - + #undef SKIP_WHITE } @@ -6037,21 +6071,21 @@ main (int argc, const char **argv) obstack_grow (&multilib_obstack, p, strlen (p)); obstack_1grow (&multilib_obstack, 0); - multilib_select = obstack_finish (&multilib_obstack); + multilib_select = XOBFINISH (&multilib_obstack, const char *); q = multilib_matches_raw; while ((p = *q++) != (char *) 0) obstack_grow (&multilib_obstack, p, strlen (p)); obstack_1grow (&multilib_obstack, 0); - multilib_matches = obstack_finish (&multilib_obstack); + multilib_matches = XOBFINISH (&multilib_obstack, const char *); q = multilib_exclusions_raw; while ((p = *q++) != (char *) 0) obstack_grow (&multilib_obstack, p, strlen (p)); obstack_1grow (&multilib_obstack, 0); - multilib_exclusions = obstack_finish (&multilib_obstack); + multilib_exclusions = XOBFINISH (&multilib_obstack, const char *); need_space = FALSE; for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++) @@ -6065,7 +6099,7 @@ main (int argc, const char **argv) } obstack_1grow (&multilib_obstack, 0); - multilib_defaults = obstack_finish (&multilib_obstack); + multilib_defaults = XOBFINISH (&multilib_obstack, const char *); } /* Set up to remember the pathname of gcc and any options @@ -6074,7 +6108,7 @@ main (int argc, const char **argv) obstack_init (&collect_obstack); obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); - putenv (obstack_finish (&collect_obstack)); + putenv (XOBFINISH (&collect_obstack, char *)); #ifdef INIT_ENVIRONMENT /* Set up any other necessary machine specific environment variables. */ @@ -6146,7 +6180,7 @@ main (int argc, const char **argv) && do_spec_2 (sysroot_suffix_spec) == 0) { if (argbuf_index > 1) - error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC."); + error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC"); else if (argbuf_index == 1) target_sysroot_suffix = xstrdup (argbuf[argbuf_index -1]); } @@ -6160,7 +6194,7 @@ main (int argc, const char **argv) { obstack_grow (&obstack, "%(sysroot_spec) ", strlen ("%(sysroot_spec) ")); obstack_grow0 (&obstack, link_spec, strlen (link_spec)); - set_spec ("link", obstack_finish (&obstack)); + set_spec ("link", XOBFINISH (&obstack, const char *)); } #endif @@ -6169,7 +6203,7 @@ main (int argc, const char **argv) && do_spec_2 (sysroot_hdrs_suffix_spec) == 0) { if (argbuf_index > 1) - error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC."); + error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC"); else if (argbuf_index == 1) target_sysroot_hdrs_suffix = xstrdup (argbuf[argbuf_index -1]); } @@ -6349,7 +6383,7 @@ main (int argc, const char **argv) obstack_init (&obstack); do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model); obstack_1grow (&obstack, '\0'); - thrmod = obstack_finish (&obstack); + thrmod = XOBFINISH (&obstack, const char *); #else thrmod = thread_model; #endif @@ -6396,13 +6430,13 @@ main (int argc, const char **argv) for (i = 0; (int) i < n_infiles; i++) { const char *name = infiles[i].name; - struct compiler *compiler = lookup_compiler (name, - strlen (name), + struct compiler *compiler = lookup_compiler (name, + strlen (name), infiles[i].language); - + if (compiler && !(compiler->combinable)) combine_inputs = false; - + if (lang_n_infiles > 0 && compiler != input_file_compiler && infiles[i].language && infiles[i].language[0] != '*') infiles[i].incompiler = compiler; @@ -6422,7 +6456,7 @@ main (int argc, const char **argv) infiles[i].compiled = false; infiles[i].preprocessed = false; } - + if (combine_flag && save_temps_flag) { bool save_combine_inputs = combine_inputs; @@ -6433,7 +6467,7 @@ main (int argc, const char **argv) for (i = 0; (int) i < n_infiles; i++) { int this_file_error = 0; - + input_file_number = i; set_input (infiles[i].name); if (infiles[i].incompiler @@ -6540,11 +6574,21 @@ main (int argc, const char **argv) clear_failure_queue (); } - /* Reset the output file name to the first input file name, for use - with %b in LINK_SPEC on a target that prefers not to emit a.out - by default. */ + /* Reset the input file name to the first compile/object file name, for use + with %b in LINK_SPEC. We use the first input file that we can find + a compiler to compile it instead of using infiles.language since for + languages other than C we use aliases that we then lookup later. */ if (n_infiles > 0) - set_input (infiles[0].name); + { + int i; + + for (i = 0; i < n_infiles ; i++) + if (infiles[i].language && infiles[i].language[0] != '*') + { + set_input (infiles[i].name); + break; + } + } if (error_count == 0) { @@ -6716,40 +6760,46 @@ fancy_abort (const char *file, int line, const char *func) /* Output an error message and exit. */ void -fatal (const char *msgid, ...) +fatal (const char *cmsgid, ...) { va_list ap; - va_start (ap, msgid); + va_start (ap, cmsgid); fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(msgid), ap); + vfprintf (stderr, _(cmsgid), ap); va_end (ap); fprintf (stderr, "\n"); delete_temp_files (); exit (1); } +/* The argument is actually c-format, not gcc-internal-format, + but because functions with identical names are used through + the rest of the compiler with gcc-internal-format, we just + need to hope all users of these functions use the common + subset between c-format and gcc-internal-format. */ + void -error (const char *msgid, ...) +error (const char *gmsgid, ...) { va_list ap; - va_start (ap, msgid); + va_start (ap, gmsgid); fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(msgid), ap); + vfprintf (stderr, _(gmsgid), ap); va_end (ap); fprintf (stderr, "\n"); } static void -notice (const char *msgid, ...) +notice (const char *cmsgid, ...) { va_list ap; - va_start (ap, msgid); - vfprintf (stderr, _(msgid), ap); + va_start (ap, cmsgid); + vfprintf (stderr, _(cmsgid), ap); va_end (ap); } @@ -7071,7 +7121,7 @@ set_multilib_dir (void) obstack_grow (&multilib_obstack, start, end - start); obstack_1grow (&multilib_obstack, 0); - mdswitches[i].str = obstack_finish (&multilib_obstack); + mdswitches[i].str = XOBFINISH (&multilib_obstack, const char *); mdswitches[i++].len = end - start; if (*end == '\0') @@ -7297,7 +7347,7 @@ print_multilib_info (void) invalid_select: fatal ("multilib select '%s' is invalid", multilib_select); } - + ++p; } @@ -7557,8 +7607,9 @@ if_exists_else_spec_function (int argc, const char **argv) } /* replace-outfile built-in spec function. - This looks for the first argument in the outfiles array's name and replaces it - with the second argument. */ + + This looks for the first argument in the outfiles array's name and + replaces it with the second argument. */ static const char * replace_outfile_spec_function (int argc, const char **argv) @@ -7567,7 +7618,7 @@ replace_outfile_spec_function (int argc, const char **argv) /* Must have exactly two arguments. */ if (argc != 2) abort (); - + for (i = 0; i < n_infiles; i++) { if (outfiles[i] && !strcmp (outfiles[i], argv[0])) @@ -7576,3 +7627,120 @@ replace_outfile_spec_function (int argc, const char **argv) return NULL; } +/* Given two version numbers, compares the two numbers. + A version number must match the regular expression + ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))* +*/ +static int +compare_version_strings (const char *v1, const char *v2) +{ + int rresult; + regex_t r; + + if (regcomp (&r, "^([1-9][0-9]*|0)(\\.([1-9][0-9]*|0))*$", + REG_EXTENDED | REG_NOSUB) != 0) + abort (); + rresult = regexec (&r, v1, 0, NULL, 0); + if (rresult == REG_NOMATCH) + fatal ("invalid version number `%s'", v1); + else if (rresult != 0) + abort (); + rresult = regexec (&r, v2, 0, NULL, 0); + if (rresult == REG_NOMATCH) + fatal ("invalid version number `%s'", v2); + else if (rresult != 0) + abort (); + + return strverscmp (v1, v2); +} + + +/* version_compare built-in spec function. + + This takes an argument of the following form: + + [] + + and produces "result" if the comparison evaluates to true, + and nothing if it doesn't. + + The supported values are: + + >= true if switch is a later (or same) version than arg1 + !> opposite of >= + < true if switch is an earlier version than arg1 + !< opposite of < + >< true if switch is arg1 or later, and earlier than arg2 + <> true if switch is earlier than arg1 or is arg2 or later + + If the switch is not present, the condition is false unless + the first character of the is '!'. + + For example, + %:version-compare(>= 10.3 mmacosx-version-min= -lmx) + adds -lmx if -mmacosx-version-min=10.3.9 was passed. */ + +static const char * +version_compare_spec_function (int argc, const char **argv) +{ + int comp1, comp2; + size_t switch_len; + const char *switch_value = NULL; + int nargs = 1, i; + bool result; + + if (argc < 3) + abort (); + if (argv[0][0] == '\0') + abort (); + if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!') + nargs = 2; + if (argc != nargs + 3) + abort (); + + switch_len = strlen (argv[nargs + 1]); + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, argv[nargs + 1], switch_len) + && check_live_switch (i, switch_len)) + switch_value = switches[i].part1 + switch_len; + + if (switch_value == NULL) + comp1 = comp2 = -1; + else + { + comp1 = compare_version_strings (switch_value, argv[1]); + if (nargs == 2) + comp2 = compare_version_strings (switch_value, argv[2]); + else + comp2 = -1; /* This value unused. */ + } + + switch (argv[0][0] << 8 | argv[0][1]) + { + case '>' << 8 | '=': + result = comp1 >= 0; + break; + case '!' << 8 | '<': + result = comp1 >= 0 || switch_value == NULL; + break; + case '<' << 8: + result = comp1 < 0; + break; + case '!' << 8 | '>': + result = comp1 < 0 || switch_value == NULL; + break; + case '>' << 8 | '<': + result = comp1 >= 0 && comp2 < 0; + break; + case '<' << 8 | '>': + result = comp1 < 0 || comp2 >= 0; + break; + + default: + abort (); + } + if (! result) + return NULL; + + return argv[nargs + 2]; +}