1 2 /* Install modified versions of certain ANSI-incompatible system header 3 files which are fixed to work correctly with ANSI C and placed in a 4 directory that GCC will search. 5 6 Copyright (C) 1999, 2000, 2001, 2004, 2009 Free Software Foundation, Inc. 7 8 This file is part of GCC. 9 10 GCC is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3, or (at your option) 13 any later version. 14 15 GCC is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with GCC; see the file COPYING3. If not see 22 <http://www.gnu.org/licenses/>. */ 23 24 #include "fixlib.h" 25 26 /* * * * * * * * * * * * * 27 28 load_file_data loads all the contents of a file into malloc-ed memory. 29 Its argument is the file pointer of the file to read in; the returned 30 result is the NUL terminated contents of the file. The file 31 is presumed to be an ASCII text file containing no NULs. */ 32 33 char * 34 load_file_data (FILE* fp) 35 { 36 char *pz_data = (char*)NULL; 37 int space_left = -1; /* allow for terminating NUL */ 38 size_t space_used = 0; 39 40 if (fp == (FILE*)NULL) 41 return pz_data; 42 43 do 44 { 45 size_t size_read; 46 47 if (space_left < 1024) 48 { 49 space_left += 4096; 50 pz_data = XRESIZEVEC (char, pz_data, space_left + space_used + 1 ); 51 } 52 size_read = fread (pz_data + space_used, 1, space_left, fp); 53 54 if (size_read == 0) 55 { 56 if (feof (fp)) 57 break; 58 59 if (ferror (fp)) 60 { 61 int err = errno; 62 if (err != EISDIR) 63 fprintf (stderr, "error %d (%s) reading input\n", err, 64 xstrerror (err)); 65 free ((void *) pz_data); 66 return (char *) NULL; 67 } 68 } 69 70 space_left -= size_read; 71 space_used += size_read; 72 } while (! feof (fp)); 73 74 pz_data = XRESIZEVEC (char, pz_data, space_used+1 ); 75 pz_data[ space_used ] = NUL; 76 77 return pz_data; 78 } 79 80 #ifdef IS_CXX_HEADER_NEEDED 81 t_bool 82 is_cxx_header (tCC* fname, tCC* text) 83 { 84 /* First, check to see if the file is in a C++ directory */ 85 for (;;) 86 { 87 switch (*(fname++)) 88 { 89 case 'C': /* check for "CC/" */ 90 if ((fname[0] == 'C') && (fname[1] == '/')) 91 return BOOL_TRUE; 92 break; 93 94 case 'x': /* check for "xx/" */ 95 if ((fname[0] == 'x') && (fname[1] == '/')) 96 return BOOL_TRUE; 97 break; 98 99 case '+': /* check for "++" */ 100 if (fname[0] == '+') 101 return BOOL_TRUE; 102 break; 103 104 case NUL: 105 goto not_cxx_name; 106 } 107 } not_cxx_name:; 108 109 /* Or it might contain one of several phrases which indicate C++ code. 110 Currently recognized are: 111 extern "C++" 112 -*- (Mode: )? C++ -*- (emacs mode marker) 113 template < 114 */ 115 { 116 tSCC cxxpat[] = "\ 117 extern[ \t]*\"C\\+\\+\"|\ 118 -\\*-[ \t]*([mM]ode:[ \t]*)?[cC]\\+\\+[; \t]*-\\*-|\ 119 template[ \t]*<|\ 120 ^[ \t]*class[ \t]|\ 121 (public|private|protected):|\ 122 ^[ \t]*#[ \t]*pragma[ \t]+(interface|implementation)\ 123 "; 124 static regex_t cxxre; 125 static int compiled; 126 127 if (!compiled) 128 compile_re (cxxpat, &cxxre, 0, "contents check", "is_cxx_header"); 129 130 if (xregexec (&cxxre, text, 0, 0, 0) == 0) 131 return BOOL_TRUE; 132 } 133 134 return BOOL_FALSE; 135 } 136 #endif /* CXX_TYPE_NEEDED */ 137 138 #ifdef SKIP_QUOTE_NEEDED 139 /* 140 * Skip over a quoted string. Single quote strings may 141 * contain multiple characters if the first character is 142 * a backslash. Especially a backslash followed by octal digits. 143 * We are not doing a correctness syntax check here. 144 */ 145 tCC* 146 skip_quote(char q, char* text ) 147 { 148 for (;;) 149 { 150 char ch = *(text++); 151 switch (ch) 152 { 153 case '\\': 154 text++; /* skip over whatever character follows */ 155 break; 156 157 case '"': 158 case '\'': 159 if (ch != q) 160 break; 161 /*FALLTHROUGH*/ 162 163 case '\n': 164 case NUL: 165 goto skip_done; 166 } 167 } skip_done:; 168 169 return text; 170 } 171 #endif /* SKIP_QUOTE_NEEDED */ 172 173 /* * * * * * * * * * * * * 174 175 Compile one regular expression pattern for later use. PAT contains 176 the pattern, RE points to a regex_t structure (which should have 177 been bzeroed). MATCH is 1 if we need to know where the regex 178 matched, 0 if not. If xregcomp fails, prints an error message and 179 aborts; E1 and E2 are strings to shove into the error message. 180 181 The patterns we search for are all egrep patterns. 182 REG_EXTENDED|REG_NEWLINE produces identical regex syntax/semantics 183 to egrep (verified from 4.4BSD Programmer's Reference Manual). */ 184 void 185 compile_re( tCC* pat, regex_t* re, int match, tCC* e1, tCC* e2 ) 186 { 187 tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\ 188 \texpr = `%s'\n\terror %s\n"; 189 int flags, err; 190 191 flags = (match ? REG_EXTENDED|REG_NEWLINE 192 : REG_EXTENDED|REG_NEWLINE|REG_NOSUB); 193 err = xregcomp (re, pat, flags); 194 195 if (err) 196 { 197 char rerrbuf[1024]; 198 regerror (err, re, rerrbuf, 1024); 199 fprintf (stderr, z_bad_comp, e1, e2, pat, rerrbuf); 200 exit (EXIT_FAILURE); 201 } 202 } 203 204 /* * * * * * * * * * * * * 205 206 Helper routine and data for the machine_name test and fix. */ 207 208 tSCC mn_label_pat[] = "^[ \t]*#[ \t]*(if|ifdef|ifndef)[ \t]+"; 209 static regex_t mn_label_re; 210 static regex_t mn_name_re; 211 212 static int mn_compiled = 0; 213 214 t_bool 215 mn_get_regexps(regex_t** label_re, regex_t** name_re, tCC* who ) 216 { 217 if (! pz_mn_name_pat) 218 return BOOL_FALSE; 219 220 if (! mn_compiled) 221 { 222 compile_re (mn_label_pat, &mn_label_re, 1, "label pattern", who); 223 compile_re (pz_mn_name_pat, &mn_name_re, 1, "name pattern", who); 224 mn_compiled++; 225 } 226 *label_re = &mn_label_re; 227 *name_re = &mn_name_re; 228 return BOOL_TRUE; 229 } 230 231 232 #ifdef SEPARATE_FIX_PROC 233 234 char* 235 make_raw_shell_str( char* pz_d, tCC* pz_s, size_t smax ) 236 { 237 tSCC zQ[] = "'\\''"; 238 size_t dtaSize; 239 char* pz_d_start = pz_d; 240 241 smax--; /* adjust for trailing NUL */ 242 243 dtaSize = strlen( pz_s ) + 3; 244 245 { 246 const char* pz = pz_s - 1; 247 248 for (;;) { 249 pz = strchr( pz+1, '\'' ); 250 if (pz == (char*)NULL) 251 break; 252 dtaSize += sizeof( zQ )-1; 253 } 254 } 255 if (dtaSize > smax) 256 return (char*)NULL; 257 258 *(pz_d++) = '\''; 259 260 for (;;) { 261 if ((size_t) (pz_d - pz_d_start) >= smax) 262 return (char*)NULL; 263 switch (*(pz_d++) = *(pz_s++)) { 264 case NUL: 265 goto loopDone; 266 267 case '\'': 268 if ((size_t) (pz_d - pz_d_start) >= smax - sizeof( zQ )-1) 269 return (char*)NULL; 270 strcpy( pz_d-1, zQ ); 271 pz_d += sizeof( zQ )-2; 272 } 273 } loopDone:; 274 pz_d[-1] = '\''; 275 *pz_d = NUL; 276 277 return pz_d; 278 } 279 280 #endif 281 282 #if defined(__MINGW32__) 283 void 284 fix_path_separators (char* p) 285 { 286 while (p != NULL) 287 { 288 p = strchr (p, '\\'); 289 if (p != NULL) 290 { 291 *p = '/'; 292 ++p; 293 } 294 } 295 } 296 297 /* Count number of needle character ocurrences in str */ 298 static int 299 count_occurrences_of_char (char* str, char needle) 300 { 301 int cnt = 0; 302 303 while (str) 304 { 305 str = strchr (str, needle); 306 if (str) 307 { 308 ++str; 309 ++cnt; 310 } 311 } 312 313 return cnt; 314 } 315 316 /* On Mingw32, system function will just start cmd by default. 317 Call system function, but prepend ${CONFIG_SHELL} or ${SHELL} -c to the command, 318 replace newlines with '$'\n'', enclose command with double quotes 319 and escape special characters which were originally enclosed in single quotes. 320 */ 321 int 322 system_with_shell (char* s) 323 { 324 static const char z_shell_start_args[] = " -c \""; 325 static const char z_shell_end_args[] = "\""; 326 static const char z_shell_newline[] = "'$'\\n''"; 327 328 /* Use configured shell if present */ 329 char *env_shell = getenv ("CONFIG_SHELL"); 330 int newline_cnt = count_occurrences_of_char (s, '\n'); 331 int escapes_cnt = count_occurrences_of_char( s, '\\') 332 + count_occurrences_of_char (s, '"') 333 + count_occurrences_of_char (s, '`'); 334 char *long_cmd; 335 char *cmd_endp; 336 int sys_result; 337 char *s_scan; 338 int in_quotes; 339 340 if (env_shell == NULL) 341 env_shell = getenv ("SHELL"); 342 343 /* If neither CONFIGURED_SHELL nor SHELL is set, just call standard system function */ 344 if (env_shell == NULL) 345 return system (s); 346 347 /* Allocate enough memory to fit newly created command string */ 348 long_cmd = XNEWVEC (char, strlen (env_shell) 349 + strlen (z_shell_start_args) 350 + strlen (s) 351 + newline_cnt * (strlen (z_shell_newline) - 1) 352 + escapes_cnt 353 + strlen (z_shell_end_args) 354 + 1); 355 356 /* Start with ${SHELL} */ 357 strcpy (long_cmd, env_shell); 358 cmd_endp = long_cmd + strlen (long_cmd); 359 360 /* Opening quote */ 361 strcpy (cmd_endp, z_shell_start_args); 362 cmd_endp += strlen (z_shell_start_args); 363 364 /* Replace newlines and escape special chars */ 365 in_quotes = 0; 366 for (s_scan = s; *s_scan; ++s_scan) 367 { 368 switch (*s_scan) 369 { 370 case '\n': 371 if (in_quotes) 372 { 373 /* Replace newline inside quotes with '$'\n'' */ 374 strcpy (cmd_endp, z_shell_newline); 375 cmd_endp += strlen (z_shell_newline); 376 } 377 else 378 { 379 /* Replace newlines outside quotes with ; and merge subsequent newlines */ 380 *(cmd_endp++) = ';'; 381 *(cmd_endp++) = ' '; 382 while (*(s_scan + 1) == '\n' || *(s_scan + 1) == ' ' || *(s_scan + 1) == '\t') 383 ++s_scan; 384 } 385 break; 386 case '\'': 387 /* Escape single quote and toggle in_quotes flag */ 388 in_quotes = !in_quotes; 389 *(cmd_endp++) = *s_scan; 390 break; 391 case '\\': 392 case '`': 393 /* Escape backslash and backtick inside quotes */ 394 if (in_quotes) 395 *(cmd_endp++) = '\\'; 396 *(cmd_endp++) = *s_scan; 397 break; 398 case '"': 399 /* Escape double quotes always */ 400 *(cmd_endp++) = '\\'; 401 *(cmd_endp++) = *s_scan; 402 break; 403 default: 404 *(cmd_endp++) = *s_scan; 405 } 406 } 407 408 /* Closing quote */ 409 strcpy (cmd_endp, z_shell_end_args); 410 411 sys_result = system (long_cmd); 412 413 free (long_cmd); 414 415 return sys_result; 416 } 417 418 #endif /* defined(__MINGW32__) */ 419