emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/lib-src/etags.c


From: Francesco Potortì
Subject: [Emacs-diffs] Changes to emacs/lib-src/etags.c
Date: Thu, 13 Jun 2002 06:44:17 -0400

Index: emacs/lib-src/etags.c
diff -c emacs/lib-src/etags.c:3.21 emacs/lib-src/etags.c:3.22
*** emacs/lib-src/etags.c:3.21  Thu Jun  6 18:37:28 2002
--- emacs/lib-src/etags.c       Thu Jun 13 06:44:15 2002
***************
*** 2,22 ****
     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002
     Free Software Foundation, Inc. and Ken Arnold
  
! This file is not considered part of GNU Emacs.
  
! This program 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 2 of the License, or
! (at your option) any later version.
! 
! This program 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 this program; if not, write to the Free Software Foundation,
! Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  
  /*
   * Authors:
--- 2,22 ----
     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002
     Free Software Foundation, Inc. and Ken Arnold
  
!  This file is not considered part of GNU Emacs.
  
!  This program 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 2 of the License, or
!  (at your option) any later version.
! 
!  This program 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 this program; if not, write to the Free Software Foundation,
!  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  
  /*
   * Authors:
***************
*** 34,40 ****
   *    Francesco Potortì <address@hidden> has maintained it since 1993.
   */
  
! char pot_etags_version[] = "@(#) pot revision number is 16.10";
  
  #define       TRUE    1
  #define       FALSE   0
--- 34,40 ----
   *    Francesco Potortì <address@hidden> has maintained it since 1993.
   */
  
! char pot_etags_version[] = "@(#) pot revision number is 16.19";
  
  #define       TRUE    1
  #define       FALSE   0
***************
*** 288,294 ****
    enum {
      at_language,              /* a language specification */
      at_regexp,                        /* a regular expression */
-     at_icregexp,              /* same, but with case ignored */
      at_filename,              /* a file name */
      at_stdin                  /* read from stdin here */
    } arg_type;                 /* argument type */
--- 288,293 ----
***************
*** 308,313 ****
--- 307,313 ----
    char *name_pattern;
    bool error_signaled;
    bool ignore_case;
+   bool multi_line;
  } pattern;
  #endif /* ETAGS_REGEXPS */
  
***************
*** 355,363 ****
  static char *get_tag __P((char *));
  
  #ifdef ETAGS_REGEXPS
! static void analyse_regex __P((char *, bool));
! static void add_regex __P((char *, bool, language *));
  static void free_patterns __P((void));
  #endif /* ETAGS_REGEXPS */
  static void error __P((const char *, const char *));
  static void suggest_asking_for_help __P((void));
--- 355,363 ----
  static char *get_tag __P((char *));
  
  #ifdef ETAGS_REGEXPS
! static void analyse_regex __P((char *));
  static void free_patterns __P((void));
+ static void regex_tag_multiline __P((void));
  #endif /* ETAGS_REGEXPS */
  static void error __P((const char *, const char *));
  static void suggest_asking_for_help __P((void));
***************
*** 417,422 ****
--- 417,423 ----
  static node *last_node;               /* the last node created */
  
  static linebuffer lb;         /* the current line */
+ static linebuffer filebuf;    /* a buffer containing the whole file */
  
  /* boolean "functions" (see init)     */
  static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
***************
*** 457,469 ****
  static bool parsing_stdin;    /* --parse-stdin used */
  
  #ifdef ETAGS_REGEXPS
! /* List of all regexps. */
! static pattern *p_head;
! 
! /* How many characters in the character set.  (From regex.c.)  */
! #define CHAR_SET_SIZE 256
! /* Translation table for case-insensitive matching. */
! static char lc_trans[CHAR_SET_SIZE];
  #endif /* ETAGS_REGEXPS */
  
  #ifdef LONG_OPTIONS
--- 458,467 ----
  static bool parsing_stdin;    /* --parse-stdin used */
  
  #ifdef ETAGS_REGEXPS
! static pattern *p_head;               /* list of all regexps */
! static bool need_filebuf;     /* some regexes are multi-line */
! #else
! # define need_filebuf FALSE
  #endif /* ETAGS_REGEXPS */
  
  #ifdef LONG_OPTIONS
