/[emacs]/emacs/lib-src/etags.c
ViewVC logotype

Diff of /emacs/lib-src/etags.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3.21 by pot, Thu Jun 6 22:37:28 2002 UTC revision 3.22 by pot, Thu Jun 13 10:44:15 2002 UTC
# Line 2  Line 2 
2     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002     Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002
3     Free Software Foundation, Inc. and Ken Arnold     Free Software Foundation, Inc. and Ken Arnold
4    
5  This file is not considered part of GNU Emacs.   This file is not considered part of GNU Emacs.
6    
7  This program is free software; you can redistribute it and/or modify   This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by   it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or   the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.   (at your option) any later version.
11    
12  This program is distributed in the hope that it will be useful,   This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.   GNU General Public License for more details.
16    
17  You should have received a copy of the GNU General Public License   You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software Foundation,   along with this program; if not, write to the Free Software Foundation,
19  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20    
21  /*  /*
22   * Authors:   * Authors:
# Line 34  Inc., 59 Temple Place - Suite 330, Bosto Line 34  Inc., 59 Temple Place - Suite 330, Bosto
34   *      Francesco Potort́ <pot@gnu.org> has maintained it since 1993.   *      Francesco Potort́ <pot@gnu.org> has maintained it since 1993.
35   */   */
36    
37  char pot_etags_version[] = "@(#) pot revision number is 16.10";  char pot_etags_version[] = "@(#) pot revision number is 16.19";
38    
39  #define TRUE    1  #define TRUE    1
40  #define FALSE   0  #define FALSE   0
# Line 288  typedef struct Line 288  typedef struct
288    enum {    enum {
289      at_language,                /* a language specification */      at_language,                /* a language specification */
290      at_regexp,                  /* a regular expression */      at_regexp,                  /* a regular expression */
     at_icregexp,                /* same, but with case ignored */  
291      at_filename,                /* a file name */      at_filename,                /* a file name */
292      at_stdin                    /* read from stdin here */      at_stdin                    /* read from stdin here */
293    } arg_type;                   /* argument type */    } arg_type;                   /* argument type */
# Line 308  typedef struct pattern Line 307  typedef struct pattern
307    char *name_pattern;    char *name_pattern;
308    bool error_signaled;    bool error_signaled;
309    bool ignore_case;    bool ignore_case;
310      bool multi_line;
311  } pattern;  } pattern;
312  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
313    
# Line 355  static bool nocase_tail __P((char *)); Line 355  static bool nocase_tail __P((char *));
355  static char *get_tag __P((char *));  static char *get_tag __P((char *));
356    
357  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
358  static void analyse_regex __P((char *, bool));  static void analyse_regex __P((char *));
 static void add_regex __P((char *, bool, language *));  
359  static void free_patterns __P((void));  static void free_patterns __P((void));
360    static void regex_tag_multiline __P((void));
361  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
362  static void error __P((const char *, const char *));  static void error __P((const char *, const char *));
363  static void suggest_asking_for_help __P((void));  static void suggest_asking_for_help __P((void));
# Line 417  static node *nodehead;         /* the head of t Line 417  static node *nodehead;         /* the head of t
417  static node *last_node;         /* the last node created */  static node *last_node;         /* the last node created */
418    
419  static linebuffer lb;           /* the current line */  static linebuffer lb;           /* the current line */
420    static linebuffer filebuf;      /* a buffer containing the whole file */
421    
422  /* boolean "functions" (see init)       */  /* boolean "functions" (see init)       */
423  static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];  static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
# Line 457  static bool packages_only;     /* --packages Line 458  static bool packages_only;     /* --packages
458  static bool parsing_stdin;      /* --parse-stdin used */  static bool parsing_stdin;      /* --parse-stdin used */
459    
460  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
461  /* List of all regexps. */  static pattern *p_head;         /* list of all regexps */
462  static pattern *p_head;  static bool need_filebuf;       /* some regexes are multi-line */
463    #else
464  /* How many characters in the character set.  (From regex.c.)  */  # define need_filebuf FALSE
 #define CHAR_SET_SIZE 256  
 /* Translation table for case-insensitive matching. */  
 static char lc_trans[CHAR_SET_SIZE];  
