| |
| /* Install modified versions of certain ANSI-incompatible system header |
| files which are fixed to work correctly with ANSI C and placed in a |
| directory that GCC will search. |
| |
| Copyright (C) 1999, 2000, 2001, 2004, 2009 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "fixlib.h" |
| |
| /* * * * * * * * * * * * * |
| |
| load_file_data loads all the contents of a file into malloc-ed memory. |
| Its argument is the file pointer of the file to read in; the returned |
| result is the NUL terminated contents of the file. The file |
| is presumed to be an ASCII text file containing no NULs. */ |
| |
| char * |
| load_file_data (FILE* fp) |
| { |
| char *pz_data = (char*)NULL; |
| int space_left = -1; /* allow for terminating NUL */ |
| size_t space_used = 0; |
| |
| if (fp == (FILE*)NULL) |
| return pz_data; |
| |
| do |
| { |
| size_t size_read; |
| |
| if (space_left < 1024) |
| { |
| space_left += 4096; |
| pz_data = XRESIZEVEC (char, pz_data, space_left + space_used + 1 ); |
| } |
| size_read = fread (pz_data + space_used, 1, space_left, fp); |
| |
| if (size_read == 0) |
| { |
| if (feof (fp)) |
| break; |
| |
| if (ferror (fp)) |
| { |
| int err = errno; |
| if (err != EISDIR) |
| fprintf (stderr, "error %d (%s) reading input\n", err, |
| xstrerror (err)); |
| free ((void *) pz_data); |
| return (char *) NULL; |
| } |
| } |
| |
| space_left -= size_read; |
| space_used += size_read; |
| } while (! feof (fp)); |
| |
| pz_data = XRESIZEVEC (char, pz_data, space_used+1 ); |
| pz_data[ space_used ] = NUL; |
| |
| return pz_data; |
| } |
| |
| #ifdef IS_CXX_HEADER_NEEDED |
| t_bool |
| is_cxx_header (tCC* fname, tCC* text) |
| { |
| /* First, check to see if the file is in a C++ directory */ |
| for (;;) |
| { |
| switch (*(fname++)) |
| { |
| case 'C': /* check for "CC/" */ |
| if ((fname[0] == 'C') && (fname[1] == '/')) |
| return BOOL_TRUE; |
| break; |
| |
| case 'x': /* check for "xx/" */ |
| if ((fname[0] == 'x') && (fname[1] == '/')) |
| return BOOL_TRUE; |
| break; |
| |
| case '+': /* check for "++" */ |
| if (fname[0] == '+') |
| return BOOL_TRUE; |
| break; |
| |
| case NUL: |
| goto not_cxx_name; |
| } |
| } not_cxx_name:; |
| |
| /* Or it might contain one of several phrases which indicate C++ code. |
| Currently recognized are: |
| extern "C++" |
| -*- (Mode: )? C++ -*- (emacs mode marker) |
| template < |
| */ |
| { |
| tSCC cxxpat[] = "\ |
| extern[ \t]*\"C\\+\\+\"|\ |
| -\\*-[ \t]*([mM]ode:[ \t]*)?[cC]\\+\\+[; \t]*-\\*-|\ |
| template[ \t]*<|\ |
| ^[ \t]*class[ \t]|\ |
| (public|private|protected):|\ |
| ^[ \t]*#[ \t]*pragma[ \t]+(interface|implementation)\ |
| "; |
| static regex_t cxxre; |
| static int compiled; |
| |
| if (!compiled) |
| compile_re (cxxpat, &cxxre, 0, "contents check", "is_cxx_header"); |
| |
| if (xregexec (&cxxre, text, 0, 0, 0) == 0) |
| return BOOL_TRUE; |
| } |
| |
| return BOOL_FALSE; |
| } |
| #endif /* CXX_TYPE_NEEDED */ |
| |
| #ifdef SKIP_QUOTE_NEEDED |
| /* |
| * Skip over a quoted string. Single quote strings may |
| * contain multiple characters if the first character is |
| * a backslash. Especially a backslash followed by octal digits. |
| * We are not doing a correctness syntax check here. |
| */ |
| tCC* |
| skip_quote(char q, char* text ) |
| { |
| for (;;) |
| { |
| char ch = *(text++); |
| switch (ch) |
| { |
| case '\\': |
| text++; /* skip over whatever character follows */ |
| break; |
| |
| case '"': |
| case '\'': |
| if (ch != q) |
| break; |
| /*FALLTHROUGH*/ |
| |
| case '\n': |
| case NUL: |
| goto skip_done; |
| } |
| } skip_done:; |
| |
| return text; |
| } |
| #endif /* SKIP_QUOTE_NEEDED */ |
| |
| /* * * * * * * * * * * * * |
| |
| Compile one regular expression pattern for later use. PAT contains |
| the pattern, RE points to a regex_t structure (which should have |
| been bzeroed). MATCH is 1 if we need to know where the regex |
| matched, 0 if not. If xregcomp fails, prints an error message and |
| aborts; E1 and E2 are strings to shove into the error message. |
| |
| The patterns we search for are all egrep patterns. |
| REG_EXTENDED|REG_NEWLINE produces identical regex syntax/semantics |
| to egrep (verified from 4.4BSD Programmer's Reference Manual). */ |
| void |
| compile_re( tCC* pat, regex_t* re, int match, tCC* e1, tCC* e2 ) |
| { |
| tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\ |
| \texpr = `%s'\n\terror %s\n"; |
| int flags, err; |
| |
| flags = (match ? REG_EXTENDED|REG_NEWLINE |
| : REG_EXTENDED|REG_NEWLINE|REG_NOSUB); |
| err = xregcomp (re, pat, flags); |
| |
| if (err) |
| { |
| char rerrbuf[1024]; |
| regerror (err, re, rerrbuf, 1024); |
| fprintf (stderr, z_bad_comp, e1, e2, pat, rerrbuf); |
| exit (EXIT_FAILURE); |
| } |
| } |
| |
| /* * * * * * * * * * * * * |
| |
| Helper routine and data for the machine_name test and fix. */ |
| |
| tSCC mn_label_pat[] = "^[ \t]*#[ \t]*(if|ifdef|ifndef)[ \t]+"; |
| static regex_t mn_label_re; |
| static regex_t mn_name_re; |
| |
| static int mn_compiled = 0; |
| |
| t_bool |
| mn_get_regexps(regex_t** label_re, regex_t** name_re, tCC* who ) |
| { |
| if (! pz_mn_name_pat) |
| return BOOL_FALSE; |
| |
| if (! mn_compiled) |
| { |
| compile_re (mn_label_pat, &mn_label_re, 1, "label pattern", who); |
| compile_re (pz_mn_name_pat, &mn_name_re, 1, "name pattern", who); |
| mn_compiled++; |
| } |
| *label_re = &mn_label_re; |
| *name_re = &mn_name_re; |
| return BOOL_TRUE; |
| } |
| |
| |
| #ifdef SEPARATE_FIX_PROC |
| |
| char* |
| make_raw_shell_str( char* pz_d, tCC* pz_s, size_t smax ) |
| { |
| tSCC zQ[] = "'\\''"; |
| size_t dtaSize; |
| char* pz_d_start = pz_d; |
| |
| smax--; /* adjust for trailing NUL */ |
| |
| dtaSize = strlen( pz_s ) + 3; |
| |
| { |
| const char* pz = pz_s - 1; |
| |
| for (;;) { |
| pz = strchr( pz+1, '\'' ); |
| if (pz == (char*)NULL) |
| break; |
| dtaSize += sizeof( zQ )-1; |
| } |
| } |
| if (dtaSize > smax) |
| return (char*)NULL; |
| |
| *(pz_d++) = '\''; |
| |
| for (;;) { |
| if ((size_t) (pz_d - pz_d_start) >= smax) |
| return (char*)NULL; |
| switch (*(pz_d++) = *(pz_s++)) { |
| case NUL: |
| goto loopDone; |
| |
| case '\'': |
| if ((size_t) (pz_d - pz_d_start) >= smax - sizeof( zQ )-1) |
| return (char*)NULL; |
| strcpy( pz_d-1, zQ ); |
| pz_d += sizeof( zQ )-2; |
| } |
| } loopDone:; |
| pz_d[-1] = '\''; |
| *pz_d = NUL; |
| |
| return pz_d; |
| } |
| |
| #endif |
| |
| #if defined(__MINGW32__) |
| void |
| fix_path_separators (char* p) |
| { |
| while (p != NULL) |
| { |
| p = strchr (p, '\\'); |
| if (p != NULL) |
| { |
| *p = '/'; |
| ++p; |
| } |
| } |
| } |
| |
| /* Count number of needle character ocurrences in str */ |
| static int |
| count_occurrences_of_char (char* str, char needle) |
| { |
| int cnt = 0; |
| |
| while (str) |
| { |
| str = strchr (str, needle); |
| if (str) |
| { |
| ++str; |
| ++cnt; |
| } |
| } |
| |
| return cnt; |
| } |
| |
| /* On Mingw32, system function will just start cmd by default. |
| Call system function, but prepend ${CONFIG_SHELL} or ${SHELL} -c to the command, |
| replace newlines with '$'\n'', enclose command with double quotes |
| and escape special characters which were originally enclosed in single quotes. |
| */ |
| int |
| system_with_shell (char* s) |
| { |
| static const char z_shell_start_args[] = " -c \""; |
| static const char z_shell_end_args[] = "\""; |
| static const char z_shell_newline[] = "'$'\\n''"; |
| |
| /* Use configured shell if present */ |
| char *env_shell = getenv ("CONFIG_SHELL"); |
| int newline_cnt = count_occurrences_of_char (s, '\n'); |
| int escapes_cnt = count_occurrences_of_char( s, '\\') |
| + count_occurrences_of_char (s, '"') |
| + count_occurrences_of_char (s, '`'); |
| char *long_cmd; |
| char *cmd_endp; |
| int sys_result; |
| char *s_scan; |
| int in_quotes; |
| |
| if (env_shell == NULL) |
| env_shell = getenv ("SHELL"); |
| |
| /* If neither CONFIGURED_SHELL nor SHELL is set, just call standard system function */ |
| if (env_shell == NULL) |
| return system (s); |
| |
| /* Allocate enough memory to fit newly created command string */ |
| long_cmd = XNEWVEC (char, strlen (env_shell) |
| + strlen (z_shell_start_args) |
| + strlen (s) |
| + newline_cnt * (strlen (z_shell_newline) - 1) |
| + escapes_cnt |
| + strlen (z_shell_end_args) |
| + 1); |
| |
| /* Start with ${SHELL} */ |
| strcpy (long_cmd, env_shell); |
| cmd_endp = long_cmd + strlen (long_cmd); |
| |
| /* Opening quote */ |
| strcpy (cmd_endp, z_shell_start_args); |
| cmd_endp += strlen (z_shell_start_args); |
| |
| /* Replace newlines and escape special chars */ |
| in_quotes = 0; |
| for (s_scan = s; *s_scan; ++s_scan) |
| { |
| switch (*s_scan) |
| { |
| case '\n': |
| if (in_quotes) |
| { |
| /* Replace newline inside quotes with '$'\n'' */ |
| strcpy (cmd_endp, z_shell_newline); |
| cmd_endp += strlen (z_shell_newline); |
| } |
| else |
| { |
| /* Replace newlines outside quotes with ; and merge subsequent newlines */ |
| *(cmd_endp++) = ';'; |
| *(cmd_endp++) = ' '; |
| while (*(s_scan + 1) == '\n' || *(s_scan + 1) == ' ' || *(s_scan + 1) == '\t') |
| ++s_scan; |
| } |
| break; |
| case '\'': |
| /* Escape single quote and toggle in_quotes flag */ |
| in_quotes = !in_quotes; |
| *(cmd_endp++) = *s_scan; |
| break; |
| case '\\': |
| case '`': |
| /* Escape backslash and backtick inside quotes */ |
| if (in_quotes) |
| *(cmd_endp++) = '\\'; |
| *(cmd_endp++) = *s_scan; |
| break; |
| case '"': |
| /* Escape double quotes always */ |
| *(cmd_endp++) = '\\'; |
| *(cmd_endp++) = *s_scan; |
| break; |
| default: |
| *(cmd_endp++) = *s_scan; |
| } |
| } |
| |
| /* Closing quote */ |
| strcpy (cmd_endp, z_shell_end_args); |
| |
| sys_result = system (long_cmd); |
| |
| free (long_cmd); |
| |
| return sys_result; |
| } |
| |
| #endif /* defined(__MINGW32__) */ |