***************
*** 680,689 ****
  }
  
  #ifndef EMACS_NAME
! # define EMACS_NAME "GNU Emacs"
  #endif
  #ifndef VERSION
! # define VERSION "21"
  #endif
  static void
  print_version ()
--- 678,687 ----
  }
  
  #ifndef EMACS_NAME
! # define EMACS_NAME "standalone"
  #endif
  #ifndef VERSION
! # define VERSION "version"
  #endif
  static void
  print_version ()
***************
*** 775,783 ****
        REGEXP is anchored (as if preceded by ^).\n\
        The form /REGEXP/NAME/ creates a named tag.\n\
        For example Tcl named tags can be created with:\n\
!       --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\"");
!   puts ("-c /REGEXP/, --ignore-case-regex=/REGEXP/ or address@hidden
!         Like -r, --regex but ignore case when matching expressions.");
    puts ("-R, --no-regex\n\
          Don't create tags from regexps for the following files.");
  #endif /* ETAGS_REGEXPS */
--- 773,783 ----
        REGEXP is anchored (as if preceded by ^).\n\
        The form /REGEXP/NAME/ creates a named tag.\n\
        For example Tcl named tags can be created with:\n\
!       --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\".");
!   puts ("In the form /REGEXP/MODS or /REGEXP/NAME/MODS, MODS are\n\
!       one-letter modifiers: `i' means to ignore case, `m' means\n\
!       allow multi-line matches, `s' implies `m' and additionally\n\
!       causes dot to match the newline character.");
    puts ("-R, --no-regex\n\
          Don't create tags from regexps for the following files.");
  #endif /* ETAGS_REGEXPS */
***************
*** 996,1009 ****
       is small. */
    argbuffer = xnew (argc, argument);
  
- #ifdef ETAGS_REGEXPS
-   /* Set syntax for regular expression routines. */
-   re_set_syntax (RE_SYNTAX_EMACS | RE_INTERVALS);
-   /* Translation table for case-insensitive search. */
-   for (i = 0; i < CHAR_SET_SIZE; i++)
-     lc_trans[i] = lowcase (i);
- #endif /* ETAGS_REGEXPS */
- 
    /*
     * If etags, always find typedefs and structure tags.  Why not?
     * Also default to find macro constants, enum constants and
--- 996,1001 ----
***************
*** 1079,1084 ****
--- 1071,1080 ----
            }
        }
        break;
+       case 'c':
+       /* Backward compatibility: support obsolete --ignore-case-regexp. */
+       optarg = concat (optarg, "i", ""); /* memory leak here */
+       /* FALLTHRU */
        case 'r':
        argbuffer[current_arg].arg_type = at_regexp;
        argbuffer[current_arg].what = optarg;
***************
*** 1089,1099 ****
        argbuffer[current_arg].what = NULL;
        ++current_arg;
        break;
-       case 'c':
-       argbuffer[current_arg].arg_type = at_icregexp;
-       argbuffer[current_arg].what = optarg;
-       ++current_arg;
-       break;
        case 'V':
        print_version ();
        break;
--- 1085,1090 ----
***************
*** 1152,1157 ****
--- 1143,1149 ----
  
    initbuffer (&lb);
    initbuffer (&filename_lb);