465  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
466    
467  #ifdef LONG_OPTIONS  #ifdef LONG_OPTIONS
# Line 680  Compressed files are supported using gzi Line 678  Compressed files are supported using gzi
678  }  }
679    
680  #ifndef EMACS_NAME  #ifndef EMACS_NAME
681  # define EMACS_NAME "GNU Emacs"  # define EMACS_NAME "standalone"
682  #endif  #endif
683  #ifndef VERSION  #ifndef VERSION
684  # define VERSION "21"  # define VERSION "version"
685  #endif  #endif
686  static void  static void
687  print_version ()  print_version ()
# Line 775  Relative ones are stored relative to the Line 773  Relative ones are stored relative to the
773          REGEXP is anchored (as if preceded by ^).\n\          REGEXP is anchored (as if preceded by ^).\n\
774          The form /REGEXP/NAME/ creates a named tag.\n\          The form /REGEXP/NAME/ creates a named tag.\n\
775          For example Tcl named tags can be created with:\n\          For example Tcl named tags can be created with:\n\
776          --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\"");          --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\".");
777    puts ("-c /REGEXP/, --ignore-case-regex=/REGEXP/ or --ignore-case-regex=@regexfile\n\    puts ("In the form /REGEXP/MODS or /REGEXP/NAME/MODS, MODS are\n\
778          Like -r, --regex but ignore case when matching expressions.");          one-letter modifiers: `i' means to ignore case, `m' means\n\
779            allow multi-line matches, `s' implies `m' and additionally\n\
780            causes dot to match the newline character.");
781    puts ("-R, --no-regex\n\    puts ("-R, --no-regex\n\
782          Don't create tags from regexps for the following files.");          Don't create tags from regexps for the following files.");
783  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
# Line 996  main (argc, argv) Line 996  main (argc, argv)
996       is small. */       is small. */
997    argbuffer = xnew (argc, argument);    argbuffer = xnew (argc, argument);
998    
 #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 */  
   
999    /*    /*
1000     * If etags, always find typedefs and structure tags.  Why not?     * If etags, always find typedefs and structure tags.  Why not?
1001     * Also default to find macro constants, enum constants and     * Also default to find macro constants, enum constants and
# Line 1079  main (argc, argv) Line 1071  main (argc, argv)
1071              }              }
1072          }          }
1073          break;          break;
1074          case 'c':
1075            /* Backward compatibility: support obsolete --ignore-case-regexp. */
1076            optarg = concat (optarg, "i", ""); /* memory leak here */
1077            /* FALLTHRU */
1078        case 'r':        case 'r':
1079          argbuffer[current_arg].arg_type = at_regexp;          argbuffer[current_arg].arg_type = at_regexp;
1080          argbuffer[current_arg].what = optarg;          argbuffer[current_arg].what = optarg;
# Line 1089  main (argc, argv) Line 1085  main (argc, argv)
1085          argbuffer[current_arg].what = NULL;          argbuffer[current_arg].what = NULL;
1086          ++current_arg;          ++current_arg;
1087          break;          break;
       case 'c':  
         argbuffer[current_arg].arg_type = at_icregexp;  
         argbuffer[current_arg].what = optarg;  
         ++current_arg;  
         break;  
1088        case 'V':        case 'V':
1089          print_version ();          print_version ();
1090          break;          break;
# Line 1152  main (argc, argv) Line 1143  main (argc, argv)
1143    
1144    initbuffer (&lb);    initbuffer (&lb);
1145    initbuffer (&filename_lb);    initbuffer (&filename_lb);
1146      initbuffer (&filebuf);
1147    
1148    if (!CTAGS)    if (!CTAGS)
1149      {      {
# Line 1186  main (argc, argv) Line 1178  main (argc, argv)
1178            break;            break;
1179  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
1180          case at_regexp:          case at_regexp:
1181            analyse_regex (argbuffer[i].what, FALSE);            analyse_regex (argbuffer[i].what);
           break;  
         case at_icregexp:  
           analyse_regex (argbuffer[i].what, TRUE);  
1182            break;            break;
1183  #endif  #endif
1184          case at_filename:          case at_filename:
# Line 1234  main (argc, argv) Line 1223  main (argc, argv)
1223  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
1224    free_patterns ();    free_patterns ();
1225  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
1226      free (filebuf.buffer);
1227    
1228    if (!CTAGS || cxref_style)    if (!CTAGS || cxref_style)
1229      {      {
# Line 1648  find_entries (inf) Line 1638  find_entries (inf)
1638       FILE *inf;       FILE *inf;
1639  {  {
1640    char *cp;    char *cp;
   node *old_last_node;  
1641    language *lang = curfdp->lang;    language *lang = curfdp->lang;
1642    Lang_function *parser = NULL;    Lang_function *parser = NULL;
1643    
# Line 1703  find_entries (inf) Line 1692  find_entries (inf)
1692    /* We rewind here, even if inf may be a pipe.  We fail if the    /* We rewind here, even if inf may be a pipe.  We fail if the
1693       length of the first line is longer than the pipe block size,       length of the first line is longer than the pipe block size,
1694       which is unlikely. */       which is unlikely. */
1695      rewind (inf);    rewind (inf);
1696    
1697    /* Else try to guess the language given the case insensitive file name. */    /* Else try to guess the language given the case insensitive file name. */
1698    if (parser == NULL)    if (parser == NULL)
# Line 1716  find_entries (inf) Line 1705  find_entries (inf)
1705          }          }
1706      }      }
1707    
1708      /* Else try Fortran or C. */
1709      if (parser == NULL)
1710        {
1711          node *old_last_node = last_node;
1712    
1713          curfdp->lang = get_language_from_langname ("fortran");
1714          find_entries (inf);
1715    
1716          if (old_last_node == last_node)
1717            /* No Fortran entries found.  Try C. */
1718            {
1719              /* We do not tag if rewind fails.
1720                 Only the file name will be recorded in the tags file. */
1721              rewind (inf);
1722              curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
1723              find_entries (inf);
1724            }
1725          return;
1726        }
1727    
1728    if (!no_line_directive    if (!no_line_directive
1729        && curfdp->lang != NULL && curfdp->lang->metasource)        && curfdp->lang != NULL && curfdp->lang->metasource)
1730      /* It may be that this is a bingo.y file, and we already parsed a bingo.c      /* It may be that this is a bingo.y file, and we already parsed a bingo.c
# Line 1748  find_entries (inf) Line 1757  find_entries (inf)
1757            fdpp = &(*fdpp)->next; /* advance the list pointer */            fdpp = &(*fdpp)->next; /* advance the list pointer */
1758      }      }
1759    
1760    if (parser != NULL)    assert (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 */  
1761    
1762        parser (inf);    /* Generic initialisations before reading from file. */
1763        return;    filebuf.len = 0;              /* reset the file buffer */
     }  
1764    
1765    /* Else try Fortran. */    /* Generic initialisations before parsing file with readline. */
1766    old_last_node = last_node;    lineno = 0;                  /* reset global line number */
1767    curfdp->lang = get_language_from_langname ("fortran");    charno = 0;                  /* reset global char number */
1768    find_entries (inf);    linecharno = 0;              /* reset global char number of line start */
1769    
1770    if (old_last_node == last_node)    parser (inf);
1771      /* No Fortran entries found.  Try C. */  
1772      {  #ifdef ETAGS_REGEXPS
1773        /* We do not tag if rewind fails.    regex_tag_multiline ();
1774           Only the file name will be recorded in the tags file. */  #endif /* ETAGS_REGEXPS */
       rewind (inf);  
       curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");  
       find_entries (inf);  
     }  
   return;  
1775  }  }
1776    
1777    
# Line 2014  add_node (np, cur_node_p) Line 2012  add_node (np, cur_node_p)
2012   * invalidate_nodes ()   * invalidate_nodes ()
2013   *      Scan the node tree and invalidate all nodes pointing to the   *      Scan the node tree and invalidate all nodes pointing to the
2014   *      given file description (CTAGS case) or free them (ETAGS case).   *      given file description (CTAGS case) or free them (ETAGS case).
2015     *
2016     * This function most likely contains a bug, but I cannot tell where.
2017     * I have a case of a binary that crashes inside this function with a bus
2018     * error.  Unfortunately, the binary does not contain debug information, and
2019     * compiling with debugging information makes the bug disappear.
2020   */   */
2021  static void  static void
2022  invalidate_nodes (badfdp, npp)  invalidate_nodes (badfdp, npp)
# Line 2030  invalidate_nodes (badfdp, npp) Line 2033  invalidate_nodes (badfdp, npp)
2033        if (np->left != NULL)        if (np->left != NULL)
2034          invalidate_nodes (badfdp, &np->left);          invalidate_nodes (badfdp, &np->left);
2035        if (np->fdp == badfdp)        if (np->fdp == badfdp)
2036          np-> valid = FALSE;          np->valid = FALSE;
2037        if (np->right != NULL)        if (np->right != NULL)
2038          invalidate_nodes (badfdp, &np->right);          invalidate_nodes (badfdp, &np->right);
2039      }      }
# Line 5263  erlang_atom (s, pos) Line 5266  erlang_atom (s, pos)
5266  #ifdef ETAGS_REGEXPS  #ifdef ETAGS_REGEXPS
5267    
5268  static char *scan_separators __P((char *));  static char *scan_separators __P((char *));
5269  static void analyse_regex __P((char *, bool));  static void add_regex __P((char *, language *));
 static void add_regex __P((char *, bool, language *));  
