From 8f9ca9127473a43ba75f03fbfc30c32e9984c982 Mon Sep 17 00:00:00 2001 From: Bruce Korb Date: Fri, 22 Oct 1999 13:23:43 +0000 Subject: Use C-coded tests and fixes for #endif/#else labels From-SVN: r30130 --- gcc/ChangeLog | 10 +++ gcc/fixinc/README | 5 +- gcc/fixinc/fixfixes.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++-- gcc/fixinc/fixincl.x | 25 ++----- gcc/fixinc/fixtests.c | 131 ++++++++++++++++++++++++++++++++- gcc/fixinc/inclhack.def | 43 +---------- gcc/fixinc/inclhack.sh | 19 +---- 7 files changed, 344 insertions(+), 81 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8ee2023..6646c8c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +1999-10-22 Bruce Korb + + * fixinc/README: document the "mach" machine matching test + * fixinc/fixfixes.c: Implement the #else/#endif label fix + * fixinc/fixtests.c: Implement the #else/#endif label test + * fixinc/inclhack.def: utilize these tests and fixes + * fixinc/inclhack.sh: regen + * fixinc/fixincl.x: regen + * fixinc/fixincl.sh: regen + Thu Oct 21 20:37:19 1999 Jeffrey A Law (law@cygnus.com) * Makefile.in (cse.o): Depend on hashtab.h, not splay-tree.h. Also diff --git a/gcc/fixinc/README b/gcc/fixinc/README index 85117f4..8fb7083 100644 --- a/gcc/fixinc/README +++ b/gcc/fixinc/README @@ -71,7 +71,10 @@ Here are the rules for making fixes in the inclhack.def file: "c_test" because they are performed internally. "test" sends a command to a server shell that actually fires off one or more processes to do the testing. Avoid it, if you can, but it is - still more efficient than a fix process. + still more efficient than a fix process. Also available is + "mach". If the target machine matches any of the named + globbing-style patterns, then the machine name test will pass. + It is desired, however, to limit the use of this test. These tests are required to: diff --git a/gcc/fixinc/fixfixes.c b/gcc/fixinc/fixfixes.c index 805e1db..c1586e8 100644 --- a/gcc/fixinc/fixfixes.c +++ b/gcc/fixinc/fixfixes.c @@ -72,7 +72,8 @@ typedef struct { } fix_entry_t; #define FIXUP_TABLE \ - _FT_( "no_double_slash", double_slash_fix ) + _FT_( "no_double_slash", double_slash_fix ) \ + _FT_( "else_endif_label", else_endif_label_fix ) #define FIX_PROC_HEAD( fix ) \ @@ -180,6 +181,184 @@ FIX_PROC_HEAD( double_slash_fix ) fclose (stdout);; } + +FIX_PROC_HEAD( else_endif_label_fix ) +{ + static const char label_pat[] = "^[ \t]*#[ \t]*(else|endif)"; + static regex_t label_re; + + char ch; + char* pz_next = (char*)NULL; + regmatch_t match[2]; + + re_set_syntax (RE_SYNTAX_EGREP); + (void)re_compile_pattern (label_pat, sizeof (label_pat)-1, + &label_re); + + for (;;) /* entire file */ + { + /* + See if we need to advance to the next candidate directive + If the scanning pointer passes over the end of the directive, + then the directive is inside a comment */ + if (pz_next < text) + { + if (regexec (&label_re, text, 2, match, 0) != 0) + { + fputs( text, stdout ); + break; + } + + pz_next = text + match[0].rm_eo; + } + + /* + IF the scan pointer has not reached the directive end, ... */ + if (pz_next > text) + { + /* + Advance the scanning pointer. If we are at the start + of a quoted string or a comment, then skip the entire unit */ + ch = *text; + + switch (ch) + { + case '/': + /* + Skip comments */ + if (text[1] == '*') + { + char* pz = strstr( text+2, "*/" ); + if (pz == (char*)NULL) + { + fputs( text, stdout ); + return; + } + pz += 2; + fwrite( text, 1, (pz - text), stdout ); + text = pz; + continue; + } + putc( ch, stdout ); + text++; + break; + + case '"': + case '\'': + text = print_quote( ch, text+1 ); + break; + + default: + putc( ch, stdout ); + text++; + } /* switch (ch) */ + continue; + } /* if (still shy of directive end) */ + + /* + The scanning pointer (text) has reached the end of the current + directive under test. Check for bogons here. */ + for (;;) /* bogon check */ + { + char ch = *(text++); + if (isspace (ch)) + { + putc( ch, stdout ); + if (ch == '\n') + { + /* + It is clean. No bogons on this directive */ + pz_next = (char*)NULL; /* force a new regex search */ + goto dont_fix_bogon; + } + continue; + } + + switch (ch) + { + case NUL: + return; + + case '\\': + /* + Skip escaped newlines. Otherwise, we have a bogon */ + if (*text != '\n') { + text--; + goto fix_the_bogon; + } + + /* + Emit the escaped newline and keep scanning for possible junk */ + putc( '\\', stdout ); + putc( '\n', stdout ); + text++; + break; + + case '/': + /* + Skip comments. Otherwise, we have a bogon */ + if (*text == '*') + { + text--; + pz_next = strstr( text+2, "*/" ); + if (pz_next == (char*)NULL) + { + putc( '\n', stdout ); + return; + } + pz_next += 2; + fwrite( text, 1, (pz_next - text), stdout ); + text = pz_next; + break; + } + + /* + FIXME: if this is a C++ file, then a double slash comment + is allowed to follow the directive. */ + + /* FALLTHROUGH */ + + default: + /* + GOTTA BE A BOGON */ + text--; + goto fix_the_bogon; + } /* switch (ch) */ + } /* for (bogon check loop) */ + + fix_the_bogon: + /* + `text' points to the start of the bogus data */ + for (;;) + { + /* + NOT an escaped newline. Find the end of line that + is not preceeded by an escape character: */ + pz_next = strchr( text, '\n' ); + if (pz_next == (char*)NULL) + { + putc( '\n', stdout ); + return; + } + + if (pz_next[-1] != '\\') + { + text = pz_next; + pz_next = (char*)NULL; /* force a new regex search */ + break; + } + + /* + The newline was escaped. We gotta keep going. */ + text = pz_next + 1; + } + + dont_fix_bogon:; + } /* for (entire file) loop */ + + return; +} + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test for fix selector @@ -206,11 +385,12 @@ apply_fix( fixname, filname ) if (strcmp (pfe->fix_name, fixname) == 0) break; if (--ct <= 0) - { - fprintf (stderr, "fixincludes error: the `%s' fix is unknown\n", - fixname ); - exit (3); - } + { + fprintf (stderr, "fixincludes error: the `%s' fix is unknown\n", + fixname ); + exit (3); + } + pfe++; } buf = load_file_data (stdin); diff --git a/gcc/fixinc/fixincl.x b/gcc/fixinc/fixincl.x index ce256a5..c6c8460 100644 --- a/gcc/fixinc/fixincl.x +++ b/gcc/fixinc/fixincl.x @@ -994,30 +994,19 @@ tSCC zEnd_Else_LabelName[] = #define apzEnd_Else_LabelMachs (const char**)NULL /* - * content selection pattern - do fix if pattern found + * perform the C function call test */ -tSCC zEnd_Else_LabelSelect0[] = - "^[ \t]*#[ \t]*(else|endif)[ \t]+([!-.0-z\\{\\|\\}\\~]|/[^\\*])"; +tSCC zEnd_Else_LabelFTst0[] = "else_endif_label"; #define END_ELSE_LABEL_TEST_CT 1 -#define END_ELSE_LABEL_RE_CT 1 +#define END_ELSE_LABEL_RE_CT 0 tTestDesc aEnd_Else_LabelTests[] = { - { TT_EGREP, zEnd_Else_LabelSelect0, (regex_t*)NULL }, }; + { TT_FUNCTION, zEnd_Else_LabelFTst0, 0 /* unused */ }, }; /* * Fix Command Arguments for End_Else_Label */ -const char* apzEnd_Else_LabelPatch[] = { "sed", - "-e", ":loop\n\ -/\\\\$/N\n\ -s/\\\\$/\\\\+++fixinc_eol+++/\n\ -/\\\\$/b loop\n\ -s/\\\\+++fixinc_eol+++/\\\\/g\n\ -s%^\\([ \t]*#[ \t]*else\\)[ \t][ \t]*/[^*].*%\\1%\n\ -s%^\\([ \t]*#[ \t]*else\\)[ \t][ \t]*[^/ \t].*%\\1%\n\ -s%^\\([ \t]*#[ \t]*endif\\)[ \t][ \t]*/[^*].*%\\1%\n\ -s%^\\([ \t]*#[ \t]*endif\\)[ \t][ \t]*\\*[^/].*%\\1%\n\ -s%^\\([ \t]*#[ \t]*endif\\)[ \t][ \t]*[^/* \t].*%\\1%", +const char* apzEnd_Else_LabelPatch[] = {"else_endif_label", (char*)NULL }; /* * * * * * * * * * * * * * * * * * * * * * * * * * @@ -4042,7 +4031,7 @@ extern char *\tsprintf();\\\n\ * * List of all fixes */ -#define REGEX_COUNT 75 +#define REGEX_COUNT 74 #define MACH_LIST_SIZE_LIMIT 154 #define FIX_COUNT 107 @@ -4179,7 +4168,7 @@ tFixDesc fixDescList[ FIX_COUNT ] = { { zEnd_Else_LabelName, zEnd_Else_LabelList, apzEnd_Else_LabelMachs, (regex_t*)NULL, - END_ELSE_LABEL_TEST_CT, FD_MACH_ONLY, + END_ELSE_LABEL_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE, aEnd_Else_LabelTests, apzEnd_Else_LabelPatch }, { zHp_InlineName, zHp_InlineList, diff --git a/gcc/fixinc/fixtests.c b/gcc/fixinc/fixtests.c index 07161ce..aac1492 100644 --- a/gcc/fixinc/fixtests.c +++ b/gcc/fixinc/fixtests.c @@ -62,7 +62,8 @@ typedef struct { } test_entry_t; #define FIX_TEST_TABLE \ - _FT_( "double_slash", double_slash_test ) + _FT_( "double_slash", double_slash_test ) \ + _FT_( "else_endif_label", else_endif_label_test ) #define TEST_FOR_FIX_PROC_HEAD( test ) \ @@ -154,6 +155,133 @@ TEST_FOR_FIX_PROC_HEAD( double_slash_test ) return SKIP_FIX; } + +TEST_FOR_FIX_PROC_HEAD( else_endif_label_test ) +{ + static int compiled = 0; + static const char label_pat[] = "^[ \t]*#[ \t]*(else|endif)"; + static regex_t label_re; + + char ch; + const char* pz_next = (char*)NULL; + regmatch_t match[2]; + + /* + This routine may be run many times within a single execution. + Do the compile once only in that case. In the standalone case, + we waste 10 bytes of memory and a test, branch and increment delay. */ + if (! compiled) + { + compiled++; + re_set_syntax (RE_SYNTAX_EGREP); + (void)re_compile_pattern (label_pat, sizeof (label_pat)-1, + &label_re); + } + + for (;;) /* entire file */ + { + /* + See if we need to advance to the next candidate directive + If the scanning pointer passes over the end of the directive, + then the directive is inside a comment */ + if (pz_next < text) + { + if (regexec (&label_re, text, 2, match, 0) != 0) + break; + pz_next = text + match[0].rm_eo; + } + + /* + IF the scan pointer has not reached the directive end, ... */ + if (pz_next > text) + { + /* + Advance the scanning pointer. If we are at the start + of a quoted string or a comment, then skip the entire unit */ + ch = *(text++); + + switch (ch) + { + case '/': + /* + Skip comments */ + if (*text == '*') + { + text = strstr( text+1, "*/" ); + if (text == (char*)NULL) + return SKIP_FIX; + text += 2; + continue; + } + break; + + case '"': + case '\'': + text = skip_quote( ch, text ); + break; + } /* switch (ch) */ + continue; + } /* if (still shy of directive end) */ + + /* + The scanning pointer (text) has reached the end of the current + directive under test, then check for bogons here */ + for (;;) /* bogon check */ + { + char ch = *(pz_next++); + if (isspace (ch)) + { + if (ch == '\n') + { + /* + It is clean. No bogons on this directive */ + text = pz_next; + pz_next = (char*)NULL; /* force a new regex search */ + break; + } + continue; + } + + switch (ch) + { + case '\\': + /* + Skip escaped newlines. Otherwise, we have a bogon */ + if (*pz_next != '\n') + return APPLY_FIX; + + pz_next++; + break; + + case '/': + /* + Skip comments. Otherwise, we have a bogon */ + if (*pz_next == '*') + { + pz_next = strstr( pz_next+1, "*/" ); + if (pz_next == (char*)NULL) + return SKIP_FIX; + pz_next += 2; + break; + } + + /* + FIXME: if this is a C++ file, then a double slash comment + is allowed to follow the directive. */ + + /* FALLTHROUGH */ + + default: + /* + GOTTA BE A BOGON */ + return APPLY_FIX; + } /* switch (ch) */ + } /* for (bogon check loop) */ + } /* for (entire file) loop */ + + return SKIP_FIX; +} + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = test for fix selector @@ -179,6 +307,7 @@ run_test( tname, fname, text ) { if (strcmp( pte->test_name, tname ) == 0) return (*pte->test_proc)( fname, text ); + pte++; } while (--ct > 0); fprintf( stderr, "fixincludes error: the `%s' fix test is unknown\n", tname ); diff --git a/gcc/fixinc/inclhack.def b/gcc/fixinc/inclhack.def index 43847f8..5802d1e 100644 --- a/gcc/fixinc/inclhack.def +++ b/gcc/fixinc/inclhack.def @@ -527,47 +527,10 @@ fix = { /* * Select files that contain '#endif' or '#else' directives with - * some sort of following junk. (Between the ascii '.' - * and '0' lies the character '/'. This will *NOT* - * match '#endif / * foo * /', but it also wont match - * '#endif / done' either. - * - * We have a second regexp in the selector to detect - * #endif followed by a / followed by anything other - * than a *. For example "#endif / * foo * /" or - * "#endif /% blah %/ which appear on OSF4.0A and AIX4.2 - * repsectively. - * - * We use the pattern [!-.0-z{|}~] instead of [^/ \t] to match a - * noncomment following #else or #endif because some buggy egreps - * think [^/] matches newline, and they thus think `#else ' matches - * `#e[ndiflse]*[ \t]+[^/ \t]'. - * [!-.0-~] does not work properly on AIX 4.1. - */ - select = "^[ \t]*#[ \t]*(else|endif)[ \t]+" - "(" '[!-.0-z\{\|\}\~]' "|" '/[^\*]' ")"; - - /* - * First, join the continued input lines. - * IF the resulting line is an endif preprocessing directive, - * then trim off the following patterns: - * 1. sequences that start with '/' and is *NOT* followed by '*' - * 2. Sequences that start with '*' and is *NOT* followed by '/' - * 3. sequences that do not start with any of '/', '*', '\t' or ' '. - * - * The fixinc_eol stuff is to work around a bug in the sed + * some sort of following junk. */ - sed = ":loop\n" - '/\\\\$/' "N\n" - 's/\\\\$/\\\\+++fixinc_eol+++/' "\n" - '/\\\\$/' "b loop\n" - 's/\\\\+++fixinc_eol+++/\\\\/g' "\n" - - "s%^\\([ \t]*#[ \t]*else\\)[ \t][ \t]*/[^*].*%\\1%\n" - "s%^\\([ \t]*#[ \t]*else\\)[ \t][ \t]*[^/ \t].*%\\1%\n" - "s%^\\([ \t]*#[ \t]*endif\\)[ \t][ \t]*/[^*].*%\\1%\n" - "s%^\\([ \t]*#[ \t]*endif\\)[ \t][ \t]*\\*[^/].*%\\1%\n" - "s%^\\([ \t]*#[ \t]*endif\\)[ \t][ \t]*[^/* \t].*%\\1%"; + c_test = "else_endif_label"; + c_fix = "else_endif_label"; }; diff --git a/gcc/fixinc/inclhack.sh b/gcc/fixinc/inclhack.sh index 00bde35..7ad7648 100755 --- a/gcc/fixinc/inclhack.sh +++ b/gcc/fixinc/inclhack.sh @@ -979,28 +979,17 @@ extern "C"\ # # Fix 27: End_Else_Label # - if ( test -n "`egrep '^[ ]*#[ ]*(else|endif)[ ]+([!-.0-z\\{\\|\\}\\~]|/[^\\*])' ${file}`" - ) > /dev/null 2>&1 ; then + if ${FIXTESTS} ${file} else_endif_label + then fixlist="${fixlist} end_else_label" if [ ! -r ${DESTFILE} ] then infile=${file} else infile=${DESTFILE} ; fi - - sed -e ':loop -/\\$/N -s/\\$/\\+++fixinc_eol+++/ -/\\$/b loop -s/\\+++fixinc_eol+++/\\/g -s%^\([ ]*#[ ]*else\)[ ][ ]*/[^*].*%\1% -s%^\([ ]*#[ ]*else\)[ ][ ]*[^/ ].*%\1% -s%^\([ ]*#[ ]*endif\)[ ][ ]*/[^*].*%\1% -s%^\([ ]*#[ ]*endif\)[ ][ ]*\*[^/].*%\1% -s%^\([ ]*#[ ]*endif\)[ ][ ]*[^/* ].*%\1%' \ - < $infile > ${DESTDIR}/fixinc.tmp + ${FIXFIXES} ${file} else_endif_label < $infile > ${DESTDIR}/fixinc.tmp rm -f ${DESTFILE} mv -f ${DESTDIR}/fixinc.tmp ${DESTFILE} - fi # end of select 'if' + fi # end of c_test 'if' # -- cgit v1.1