+   initbuffer (&filebuf);
  
    if (!CTAGS)
      {
***************
*** 1186,1195 ****
          break;
  #ifdef ETAGS_REGEXPS
        case at_regexp:
!         analyse_regex (argbuffer[i].what, FALSE);
!         break;
!       case at_icregexp:
!         analyse_regex (argbuffer[i].what, TRUE);
          break;
  #endif
        case at_filename:
--- 1178,1184 ----
          break;
  #ifdef ETAGS_REGEXPS
        case at_regexp:
!         analyse_regex (argbuffer[i].what);
          break;
  #endif
        case at_filename:
***************
*** 1234,1239 ****
--- 1223,1229 ----
  #ifdef ETAGS_REGEXPS
    free_patterns ();
  #endif /* ETAGS_REGEXPS */
+   free (filebuf.buffer);
  
    if (!CTAGS || cxref_style)
      {
***************
*** 1648,1654 ****
       FILE *inf;
  {
    char *cp;
-   node *old_last_node;
    language *lang = curfdp->lang;
    Lang_function *parser = NULL;
  
--- 1638,1643 ----
***************
*** 1703,1709 ****
    /* We rewind here, even if inf may be a pipe.  We fail if the
       length of the first line is longer than the pipe block size,
       which is unlikely. */
!     rewind (inf);
  
    /* Else try to guess the language given the case insensitive file name. */
    if (parser == NULL)
--- 1692,1698 ----
    /* We rewind here, even if inf may be a pipe.  We fail if the
       length of the first line is longer than the pipe block size,
       which is unlikely. */
!   rewind (inf);
  
    /* Else try to guess the language given the case insensitive file name. */
    if (parser == NULL)
***************
*** 1716,1721 ****
--- 1705,1730 ----
        }
      }
  
+   /* Else try Fortran or C. */
+   if (parser == NULL)
+     {
+       node *old_last_node = last_node;
+ 
+       curfdp->lang = get_language_from_langname ("fortran");
+       find_entries (inf);
+ 
+       if (old_last_node == last_node)
+       /* No Fortran entries found.  Try C. */
+       {
+         /* We do not tag if rewind fails.
+            Only the file name will be recorded in the tags file. */
+         rewind (inf);
+         curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
+         find_entries (inf);
+       }
+       return;
+     }
+ 
    if (!no_line_directive
        && curfdp->lang != NULL && curfdp->lang->metasource)
      /* It may be that this is a bingo.y file, and we already parsed a bingo.c
***************
*** 1748,1779 ****
          fdpp = &(*fdpp)->next; /* advance the list pointer */
      }
  
!   if (parser != NULL)
!     {
!       /* Generic initialisations before reading from file. */
!       lineno = 0;             /* reset global line number */
!       charno = 0;             /* reset global char number */
!       linecharno = 0;         /* reset global char number of line start */
  
!       parser (inf);
!       return;
!     }
  
!   /* Else try Fortran. */
!   old_last_node = last_node;
!   curfdp->lang = get_language_from_langname ("fortran");
!   find_entries (inf);
! 
!   if (old_last_node == last_node)
!     /* No Fortran entries found.  Try C. */
!     {
!       /* We do not tag if rewind fails.
!        Only the file name will be recorded in the tags file. */
!       rewind (inf);
!       curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
!       find_entries (inf);
!     }
!   return;
  }
  
  
--- 1757,1777 ----
          fdpp = &(*fdpp)->next; /* advance the list pointer */
      }
  
!   assert (parser != NULL);
  
!   /* Generic initialisations before reading from file. */
!   filebuf.len = 0;            /* reset the file buffer */
  
!   /* Generic initialisations before parsing file with readline. */
!   lineno = 0;                /* reset global line number */
!   charno = 0;                /* reset global char number */
!   linecharno = 0;            /* reset global char number of line start */
! 
!   parser (inf);
! 
! #ifdef ETAGS_REGEXPS
!   regex_tag_multiline ();
! #endif /* ETAGS_REGEXPS */
  }
  
  
***************
*** 2014,2019 ****
--- 2012,2022 ----
   * invalidate_nodes ()
   *    Scan the node tree and invalidate all nodes pointing to the
   *    given file description (CTAGS case) or free them (ETAGS case).
+  *
+  * This function most likely contains a bug, but I cannot tell where.
+  * I have a case of a binary that crashes inside this function with a bus
+  * error.  Unfortunately, the binary does not contain debug information, and
+  * compiling with debugging information makes the bug disappear.
   */
  static void
  invalidate_nodes (badfdp, npp)
***************
*** 2030,2036 ****
        if (np->left != NULL)
        invalidate_nodes (badfdp, &np->left);
        if (np->fdp == badfdp)
!       np-> valid = FALSE;
        if (np->right != NULL)
        invalidate_nodes (badfdp, &np->right);
      }
--- 2033,2039 ----
        if (np->left != NULL)
        invalidate_nodes (badfdp, &np->left);
        if (np->fdp == badfdp)