5270  static char *substitute __P((char *, char *, struct re_registers *));  static char *substitute __P((char *, char *, struct re_registers *));
5271    
5272  /* Take a string like "/blah/" and turn it into "blah", making sure  /*
5273     that the first and last characters are the same, and handling   * Take a string like "/blah/" and turn it into "blah", verifying
5274     quoted separator characters.  Actually, stops on the occurrence of   * that the first and last characters are the same, and handling
5275     an unquoted separator.  Also turns "\t" into a Tab character, and   * quoted separator characters.  Actually, stops on the occurrence of
5276     similarly for all character escape sequences supported by Gcc.   * an unquoted separator.  Also process \t, \n, etc. and turn into
5277     Returns pointer to terminating separator.  Works in place.  Null   * appropriate characters. Works in place.  Null terminates name string.
5278     terminates name string. */   * Returns pointer to terminating separator, or NULL for
5279     * unterminated regexps.
5280     */
5281  static char *  static char *
5282  scan_separators (name)  scan_separators (name)
5283       char *name;       char *name;
# Line 5288  scan_separators (name) Line 5292  scan_separators (name)
5292          {          {
5293            switch (*name)            switch (*name)
5294              {              {
5295              case 'a': *copyto++ = '\007'; break;              case 'a': *copyto++ = '\007'; break; /* BEL (bell)           */
5296              case 'b': *copyto++ = '\b'; break;              case 'b': *copyto++ = '\b'; break;   /* BS (back space)      */
5297              case 'd': *copyto++ = 0177; break;              case 'd': *copyto++ = 0177; break;   /* DEL (delete)         */
5298              case 'e': *copyto++ = 033; break;              case 'e': *copyto++ = 033; break;    /* ESC (delete)         */
5299              case 'f': *copyto++ = '\f'; break;              case 'f': *copyto++ = '\f'; break;   /* FF (form feed)       */
5300              case 'n': *copyto++ = '\n'; break;              case 'n': *copyto++ = '\n'; break;   /* NL (new line)        */
5301              case 'r': *copyto++ = '\r'; break;              case 'r': *copyto++ = '\r'; break;   /* CR (carriage return) */
5302              case 't': *copyto++ = '\t'; break;              case 't': *copyto++ = '\t'; break;   /* TAB (horizontal tab) */
5303              case 'v': *copyto++ = '\v'; break;              case 'v': *copyto++ = '\v'; break;   /* VT (vertical tab)    */
5304              default:              default:
5305                if (*name == sep)                if (*name == sep)
5306                  *copyto++ = sep;                  *copyto++ = sep;
# Line 5317  scan_separators (name) Line 5321  scan_separators (name)
5321        else        else
5322          *copyto++ = *name;          *copyto++ = *name;
5323      }      }
5324      if (*name != sep)
5325        name = NULL;                /* signal unterminated regexp */
5326    
5327    /* Terminate copied string. */    /* Terminate copied string. */
5328    *copyto = '\0';    *copyto = '\0';
# Line 5326  scan_separators (name) Line 5332  scan_separators (name)
5332  /* Look at the argument of --regex or --no-regex and do the right  /* Look at the argument of --regex or --no-regex and do the right
5333     thing.  Same for each line of a regexp file. */     thing.  Same for each line of a regexp file. */
5334  static void  static void
5335  analyse_regex (regex_arg, ignore_case)  analyse_regex (regex_arg)
5336       char *regex_arg;       char *regex_arg;
      bool ignore_case;  
5337  {  {
5338    if (regex_arg == NULL)    if (regex_arg == NULL)
5339      {      {
# Line 5362  analyse_regex (regex_arg, ignore_case) Line 5367  analyse_regex (regex_arg, ignore_case)
5367            }            }
5368          initbuffer (&regexbuf);          initbuffer (&regexbuf);
5369          while (readline_internal (&regexbuf, regexfp) > 0)          while (readline_internal (&regexbuf, regexfp) > 0)
5370            analyse_regex (regexbuf.buffer, ignore_case);            analyse_regex (regexbuf.buffer);
5371          free (regexbuf.buffer);          free (regexbuf.buffer);
5372          fclose (regexfp);          fclose (regexfp);
5373        }        }
# Line 5381  analyse_regex (regex_arg, ignore_case) Line 5386  analyse_regex (regex_arg, ignore_case)
5386                error ("unterminated language name in regex: %s", regex_arg);                error ("unterminated language name in regex: %s", regex_arg);
5387                return;                return;
5388              }              }
5389          *cp = '\0';          *cp++ = '\0';
5390          lang = get_language_from_langname (lang_name);          lang = get_language_from_langname (lang_name);
5391          if (lang == NULL)          if (lang == NULL)
5392            return;            return;
5393          add_regex (cp + 1, ignore_case, lang);          add_regex (cp, lang);
5394        }        }
5395        break;        break;
5396    
5397        /* Regexp to be used for any language. */        /* Regexp to be used for any language. */
5398      default:      default:
5399        add_regex (regex_arg, ignore_case, NULL);        add_regex (regex_arg, NULL);
5400        break;        break;
5401      }      }
5402  }  }
# Line 5399  analyse_regex (regex_arg, ignore_case) Line 5404  analyse_regex (regex_arg, ignore_case)
5404  /* Turn a name, which is an ed-style (but Emacs syntax) regular  /* Turn a name, which is an ed-style (but Emacs syntax) regular
5405     expression, into a real regular expression by compiling it. */     expression, into a real regular expression by compiling it. */
5406  static void  static void
5407  add_regex (regexp_pattern, ignore_case, lang)  add_regex (regexp_pattern, lang)
5408       char *regexp_pattern;       char *regexp_pattern;
      bool ignore_case;  
