Retro68/gcc/fixincludes/fixlib.c
2017-10-07 02:16:47 +02:00

419 lines
10 KiB
C

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