Home | History | Annotate | Line # | Download | only in fixincludes
      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