!       np->valid = FALSE;
        if (np->right != NULL)
        invalidate_nodes (badfdp, &np->right);
      }
***************
*** 5263,5279 ****
  #ifdef ETAGS_REGEXPS
  
  static char *scan_separators __P((char *));
! static void analyse_regex __P((char *, bool));
! static void add_regex __P((char *, bool, language *));
  static char *substitute __P((char *, char *, struct re_registers *));
  
! /* Take a string like "/blah/" and turn it into "blah", making sure
!    that the first and last characters are the same, and handling
!    quoted separator characters.  Actually, stops on the occurrence of
!    an unquoted separator.  Also turns "\t" into a Tab character, and
!    similarly for all character escape sequences supported by Gcc.
!    Returns pointer to terminating separator.  Works in place.  Null
!    terminates name string. */
  static char *
  scan_separators (name)
       char *name;
--- 5266,5283 ----
  #ifdef ETAGS_REGEXPS
  
  static char *scan_separators __P((char *));
! static void add_regex __P((char *, language *));
  static char *substitute __P((char *, char *, struct re_registers *));
  
! /*
!  * Take a string like "/blah/" and turn it into "blah", verifying
!  * that the first and last characters are the same, and handling
!  * quoted separator characters.  Actually, stops on the occurrence of
!  * an unquoted separator.  Also process \t, \n, etc. and turn into
!  * appropriate characters. Works in place.  Null terminates name string.
!  * Returns pointer to terminating separator, or NULL for
!  * unterminated regexps.
!  */
  static char *
  scan_separators (name)
       char *name;
***************
*** 5288,5302 ****
        {
          switch (*name)
            {
!           case 'a': *copyto++ = '\007'; break;
!           case 'b': *copyto++ = '\b'; break;
!           case 'd': *copyto++ = 0177; break;
!           case 'e': *copyto++ = 033; break;
!           case 'f': *copyto++ = '\f'; break;
!           case 'n': *copyto++ = '\n'; break;
!           case 'r': *copyto++ = '\r'; break;
!           case 't': *copyto++ = '\t'; break;
!           case 'v': *copyto++ = '\v'; break;
            default:
              if (*name == sep)
                *copyto++ = sep;
--- 5292,5306 ----
        {
          switch (*name)
            {
!           case 'a': *copyto++ = '\007'; break; /* BEL (bell)           */
!           case 'b': *copyto++ = '\b'; break;   /* BS (back space)      */
!           case 'd': *copyto++ = 0177; break;   /* DEL (delete)         */
!           case 'e': *copyto++ = 033; break;    /* ESC (delete)         */
!           case 'f': *copyto++ = '\f'; break;   /* FF (form feed)       */
!           case 'n': *copyto++ = '\n'; break;   /* NL (new line)        */
!           case 'r': *copyto++ = '\r'; break;   /* CR (carriage return) */
!           case 't': *copyto++ = '\t'; break;   /* TAB (horizontal tab) */
!           case 'v': *copyto++ = '\v'; break;   /* VT (vertical tab)    */
            default:
              if (*name == sep)
                *copyto++ = sep;
***************
*** 5317,5322 ****
--- 5321,5328 ----
        else
        *copyto++ = *name;
      }
+   if (*name != sep)
+     name = NULL;              /* signal unterminated regexp */
  
    /* Terminate copied string. */
    *copyto = '\0';
***************
*** 5326,5334 ****
  /* Look at the argument of --regex or --no-regex and do the right
     thing.  Same for each line of a regexp file. */
  static void
! analyse_regex (regex_arg, ignore_case)
       char *regex_arg;
-      bool ignore_case;
  {
    if (regex_arg == NULL)
      {
--- 5332,5339 ----
  /* Look at the argument of --regex or --no-regex and do the right
     thing.  Same for each line of a regexp file. */
  static void
! analyse_regex (regex_arg)
       char *regex_arg;
  {
    if (regex_arg == NULL)
      {
***************
*** 5362,5368 ****
          }
        initbuffer (&regexbuf);
        while (readline_internal (&regexbuf, regexfp) > 0)
!         analyse_regex (regexbuf.buffer, ignore_case);
        free (regexbuf.buffer);
        fclose (regexfp);
        }
--- 5367,5373 ----
          }
        initbuffer (&regexbuf);
        while (readline_internal (&regexbuf, regexfp) > 0)
!         analyse_regex (regexbuf.buffer);
        free (regexbuf.buffer);
        fclose (regexfp);
        }
***************
*** 5381,5397 ****
              error ("unterminated language name in regex: %s", regex_arg);
              return;
            }
!       *cp = '\0';
        lang = get_language_from_langname (lang_name);
        if (lang == NULL)
          return;
!       add_regex (cp + 1, ignore_case, lang);
        }
        break;
  
        /* Regexp to be used for any language. */
      default:
!       add_regex (regex_arg, ignore_case, NULL);
        break;
      }
  }
