|  | 
 | /* 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__) */ |