Use C-coded tests and fixes for #endif/#else labels
authorBruce Korb <autogen@linuxbox.com>
Fri, 22 Oct 1999 13:23:43 +0000 (13:23 +0000)
committerBruce Korb <korbb@gcc.gnu.org>
Fri, 22 Oct 1999 13:23:43 +0000 (13:23 +0000)
From-SVN: r30130

gcc/ChangeLog
gcc/fixinc/README
gcc/fixinc/fixfixes.c
gcc/fixinc/fixincl.x
gcc/fixinc/fixtests.c
gcc/fixinc/inclhack.def
gcc/fixinc/inclhack.sh

index 8ee202335153e584e85edc48ca3c00e7d91e928f..6646c8c399a2ed00e761f8c3c3b0f2e043e9453a 100644 (file)
@@ -1,3 +1,13 @@
+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
index 85117f475502d79cf2dd1d0058811badb6667cc3..8fb70839342ed02f875adc0fb4abccd0aa1e339c 100644 (file)
@@ -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:
 
index 805e1db09d1de13b43ae398f24a7c203075de719..c1586e8cfb7ce45b6e9d2de1c196cd208629e092 100644 (file)
@@ -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);
index ce256a56e74ef561f3e97d7f0e82ee152127711a..c6c8460061848a92f3192746e8594240c8c69aac 100644 (file)
@@ -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,
index 07161ce7e05b534610be8a255768286aed9b488f..aac14924c0497076b25b1f59716b2f87a727dc68 100644 (file)
@@ -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 );
index 43847f8eb5d6b3eafed0ba3a4d3ef13854eb6e21..5802d1ea27226ce1638f28ec80921e9c037f0575 100644 (file)
@@ -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";
 };
 
 
index 00bde357032be2ea965eb11a06b8820b3e4e1613..7ad7648ff5ea32e7b28849106897503a08af55ae 100755 (executable)
@@ -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'
 
 
     #