--- 5386,5402 ----
              error ("unterminated language name in regex: %s", regex_arg);
              return;
            }
!       *cp++ = '\0';
        lang = get_language_from_langname (lang_name);
        if (lang == NULL)
          return;
!       add_regex (cp, lang);
        }
        break;
  
        /* Regexp to be used for any language. */
      default:
!       add_regex (regex_arg, NULL);
        break;
      }
  }
***************
*** 5399,5435 ****
  /* Turn a name, which is an ed-style (but Emacs syntax) regular
     expression, into a real regular expression by compiling it. */
  static void
! add_regex (regexp_pattern, ignore_case, lang)
       char *regexp_pattern;
-      bool ignore_case;
       language *lang;
  {
    static struct re_pattern_buffer zeropattern;
!   char *name;
    const char *err;
    struct re_pattern_buffer *patbuf;
    pattern *pp;
  
  
!   if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
      {
!       error ("%s: unterminated regexp", regexp_pattern);
        return;
      }
    name = scan_separators (regexp_pattern);
!   if (regexp_pattern[0] == '\0')
      {
!       error ("null regexp", (char *)NULL);
        return;
      }
!   (void) scan_separators (name);
  
    patbuf = xnew (1, struct re_pattern_buffer);
    *patbuf = zeropattern;
    if (ignore_case)
!     patbuf->translate = lc_trans;     /* translation table to fold case  */
  
!   err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
    if (err != NULL)
      {
        error ("%s while compiling pattern", err);
--- 5404,5494 ----
  /* Turn a name, which is an ed-style (but Emacs syntax) regular
     expression, into a real regular expression by compiling it. */
  static void
! add_regex (regexp_pattern, lang)
       char *regexp_pattern;
       language *lang;
  {
    static struct re_pattern_buffer zeropattern;
!   char sep, *pat, *name, *modifiers;
    const char *err;
    struct re_pattern_buffer *patbuf;
    pattern *pp;
+   bool ignore_case, multi_line, single_line;
  
  
!   if (strlen(regexp_pattern) < 3)
      {
!       error ("null regexp", (char *)NULL);
        return;
      }
+   sep = regexp_pattern[0];
    name = scan_separators (regexp_pattern);
!   if (name == NULL)
      {
!       error ("%s: unterminated regexp", regexp_pattern);
!       return;
!     }
!   if (name[1] == sep)
!     {
!       error ("null name for regexp \"%s\"", regexp_pattern);
        return;
      }
!   modifiers = scan_separators (name);
!   if (modifiers == NULL)      /* no terminating separator --> no name */
!     {
!       modifiers = name;
!       name = "";
!     }
!   else
!     modifiers += 1;           /* skip separator */
! 
!   /* Parse regex modifiers. */
!   ignore_case = FALSE;                /* case is significant */
!   multi_line = FALSE;         /* matches are done one line at a time */
!   single_line = FALSE;                /* dot does not match newline */
!   for (; modifiers[0] != '\0'; modifiers++)
!     switch (modifiers[0])
!       {
!       case 'i':
!       ignore_case = TRUE;
!       break;
!       case 's':
!       single_line = TRUE;
!       /* FALLTHRU */
!       case 'm':
!       multi_line = TRUE;
!       need_filebuf = TRUE;
!       break;
!       default:
!       modifiers[1] = '\0';
!       error ("invalid regexp modifier `%s'", modifiers);
!       return;
!       }
  
    patbuf = xnew (1, struct re_pattern_buffer);
    *patbuf = zeropattern;
    if (ignore_case)
!     {
!       static char lc_trans[CHARS];
!       int i;
!       for (i = 0; i < CHARS; i++)
!       lc_trans[i] = lowcase (i);
!       patbuf->translate = lc_trans;   /* translation table to fold case  */
!     }
! 
!   if (multi_line)
!     pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
!   else
!     pat = regexp_pattern;
  
!   if (single_line)
!     re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
!   else
!     re_set_syntax (RE_SYNTAX_EMACS);
! 
!   err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
!   if (multi_line)
!     free (pat);
    if (err != NULL)
      {
        error ("%s while compiling pattern", err);
***************
*** 5445,5450 ****
--- 5504,5510 ----
    p_head->name_pattern = savestr (name);
    p_head->error_signaled = FALSE;
    p_head->ignore_case = ignore_case;
+   p_head->multi_line = multi_line;
  }
  
  /*
***************
*** 5512,5517 ****
--- 5572,5663 ----
      }
    return;
  }
+ 
+ /*
+  * Reads the whole file as a single string from `filebuf' and looks for
+  * multi-line regular expressions, creating tags on matches.
+  * readline already dealt with normal regexps.
+  *
+  * Idea by Ben Wing <address@hidden> (2002).
+  */
+ static void
+ regex_tag_multiline ()
+ {
+   char *buffer = filebuf.buffer;
+   pattern *pp;
+ 
+   for (pp = p_head; pp != NULL; pp = pp->p_next)
+     {
+       int match = 0;
+ 
+       if (!pp->multi_line)
+       continue;               /* skip normal regexps */
+ 
+       /* Generic initialisations before parsing file from memory. */
+       lineno = 1;             /* reset global line number */
+       charno = 0;             /* reset global char number */
+       linecharno = 0;         /* reset global char number of line start */
+ 
+       /* Only use generic regexps or those for the current language. */
+       if (pp->lang != NULL && pp->lang != curfdp->lang)
+       continue;
+ 
+       while (match >= 0 && match < filebuf.len)
+       {
+         match = re_search (pp->pat, buffer, filebuf.len, charno,
+                            filebuf.len - match, &pp->regs);
+         switch (match)
+           {
+           case -2:
+             /* Some error. */
+             if (!pp->error_signaled)
+               {
+                 error ("regexp stack overflow while matching \"%s\"",
+                        pp->regex);
+                 pp->error_signaled = TRUE;
+               }
+             break;
+           case -1:
+             /* No match. */
+             break;
+           default:
+             if (match == pp->regs.end[0])
+               {
+                 if (!pp->error_signaled)
+                   {
+                     error ("regexp matches the empty string: \"%s\"",
+                            pp->regex);
+                     pp->error_signaled = TRUE;
+                   }
+                 match = -3;   /* exit from while loop */
+                 break;
+               }
+ 
+             /* Match occurred.  Construct a tag. */
+             while (charno < pp->regs.end[0])
+               if (buffer[charno++] == '\n')
+                 lineno++, linecharno = charno;
+             if (pp->name_pattern[0] != '\0')
+               {
+                 /* Make a named tag. */
+                 char *name = substitute (buffer,
+                                          pp->name_pattern, &pp->regs);
+                 if (name != NULL)
+                   pfnote (name, TRUE, buffer + linecharno,
+                           charno - linecharno + 1, lineno, linecharno);
+               }
+             else
+               {
+                 /* Make an unnamed tag. */
+                 pfnote ((char *)NULL, TRUE, buffer + linecharno,
+                         charno - linecharno + 1, lineno, linecharno);
+               }
+             break;
+           }
+       }
+     }
+ }
+ 
  #endif /* ETAGS_REGEXPS */
  
  
***************
*** 5564,5573 ****
   * newline or CR-NL, if any.  Return the number of characters read from
   * `stream', which is the length of the line including the newline.
   *
!  * On DOS or Windows we do not count the CR character, if any, before the
!  * NL, in the returned length; this mirrors the behavior of emacs on those
   * platforms (for text files, it translates CR-NL to NL as it reads in the
   * file).
   */
  static long
  readline_internal (lbp, stream)
--- 5710,5722 ----
   * newline or CR-NL, if any.  Return the number of characters read from
   * `stream', which is the length of the line including the newline.
   *
!  * On DOS or Windows we do not count the CR character, if any before the
!  * NL, in the returned length; this mirrors the behavior of Emacs on those
   * platforms (for text files, it translates CR-NL to NL as it reads in the
   * file).
+  *
+  * If multi-line regular expressions are requested, each line read is
+  * appended to `filebuf'.
   */
  static long
  readline_internal (lbp, stream)
***************
*** 5626,5637 ****
      }
    lbp->len = p - buffer;
  
    return lbp->len + chars_deleted;
  }
  
  /*
   * Like readline_internal, above, but in addition try to match the
!  * input line against relevant regular expressions.
   */
  static void
  readline (lbp, stream)
--- 5775,5802 ----
      }
    lbp->len = p - buffer;
  
+   if (need_filebuf            /* we need filebuf for multi-line regexps */
+       && chars_deleted > 0)   /* not at EOF */
+     {
+       while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
+       {
+         /* Expand filebuf. */
+         filebuf.size *= 2;
+         xrnew (filebuf.buffer, filebuf.size, char);
+       }
+       strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
+       filebuf.len += lbp->len;
+       filebuf.buffer[filebuf.len++] = '\n';
+       filebuf.buffer[filebuf.len] = '\0';
+     }
+ 
    return lbp->len + chars_deleted;
  }
  
  /*
   * Like readline_internal, above, but in addition try to match the
!  * input line against relevant regular expressions and manage #line
!  * directives.
   */
  static void
  readline (lbp, stream)
***************
*** 5752,5759 ****
        {
          if (result > 0)
            {
!           /* Do a tail recursion on ourselves, thus discarding the contents
!              of the line buffer. */
              readline (lbp, stream);
              return;
            }
--- 5917,5924 ----
        {
          if (result > 0)
            {
!             /* Do a tail recursion on ourselves, thus discarding the contents
!                of the line buffer. */
              readline (lbp, stream);
              return;
            }
***************
*** 5772,5779 ****
      if (lbp->len > 0)
        for (pp = p_head; pp != NULL; pp = pp->p_next)
        {
!         /* Only use generic regexps or those for the current language. */
!         if (pp->lang != NULL && pp->lang != fdhead->lang)
            continue;
  
          match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);
--- 5937,5947 ----
      if (lbp->len > 0)
        for (pp = p_head; pp != NULL; pp = pp->p_next)
        {
!         /* Only use generic regexps or those for the current language.
!            Also do not use multiline regexps, which is the job of
!            regex_tag_multiline. */
!         if ((pp->lang != NULL && pp->lang != fdhead->lang)
!             || pp->multi_line)
            continue;
  
          match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);
***************
*** 5783,5795 ****
              /* Some error. */
              if (!pp->error_signaled)
                {
!                 error ("error while matching \"%s\"", pp->regex);
                  pp->error_signaled = TRUE;
                }
              break;
            case -1:
              /* No match. */
              break;
            default:
              /* Match occurred.  Construct a tag. */
              if (pp->name_pattern[0] != '\0')
--- 5951,5973 ----
              /* Some error. */
              if (!pp->error_signaled)
                {
!                 error ("regexp stack overflow while matching \"%s\"",
!                        pp->regex);
                  pp->error_signaled = TRUE;
                }
              break;
            case -1:
              /* No match. */
              break;
+           case 0:
+             /* Empty string matched. */
+             if (!pp->error_signaled)
+               {
+                 error ("regexp matches the empty string: \"%s\"",
+                        pp->regex);
+                 pp->error_signaled = TRUE;
+               }
+             break;
            default:
              /* Match occurred.  Construct a tag. */
              if (pp->name_pattern[0] != '\0')
***************
*** 6229,6234 ****
   * indent-tabs-mode: t
   * tab-width: 8
   * fill-column: 79
!  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" 
"node")
   * End:
   */
--- 6407,6412 ----
   * indent-tabs-mode: t
   * tab-width: 8
   * fill-column: 79
!  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" 
"node" "pattern")
   * End:
   */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]