+1999-10-22 Bruce Korb <autogen@linuxbox.com>
+
+ * 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
"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:
} 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 ) \
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
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);
#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 };
/* * * * * * * * * * * * * * * * * * * * * * * * * *
*
* List of all fixes
*/
-#define REGEX_COUNT 75
+#define REGEX_COUNT 74
#define MACH_LIST_SIZE_LIMIT 154
#define FIX_COUNT 107
{ 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,
} 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 ) \
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
{
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 );
/*
* 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";
};
#
# 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'
#