5409       language *lang;       language *lang;
5410  {  {
5411    static struct re_pattern_buffer zeropattern;    static struct re_pattern_buffer zeropattern;
5412    char *name;    char sep, *pat, *name, *modifiers;
5413    const char *err;    const char *err;
5414    struct re_pattern_buffer *patbuf;    struct re_pattern_buffer *patbuf;
5415    pattern *pp;    pattern *pp;
5416      bool ignore_case, multi_line, single_line;
5417    
5418    
5419    if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])    if (strlen(regexp_pattern) < 3)
5420      {      {
5421        error ("%s: unterminated regexp", regexp_pattern);        error ("null regexp", (char *)NULL);
5422        return;        return;
5423      }      }
5424      sep = regexp_pattern[0];
5425    name = scan_separators (regexp_pattern);    name = scan_separators (regexp_pattern);
5426    if (regexp_pattern[0] == '\0')    if (name == NULL)
5427      {      {
5428        error ("null regexp", (char *)NULL);        error ("%s: unterminated regexp", regexp_pattern);
5429          return;
5430        }
5431      if (name[1] == sep)
5432        {
5433          error ("null name for regexp \"%s\"", regexp_pattern);
5434        return;        return;
5435      }      }
5436    (void) scan_separators (name);    modifiers = scan_separators (name);
5437      if (modifiers == NULL)        /* no terminating separator --> no name */
5438        {
5439          modifiers = name;
5440          name = "";
5441        }
5442      else
5443        modifiers += 1;             /* skip separator */
5444    
5445      /* Parse regex modifiers. */
5446      ignore_case = FALSE;          /* case is significant */
5447      multi_line = FALSE;           /* matches are done one line at a time */
5448      single_line = FALSE;          /* dot does not match newline */
5449      for (; modifiers[0] != '\0'; modifiers++)
5450        switch (modifiers[0])
5451          {
5452          case 'i':
5453            ignore_case = TRUE;
5454            break;
5455          case 's':
5456            single_line = TRUE;
5457            /* FALLTHRU */
5458          case 'm':
5459            multi_line = TRUE;
5460            need_filebuf = TRUE;
5461            break;
5462          default:
5463            modifiers[1] = '\0';
5464            error ("invalid regexp modifier `%s'", modifiers);
5465            return;
5466          }
5467    
5468    patbuf = xnew (1, struct re_pattern_buffer);    patbuf = xnew (1, struct re_pattern_buffer);
5469    *patbuf = zeropattern;    *patbuf = zeropattern;
5470    if (ignore_case)    if (ignore_case)
5471      patbuf->translate = lc_trans;       /* translation table to fold case  */      {
5472          static char lc_trans[CHARS];
5473          int i;
5474          for (i = 0; i < CHARS; i++)
5475            lc_trans[i] = lowcase (i);
5476          patbuf->translate = lc_trans;     /* translation table to fold case  */
5477        }
5478    
5479      if (multi_line)
5480        pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
5481      else
5482        pat = regexp_pattern;
5483    
5484    err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);    if (single_line)
5485        re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
5486      else
5487        re_set_syntax (RE_SYNTAX_EMACS);
5488    
5489      err = re_compile_pattern (pat, strlen (regexp_pattern), patbuf);
5490      if (multi_line)
5491        free (pat);
5492    if (err != NULL)    if (err != NULL)
5493      {      {
5494        error ("%s while compiling pattern", err);        error ("%s while compiling pattern", err);
# Line 5445  add_regex (regexp_pattern, ignore_case, Line 5504  add_regex (regexp_pattern, ignore_case,
5504    p_head->name_pattern = savestr (name);    p_head->name_pattern = savestr (name);
5505    p_head->error_signaled = FALSE;    p_head->error_signaled = FALSE;
5506    p_head->ignore_case = ignore_case;    p_head->ignore_case = ignore_case;
5507      p_head->multi_line = multi_line;
5508  }  }
5509    
5510  /*  /*
# Line 5512  free_patterns () Line 5572  free_patterns ()
5572      }      }
5573    return;    return;
5574  }  }
5575    
5576    /*
5577     * Reads the whole file as a single string from `filebuf' and looks for
5578     * multi-line regular expressions, creating tags on matches.
5579     * readline already dealt with normal regexps.
5580     *
5581     * Idea by Ben Wing <ben@666.com> (2002).
5582     */
5583    static void
5584    regex_tag_multiline ()
5585    {
5586      char *buffer = filebuf.buffer;
5587      pattern *pp;
5588    
5589      for (pp = p_head; pp != NULL; pp = pp->p_next)
5590        {
5591          int match = 0;
5592    
5593          if (!pp->multi_line)
5594            continue;               /* skip normal regexps */
5595    
5596          /* Generic initialisations before parsing file from memory. */
5597          lineno = 1;               /* reset global line number */
5598          charno = 0;               /* reset global char number */
5599          linecharno = 0;           /* reset global char number of line start */
5600    
5601          /* Only use generic regexps or those for the current language. */
5602          if (pp->lang != NULL && pp->lang != curfdp->lang)
5603            continue;
5604    
5605          while (match >= 0 && match < filebuf.len)
5606            {
5607              match = re_search (pp->pat, buffer, filebuf.len, charno,
5608                                 filebuf.len - match, &pp->regs);
5609              switch (match)
5610                {
5611                case -2:
5612                  /* Some error. */
5613                  if (!pp->error_signaled)
5614                    {
5615                      error ("regexp stack overflow while matching \"%s\"",
5616                             pp->regex);
5617                      pp->error_signaled = TRUE;
5618                    }
5619                  break;
5620                case -1:
5621                  /* No match. */
5622                  break;
5623                default:
5624                  if (match == pp->regs.end[0])
5625                    {
5626                      if (!pp->error_signaled)
5627                        {
5628                          error ("regexp matches the empty string: \"%s\"",
5629                                 pp->regex);
5630                          pp->error_signaled = TRUE;
5631                        }
5632                      match = -3;   /* exit from while loop */
5633                      break;
5634                    }
5635    
5636                  /* Match occurred.  Construct a tag. */
5637                  while (charno < pp->regs.end[0])
5638                    if (buffer[charno++] == '\n')
5639                      lineno++, linecharno = charno;
5640                  if (pp->name_pattern[0] != '\0')
5641                    {
5642                      /* Make a named tag. */
5643                      char *name = substitute (buffer,
5644                                               pp->name_pattern, &pp->regs);
5645                      if (name != NULL)
5646                        pfnote (name, TRUE, buffer + linecharno,
5647                                charno - linecharno + 1, lineno, linecharno);
5648                    }
5649                  else
5650                    {
5651                      /* Make an unnamed tag. */
5652                      pfnote ((char *)NULL, TRUE, buffer + linecharno,
5653                              charno - linecharno + 1, lineno, linecharno);
5654                    }
5655                  break;
5656                }
5657            }
5658        }
5659    }
5660    
5661  #endif /* ETAGS_REGEXPS */  #endif /* ETAGS_REGEXPS */
5662    
5663    
# Line 5564  initbuffer (lbp) Line 5710  initbuffer (lbp)
5710   * newline or CR-NL, if any.  Return the number of characters read from   * newline or CR-NL, if any.  Return the number of characters read from
5711   * `stream', which is the length of the line including the newline.   * `stream', which is the length of the line including the newline.
5712   *   *
5713   * On DOS or Windows we do not count the CR character, if any, before the   * On DOS or Windows we do not count the CR character, if any before the
5714   * NL, in the returned length; this mirrors the behavior of emacs on those   * NL, in the returned length; this mirrors the behavior of Emacs on those
5715   * platforms (for text files, it translates CR-NL to NL as it reads in the   * platforms (for text files, it translates CR-NL to NL as it reads in the
5716   * file).   * file).
5717     *
5718     * If multi-line regular expressions are requested, each line read is
5719     * appended to `filebuf'.
5720   */   */
5721  static long  static long
5722  readline_internal (lbp, stream)  readline_internal (lbp, stream)
# Line 5626  readline_internal (lbp, stream) Line 5775  readline_internal (lbp, stream)
5775      }      }
5776    lbp->len = p - buffer;    lbp->len = p - buffer;
5777    
5778      if (need_filebuf              /* we need filebuf for multi-line regexps */
5779          && chars_deleted > 0)     /* not at EOF */
5780        {
5781          while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
5782            {
5783              /* Expand filebuf. */
5784              filebuf.size *= 2;
5785              xrnew (filebuf.buffer, filebuf.size, char);
5786            }
5787          strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
5788          filebuf.len += lbp->len;
5789          filebuf.buffer[filebuf.len++] = '\n';
5790          filebuf.buffer[filebuf.len] = '\0';
5791        }
5792    
5793    return lbp->len + chars_deleted;    return lbp->len + chars_deleted;
5794  }  }
5795    
5796  /*  /*
5797   * Like readline_internal, above, but in addition try to match the   * Like readline_internal, above, but in addition try to match the
5798   * input line against relevant regular expressions.   * input line against relevant regular expressions and manage #line
5799     * directives.
5800   */   */
5801  static void  static void
5802  readline (lbp, stream)  readline (lbp, stream)
# Line 5752  readline (lbp, stream) Line 5917  readline (lbp, stream)
5917          {          {
5918            if (result > 0)            if (result > 0)
5919              {              {
5920              /* Do a tail recursion on ourselves, thus discarding the contents                /* Do a tail recursion on ourselves, thus discarding the contents
5921                 of the line buffer. */                   of the line buffer. */
5922                readline (lbp, stream);                readline (lbp, stream);
5923                return;                return;
5924              }              }
# Line 5772  readline (lbp, stream) Line 5937  readline (lbp, stream)
5937      if (lbp->len > 0)      if (lbp->len > 0)
5938        for (pp = p_head; pp != NULL; pp = pp->p_next)        for (pp = p_head; pp != NULL; pp = pp->p_next)
5939          {          {
5940            /* Only use generic regexps or those for the current language. */            /* Only use generic regexps or those for the current language.
5941            if (pp->lang != NULL && pp->lang != fdhead->lang)               Also do not use multiline regexps, which is the job of
5942                 regex_tag_multiline. */
5943              if ((pp->lang != NULL && pp->lang != fdhead->lang)
5944                  || pp->multi_line)
5945              continue;              continue;
5946    
5947            match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);            match = re_match (pp->pat, lbp->buffer, lbp->len, 0, &pp->regs);
# Line 5783  readline (lbp, stream) Line 5951  readline (lbp, stream)
5951                /* Some error. */                /* Some error. */
5952                if (!pp->error_signaled)                if (!pp->error_signaled)
5953                  {                  {
5954                    error ("error while matching \"%s\"", pp->regex);                    error ("regexp stack overflow while matching \"%s\"",
5955                             pp->regex);
5956                    pp->error_signaled = TRUE;                    pp->error_signaled = TRUE;
5957                  }                  }
5958                break;                break;
5959              case -1:              case -1:
5960                /* No match. */                /* No match. */
5961                break;                break;
5962                case 0:
5963                  /* Empty string matched. */
5964                  if (!pp->error_signaled)
5965                    {
5966                      error ("regexp matches the empty string: \"%s\"",
5967                             pp->regex);
5968                      pp->error_signaled = TRUE;
5969                    }
5970                  break;
5971              default:              default:
5972                /* Match occurred.  Construct a tag. */                /* Match occurred.  Construct a tag. */
5973                if (pp->name_pattern[0] != '\0')                if (pp->name_pattern[0] != '\0')
# Line 6229  xrealloc (ptr, size) Line 6407  xrealloc (ptr, size)
6407   * indent-tabs-mode: t   * indent-tabs-mode: t
6408   * tab-width: 8   * tab-width: 8
6409   * fill-column: 79   * fill-column: 79
6410   * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node")   * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "pattern")
6411   * End:   * End:
6412   */   */

Legend:
Removed from v.3.21  
changed lines
  Added in v.3.22

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26