This commit was generated by cvs2svn to compensate for changes in r10464,
[chise/xemacs-chise.git.1] / lib-src / ootags.c
1 /* Tags file maker to go with GNU Emacs
2    Copyright (C) 1984, 87, 88, 89, 93, 94, 95
3    Free Software Foundation, Inc. and Ken Arnold
4
5 This file is not considered part of GNU Emacs.
6
7 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
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 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,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /*
22  * Authors:
23  *      Ctags originally by Ken Arnold.
24  *      Fortran added by Jim Kleckner.
25  *      Ed Pelegri-Llopart added C typedefs.
26  *      Gnu Emacs TAGS format and modifications by RMS?
27  *      Sam Kendall added C++.
28  *      Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
29  *      Regexp tags by Tom Tromey.
30  *
31  *      Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer.
32  */
33
34 char pot_etags_version[] = "@(#) pot revision number is 12.28";
35
36 /* Prototyping magic snarfed from gmalloc.c */
37 #if defined (__cplusplus) || defined (__STDC__)
38 #undef  PP
39 #define PP(args)        args
40 #undef  __ptr_t
41 #define __ptr_t         void *
42 #else /* Not C++ or ANSI C.  */
43 #undef  PP
44 #define PP(args)        ()
45 #undef  const
46 #define const
47 #undef  __ptr_t
48 #define __ptr_t         char *
49 #endif /* C++ or ANSI C.  */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53   /* On some systems, Emacs defines static as nothing for the sake
54      of unexec.  We don't want that here since we don't use unexec. */
55 # undef static
56 # define ETAGS_REGEXPS          /* use the regexp features */
57 # define LONG_OPTIONS           /* accept long options */
58 #endif /* HAVE_CONFIG_H */
59
60 #define TRUE    1
61 #define FALSE   0
62
63 #ifndef DEBUG
64 # define DEBUG FALSE
65 #endif
66
67 #ifdef WIN32_NATIVE
68 # include <stdlib.h>
69 # include <fcntl.h>
70 # include <string.h>
71 # include <io.h>
72 # define MAXPATHLEN _MAX_PATH
73 # ifndef HAVE_CONFIG_H
74 #   define HAVE_GETCWD
75 # endif /* not HAVE_CONFIG_H */
76 #endif /* WIN32_NATIVE */
77
78 #if !defined (WIN32_NATIVE) && defined (STDC_HEADERS)
79 #include <stdlib.h>
80 #include <string.h>
81 #endif
82
83 #ifdef HAVE_UNISTD_H
84 # include <unistd.h>
85 #else
86 # ifdef HAVE_GETCWD
87     extern char *getcwd ();
88 # endif
89 #endif /* HAVE_UNISTD_H */
90
91 #include <stdio.h>
92 #include <ctype.h>
93 #include <errno.h>
94 #include <sys/types.h>
95 #include <sys/stat.h>
96
97 #if !defined (S_ISREG) && defined (S_IFREG)
98 # define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG)
99 #endif
100
101 #ifdef LONG_OPTIONS
102 # include <getopt.h>
103 #else
104 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
105   extern char *optarg;
106   extern int optind, opterr;
107 #endif /* LONG_OPTIONS */
108
109 #ifdef ETAGS_REGEXPS
110 # include <regex.h>
111 #endif /* ETAGS_REGEXPS */
112
113 /* Define CTAGS to make the program "ctags" compatible with the usual one.
114  Leave it undefined to make the program "etags", which makes emacs-style
115  tag tables and tags typedefs, #defines and struct/union/enum by default. */
116 #ifdef CTAGS
117 # undef  CTAGS
118 # define CTAGS TRUE
119 #else
120 # define CTAGS FALSE
121 #endif
122
123 /* Exit codes for success and failure.  */
124 #ifdef VMS
125 # define        GOOD    1
126 # define        BAD     0
127 #else
128 # define        GOOD    0
129 # define        BAD     1
130 #endif
131
132 /* C extensions. */
133 #define C_PLPL  0x00001         /* C++ */
134 #define C_STAR  0x00003         /* C* */
135 #define C_JAVA  0x00005         /* JAVA */
136 #define YACC    0x10000         /* yacc file */
137
138 #define streq(s,t)      ((DEBUG && (s) == NULL && (t) == NULL   \
139                           && (abort (), 1)) || !strcmp (s, t))
140 #define strneq(s,t,n)   ((DEBUG && (s) == NULL && (t) == NULL   \
141                           && (abort (), 1)) || !strncmp (s, t, n))
142
143 #define lowcase(c)      tolower ((char)c)
144
145 #define CHARS 256               /* 2^sizeof(char) */
146 #define CHAR(x)         ((unsigned int)x & (CHARS - 1))
147 #define iswhite(c)      (_wht[CHAR(c)]) /* c is white */
148 #define notinname(c)    (_nin[CHAR(c)]) /* c is not in a name */
149 #define begtoken(c)     (_btk[CHAR(c)]) /* c can start token */
150 #define intoken(c)      (_itk[CHAR(c)]) /* c can be in token */
151 #define endtoken(c)     (_etk[CHAR(c)]) /* c ends tokens */
152
153 /*#ifdef INFODOCK*/
154 /*#undef OO_BROWSER*/
155 /* Due to the way this file is constructed, this unfortunately doesn't */
156 /* work except for documentation purposes. -slb */
157 #define OO_BROWSER 1
158 /*#endif*/
159
160 #ifdef OO_BROWSER
161 #define set_construct(construct) \
162   if (!oo_browser_construct) oo_browser_construct = construct
163 void oo_browser_clear_all_globals(void);
164 void oo_browser_clear_some_globals(void);
165 void oo_browser_check_and_clear_structtype(void);
166 #endif
167
168 /*
169  *      xnew, xrnew -- allocate, reallocate storage
170  *
171  * SYNOPSIS:    Type *xnew (int n, Type);
172  *              Type *xrnew (OldPointer, int n, Type);
173  */
174 #ifdef chkmalloc
175 # include "chkmalloc.h"
176 # define xnew(n,Type)     ((Type *) trace_malloc (__FILE__, __LINE__, \
177                                                   (n) * sizeof (Type)))
178 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
179                                                    (op), (n) * sizeof (Type)))
180 #else
181 # define xnew(n,Type)     ((Type *) xmalloc ((n) * sizeof (Type)))
182 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
183 #endif
184
185 typedef int bool;
186
187 typedef void Lang_function (FILE *);
188
189 typedef struct
190 {
191   char *name;
192   Lang_function *function;
193   char **suffixes;
194   char **interpreters;
195 } language;
196
197 typedef struct node_st
198 {                               /* sorting structure            */
199   char *name;                   /* function or type name        */
200 #ifdef OO_BROWSER
201   short int construct;          /* Construct type for the OO-Browser */
202 #endif
203   char *file;                   /* file name                    */
204   bool is_func;                 /* use pattern or line no       */
205   bool been_warned;             /* set if noticed dup           */
206   int lno;                      /* line number tag is on        */
207   long cno;                     /* character number line starts on */
208   char *pat;                    /* search pattern               */
209   struct node_st *left, *right; /* left and right sons          */
210 } node;
211
212 #ifdef OO_BROWSER
213 /* If you add to this array, you must add a corresponding entry to the
214    following enum. */
215 static char *oo_browser_default_classes[] =
216   /* Lack of square brackets around some of these entries are intentional. */
217   {"null", "class", "method", "[constant]", "[enumeration]", "[enum_label]",
218    "extern", "[function]", "[macro]", "objc", "[structure]", "[type]",
219    "[union]", "[variable]"};
220
221 /* If you add to this enum, you must add a corresponding entry to the
222    preceding array. */
223 enum oo_browser_constructs {C_NULL, C_CLASS, C_METHOD, C_CONSTANT, C_ENUMERATION,
224                             C_ENUM_LABEL, C_EXTERN, C_FUNCTION, C_MACRO,
225                             C_OBJC, C_STRUCTURE, C_TYPE, C_UNION, C_VARIABLE};
226
227 enum oo_browser_constructs oo_browser_construct = C_NULL;
228 #endif
229
230 /*
231  * A `linebuffer' is a structure which holds a line of text.
232  * `readline_internal' reads a line from a stream into a linebuffer
233  * and works regardless of the length of the line.
234  * SIZE is the size of BUFFER, LEN is the length of the string in
235  * BUFFER after readline reads it.
236  */
237 typedef struct
238 {
239   long size;
240   int len;
241   char *buffer;
242 } linebuffer;
243
244 extern char *getenv PP ((const char *envvar));
245
246 /* Many compilers barf on this:
247         Lang_function Asm_labels;
248    so let's write it this way */
249 void Asm_labels PP ((FILE *inf));
250 void C_entries PP ((int c_ext, FILE *inf));
251 void default_C_entries PP ((FILE *inf));
252 void plain_C_entries PP ((FILE *inf));
253 void Cjava_entries PP ((FILE *inf));
254 void Cplusplus_entries PP ((FILE *inf));
255 void Yacc_entries PP ((FILE *inf));
256 void Cobol_paragraphs PP ((FILE *inf));
257 void Cstar_entries PP ((FILE *inf));
258 void Erlang_functions PP ((FILE *inf));
259 void Fortran_functions PP ((FILE *inf));
260 void Lisp_functions PP ((FILE *inf));
261 void Pascal_functions PP ((FILE *inf));
262 void Perl_functions PP ((FILE *inf));
263 void Postscript_functions PP ((FILE *inf));
264 void Prolog_functions PP ((FILE *inf));
265 void Python_functions PP ((FILE *inf));
266 void Scheme_functions PP ((FILE *inf));
267 void TeX_functions PP ((FILE *inf));
268 void just_read_file PP ((FILE *inf));
269
270 void print_language_names PP ((void));
271 void print_version PP ((void));
272 void print_help PP ((void));
273
274 language *get_language_from_name PP ((char *name));
275 language *get_language_from_interpreter PP ((char *interpreter));
276 language *get_language_from_suffix PP ((char *suffix));
277 int total_size_of_entries PP ((node *np));
278 long readline PP ((linebuffer *lbp, FILE *stream));
279 long readline_internal PP ((linebuffer *lbp, FILE *stream));
280 #ifdef ETAGS_REGEXPS
281 void analyse_regex PP ((char *regex_arg));
282 void add_regex PP ((char *regexp_pattern, language *lang));
283 void free_patterns PP ((void));
284 #endif /* ETAGS_REGEXPS */
285 void error PP ((const char *s1, const char *s2));
286 void suggest_asking_for_help PP ((void));
287 void fatal PP ((char *s1, char *s2));
288 void pfatal PP ((char *s1));
289 void add_node PP ((node *np, node **cur_node_p));
290
291 void init PP ((void));
292 void initbuffer PP ((linebuffer *lbp));
293 void find_entries PP ((char *file, FILE *inf));
294 void free_tree PP ((node *np));
295 void pfnote PP ((char *name, bool is_func, char *linestart, int linelen, int lno, long cno));
296 void new_pfnote PP ((char *name, int namelen, bool is_func, char *linestart, int linelen, int lno, long cno));
297 void process_file PP ((char *file));
298 void put_entries PP ((node *np));
299 void takeprec PP ((void));
300
301 char *concat PP ((char *s1, char *s2, char *s3));
302 char *skip_spaces PP ((char *cp));
303 char *skip_non_spaces PP ((char *cp));
304 char *savenstr PP ((char *cp, int len));
305 char *savestr PP ((char *cp));
306 char *etags_strchr PP ((char *sp, int c));
307 char *etags_strrchr PP ((char *sp, int c));
308 char *etags_getcwd PP ((void));
309 char *relative_filename PP ((char *file, char *dir));
310 char *absolute_filename PP ((char *file, char *dir));
311 char *absolute_dirname PP ((char *file, char *dir));
312 bool filename_is_absolute PP ((char *fn));
313 void canonicalize_filename PP ((char *fn));
314 void grow_linebuffer PP ((linebuffer *lbp, int toksize));
315 long *xmalloc PP ((unsigned int size));
316 long *xrealloc PP ((char *ptr, unsigned int size));
317
318 \f
319 char searchar = '/';            /* use /.../ searches */
320
321 char *tagfile;                  /* output file */
322 char *progname;                 /* name this program was invoked with */
323 char *cwd;                      /* current working directory */
324 char *tagfiledir;               /* directory of tagfile */
325 FILE *tagf;                     /* ioptr for tags file */
326
327 char *curfile;                  /* current input file name */
328 language *curlang;              /* current language */
329
330 int lineno;                     /* line number of current line */
331 long charno;                    /* current character number */
332 long linecharno;                /* charno of start of current line */
333 char *dbp;                      /* pointer to start of current tag */
334 node *head;                     /* the head of the binary tree of tags */
335
336 linebuffer lb;                  /* the current line */
337 linebuffer token_name;          /* used by C_entries as a temporary area */
338 struct
339 {
340   long linepos;
341   linebuffer lb;                /* used by C_entries instead of lb */
342 } lbs[2];
343
344 /* boolean "functions" (see init)       */
345 bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
346 char
347   /* white chars */
348   *white = " \f\t\n\r",
349   /* not in a name */
350   *nonam = " \f\t\n\r(=,[;",
351   /* token ending chars */
352   *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
353   /* token starting chars */
354   *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
355   /* valid in-token chars */
356   *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
357
358 bool append_to_tagfile;         /* -a: append to tags */
359 /* The following four default to TRUE for etags, but to FALSE for ctags.  */
360 bool typedefs;                  /* -t: create tags for C typedefs */
361 bool typedefs_and_cplusplus;    /* -T: create tags for C typedefs, level */
362                                 /* 0 struct/enum/union decls, and C++ */
363                                 /* member functions. */
364 bool constantypedefs;           /* -d: create tags for C #define, enum */
365                                 /* constants and variables. */
366                                 /* -D: opposite of -d.  Default under ctags. */
367 bool globals;                   /* create tags for global variables */
368 bool members;                   /* create tags for C member variables */
369 bool update;                    /* -u: update tags */
370 bool vgrind_style;              /* -v: create vgrind style index output */
371 bool no_warnings;               /* -w: suppress warnings */
372 bool cxref_style;               /* -x: create cxref style output */
373 bool cplusplus;                 /* .[hc] means C++, not C */
374 bool noindentypedefs;           /* -I: ignore indentation in C */
375 #ifdef OO_BROWSER
376 bool oo_browser_format;         /* -O: OO-Browser tags format */
377 #endif
378
379 #ifdef LONG_OPTIONS
380 struct option longopts[] =
381 {
382   { "append",                   no_argument,       NULL,     'a'   },
383   { "backward-search",          no_argument,       NULL,     'B'   },
384   { "c++",                      no_argument,       NULL,     'C'   },
385   { "cxref",                    no_argument,       NULL,     'x'   },
386   { "defines",                  no_argument,       NULL,     'd'   },
387   { "no-defines",               no_argument,       NULL,     'D'   },
388   { "globals",                  no_argument,       &globals, TRUE  },
389   { "no-globals",               no_argument,       &globals, FALSE },
390   { "help",                     no_argument,       NULL,     'h'   },
391   { "help",                     no_argument,       NULL,     'H'   },
392   { "ignore-indentation",       no_argument,       NULL,     'I'   },
393   { "include",                  required_argument, NULL,     'i'   },
394   { "language",                 required_argument, NULL,     'l'   },
395   { "members",                  no_argument,       &members, TRUE  },
396   { "no-members",               no_argument,       &members, FALSE },
397   { "no-warn",                  no_argument,       NULL,     'w'   },
398   { "output",                   required_argument, NULL,     'o'   },
399 #ifdef OO_BROWSER
400   { "oo-browser",               no_argument,       NULL,     'O'   },
401 #endif
402 #ifdef ETAGS_REGEXPS  
403   { "regex",                    required_argument, NULL,     'r'   },
404   { "no-regex",                 no_argument,       NULL,     'R'   },
405 #endif /* ETAGS_REGEXPS */  
406   { "typedefs",                 no_argument,       NULL,     't'   },
407   { "typedefs-and-c++",         no_argument,       NULL,     'T'   },
408   { "update",                   no_argument,       NULL,     'u'   },
409   { "version",                  no_argument,       NULL,     'V'   },
410   { "vgrind",                   no_argument,       NULL,     'v'   },
411   { 0 }
412 };
413 #endif /* LONG_OPTIONS */
414
415 #ifdef ETAGS_REGEXPS
416 /* Structure defining a regular expression.  Elements are
417    the compiled pattern, and the name string. */
418 typedef struct pattern
419 {
420   struct pattern *p_next;
421   language *language;
422   char *regex;
423   struct re_pattern_buffer *pattern;
424   struct re_registers regs;
425   char *name_pattern;
426   bool error_signaled;
427 } pattern;
428
429 /* Array of all regexps. */
430 pattern *p_head = NULL;
431 #endif /* ETAGS_REGEXPS */
432
433 /*
434  * Language stuff.
435  */
436
437 /* Non-NULL if language fixed. */
438 language *forced_lang = NULL;
439
440 /* Assembly code */
441 char *Asm_suffixes [] = { "a",  /* Unix assembler */
442                           "asm", /* Microcontroller assembly */
443                           "def", /* BSO/Tasking definition includes  */
444                           "inc", /* Microcontroller include files */
445                           "ins", /* Microcontroller include files */
446                           "s", "sa", /* Unix assembler */
447                           "src", /* BSO/Tasking C compiler output */
448                           NULL
449                         };
450
451 /* Note that .c and .h can be considered C++, if the --c++ flag was
452    given.  That is why default_C_entries is called here. */
453 char *default_C_suffixes [] =
454   { "c", "h", NULL };
455
456 char *Cplusplus_suffixes [] =
457   { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
458     "M",                        /* Objective C++ */
459     "pdb",                      /* Postscript with C syntax */
460     NULL };
461
462 char *Cjava_suffixes [] =
463   { "java", NULL };
464
465 char *Cobol_suffixes [] =
466   { "COB", "cob", NULL };
467
468 char *Cstar_suffixes [] =
469   { "cs", "hs", NULL };
470
471 char *Erlang_suffixes [] =
472   { "erl", "hrl", NULL };
473
474 char *Fortran_suffixes [] =
475   { "F", "f", "f90", "for", NULL };
476
477 char *Lisp_suffixes [] =
478   { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
479
480 char *Pascal_suffixes [] =
481   { "p", "pas", NULL };
482
483 char *Perl_suffixes [] =
484   { "pl", "pm", NULL };
485 char *Perl_interpreters [] =
486   { "perl", "@PERL@", NULL };
487
488 char *plain_C_suffixes [] =
489   { "pc",                       /* Pro*C file */
490     "m",                        /* Objective C file */
491     "lm",                       /* Objective lex file */
492      NULL };
493
494 char *Postscript_suffixes [] =
495   { "ps", NULL };
496
497 char *Prolog_suffixes [] =
498   { "prolog", NULL };
499
500 char *Python_suffixes [] =
501   { "py", NULL };
502
503 /* Can't do the `SCM' or `scm' prefix with a version number. */
504 char *Scheme_suffixes [] =
505   { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "ss", "t", NULL };
506
507 char *TeX_suffixes [] =
508   { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
509
510 char *Yacc_suffixes [] =
511   { "y", "ym", NULL };          /* .ym is Objective yacc file */
512
513 /*
514  * Table of languages.
515  *
516  * It is ok for a given function to be listed under more than one
517  * name.  I just didn't.
518  */
519
520 language lang_names [] =
521 {
522   { "asm",     Asm_labels,          Asm_suffixes,         NULL              },
523   { "c",       default_C_entries,   default_C_suffixes,   NULL              },
524   { "c++",     Cplusplus_entries,   Cplusplus_suffixes,   NULL              },
525   { "c*",      Cstar_entries,       Cstar_suffixes,       NULL              },
526   { "cobol",   Cobol_paragraphs,    Cobol_suffixes,       NULL              },
527   { "erlang",  Erlang_functions,    Erlang_suffixes,      NULL              },
528   { "fortran", Fortran_functions,   Fortran_suffixes,     NULL              },
529   { "java",    Cjava_entries,       Cjava_suffixes,       NULL              },
530   { "lisp",    Lisp_functions,      Lisp_suffixes,        NULL              },
531   { "pascal",  Pascal_functions,    Pascal_suffixes,      NULL              },
532   { "perl",    Perl_functions,      Perl_suffixes,        Perl_interpreters },
533   { "postscript", Postscript_functions, Postscript_suffixes, NULL           },
534   { "proc",    plain_C_entries,     plain_C_suffixes,     NULL              },
535   { "prolog",  Prolog_functions,    Prolog_suffixes,      NULL              },
536   { "python",  Python_functions,    Python_suffixes,      NULL              },
537   { "scheme",  Scheme_functions,    Scheme_suffixes,      NULL              },
538   { "tex",     TeX_functions,       TeX_suffixes,         NULL              },
539   { "yacc",    Yacc_entries,        Yacc_suffixes,        NULL              },
540   { "auto", NULL },             /* default guessing scheme */
541   { "none", just_read_file },   /* regexp matching only */
542   { NULL, NULL }                /* end of list */
543 };
544
545 \f
546 void
547 print_language_names ()
548 {
549   language *lang;
550   char **ext;
551
552   puts ("\nThese are the currently supported languages, along with the\n\
553 default file name suffixes:");
554   for (lang = lang_names; lang->name != NULL; lang++)
555     {
556       printf ("\t%s\t", lang->name);
557       if (lang->suffixes != NULL)
558         for (ext = lang->suffixes; *ext != NULL; ext++)
559           printf (" .%s", *ext);
560       puts ("");
561     }
562   puts ("Where `auto' means use default language for files based on file\n\
563 name suffix, and `none' means only do regexp processing on files.\n\
564 If no language is specified and no matching suffix is found,\n\
565 the first line of the file is read for a sharp-bang (#!) sequence\n\
566 followed by the name of an interpreter.  If no such sequence is found,\n\
567 Fortran is tried first; if no tags are found, C is tried next.");
568 }
569
570 #ifndef VERSION
571 # define VERSION "20"
572 #endif
573 void
574 print_version ()
575 {
576   printf ("%s (GNU Emacs %s)\n", (CTAGS) ? "ctags" : "etags", VERSION);
577   puts ("Copyright (C) 1996 Free Software Foundation, Inc. and Ken Arnold");
578   puts ("This program is distributed under the same terms as Emacs");
579
580   exit (GOOD);
581 }
582
583 void
584 print_help ()
585 {
586   printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
587 \n\
588 These are the options accepted by %s.\n", progname, progname);
589 #ifdef LONG_OPTIONS
590   puts ("You may use unambiguous abbreviations for the long option names.");
591 #else
592   puts ("Long option names do not work with this executable, as it is not\n\
593 linked with GNU getopt.");
594 #endif /* LONG_OPTIONS */
595   puts ("A - as file name means read names from stdin (one per line).");
596   if (!CTAGS)
597     printf ("  Absolute names are stored in the output file as they are.\n\
598 Relative ones are stored relative to the output file's directory.");
599   puts ("\n");
600
601   puts ("-a, --append\n\
602         Append tag entries to existing tags file.");
603
604   if (CTAGS)
605     puts ("-B, --backward-search\n\
606         Write the search commands for the tag entries using '?', the\n\
607         backward-search command instead of '/', the forward-search command.");
608
609   puts ("-C, --c++\n\
610         Treat files whose name suffix defaults to C language as C++ files.");
611
612   if (CTAGS)
613     puts ("-d, --defines\n\
614         Create tag entries for C #define constants and enum constants, too.");
615   else
616     puts ("-D, --no-defines\n\
617         Don't create tag entries for C #define constants and enum constants.\n\
618         This makes the tags file smaller.");
619
620   if (!CTAGS)
621     {
622       puts ("-i FILE, --include=FILE\n\
623         Include a note in tag file indicating that, when searching for\n\
624         a tag, one should also consult the tags file FILE after\n\
625         checking the current file.");
626       puts ("-l LANG, --language=LANG\n\
627         Force the following files to be considered as written in the\n\
628         named language up to the next --language=LANG option.");
629     }
630
631   if (CTAGS)
632     puts ("--globals\n\
633         Create tag entries for global variables in some languages.");
634   else
635     puts ("--no-globals\n\
636         Do not create tag entries for global variables in some\n\
637         languages.  This makes the tags file smaller.");
638   puts ("--members\n\
639         Create tag entries for member variables in C and derived languages.");
640
641 #ifdef ETAGS_REGEXPS
642   puts ("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
643         Make a tag for each line matching pattern REGEXP in the\n\
644         following files.  regexfile is a file containing one REGEXP\n\
645         per line.  REGEXP is anchored (as if preceded by ^).\n\
646         The form /REGEXP/NAME/ creates a named tag.  For example Tcl\n\
647         named tags can be created with:\n\
648         --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
649   puts ("-R, --no-regex\n\
650         Don't create tags from regexps for the following files.");
651 #endif /* ETAGS_REGEXPS */
652   puts ("-o FILE, --output=FILE\n\
653         Write the tags to FILE.");
654 #ifdef OO_BROWSER
655   puts ("-O, --oo-browser\n\
656         Generate a specialized tags format used only by the Altrasoft OO-Browser.");
657 #endif
658   puts ("-I, --ignore-indentation\n\
659         Don't rely on indentation quite as much as normal.  Currently,\n\
660         this means not to assume that a closing brace in the first\n\
661         column is the final brace of a function or structure\n\
662         definition in C and C++.");
663
664   if (CTAGS)
665     {
666       puts ("-t, --typedefs\n\
667         Generate tag entries for C typedefs.");
668       puts ("-T, --typedefs-and-c++\n\
669         Generate tag entries for C typedefs, C struct/enum/union tags,\n\
670         and C++ member functions.");
671       puts ("-u, --update\n\
672         Update the tag entries for the given files, leaving tag\n\
673         entries for other files in place.  Currently, this is\n\
674         implemented by deleting the existing entries for the given\n\
675         files and then rewriting the new entries at the end of the\n\
676         tags file.  It is often faster to simply rebuild the entire\n\
677         tag file than to use this.");
678       puts ("-v, --vgrind\n\
679         Generates an index of items intended for human consumption,\n\
680         similar to the output of vgrind.  The index is sorted, and\n\
681         gives the page number of each item.");
682       puts ("-w, --no-warn\n\
683         Suppress warning messages about entries defined in multiple\n\
684         files.");
685       puts ("-x, --cxref\n\
686         Like --vgrind, but in the style of cxref, rather than vgrind.\n\
687         The output uses line numbers instead of page numbers, but\n\
688         beyond that the differences are cosmetic; try both to see\n\
689         which you like.");
690     }
691
692   puts ("-V, --version\n\
693         Print the version of the program.\n\
694 -h, --help\n\
695         Print this help message.");
696
697   print_language_names ();
698
699   puts ("");
700   puts ("Report bugs to bug-gnu-emacs@prep.ai.mit.edu");
701
702   exit (GOOD);
703 }
704
705 \f
706 enum argument_type
707 {
708   at_language,
709   at_regexp,
710   at_filename
711 };
712
713 /* This structure helps us allow mixing of --lang and file names. */
714 typedef struct
715 {
716   enum argument_type arg_type;
717   char *what;
718   language *lang;
719 } argument;
720
721 #ifdef VMS                      /* VMS specific functions */
722
723 #define EOS     '\0'
724
725 /* This is a BUG!  ANY arbitrary limit is a BUG!
726    Won't someone please fix this?  */
727 #define MAX_FILE_SPEC_LEN       255
728 typedef struct  {
729   short   curlen;
730   char    body[MAX_FILE_SPEC_LEN + 1];
731 } vspec;
732
733 /*
734  v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
735  returning in each successive call the next file name matching the input
736  spec. The function expects that each in_spec passed
737  to it will be processed to completion; in particular, up to and
738  including the call following that in which the last matching name
739  is returned, the function ignores the value of in_spec, and will
740  only start processing a new spec with the following call.
741  If an error occurs, on return out_spec contains the value
742  of in_spec when the error occurred.
743
744  With each successive file name returned in out_spec, the
745  function's return value is one. When there are no more matching
746  names the function returns zero. If on the first call no file
747  matches in_spec, or there is any other error, -1 is returned.
748 */
749
750 #include        <rmsdef.h>
751 #include        <descrip.h>
752 #define         OUTSIZE MAX_FILE_SPEC_LEN
753 short
754 fn_exp (out, in)
755      vspec *out;
756      char *in;
757 {
758   static long context = 0;
759   static struct dsc$descriptor_s o;
760   static struct dsc$descriptor_s i;
761   static bool pass1 = TRUE;
762   long status;
763   short retval;
764
765   if (pass1)
766     {
767       pass1 = FALSE;
768       o.dsc$a_pointer = (char *) out;
769       o.dsc$w_length = (short)OUTSIZE;
770       i.dsc$a_pointer = in;
771       i.dsc$w_length = (short)strlen(in);
772       i.dsc$b_dtype = DSC$K_DTYPE_T;
773       i.dsc$b_class = DSC$K_CLASS_S;
774       o.dsc$b_dtype = DSC$K_DTYPE_VT;
775       o.dsc$b_class = DSC$K_CLASS_VS;
776     }
777   if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
778     {
779       out->body[out->curlen] = EOS;
780       return 1;
781     }
782   else if (status == RMS$_NMF)
783     retval = 0;
784   else
785     {
786       strcpy(out->body, in);
787       retval = -1;
788     }
789   lib$find_file_end(&context);
790   pass1 = TRUE;
791   return retval;
792 }
793
794 /*
795   v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
796   name of each file specified by the provided arg expanding wildcards.
797 */
798 char *
799 gfnames (arg, p_error)
800      char *arg;
801      bool *p_error;
802 {
803   static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
804
805   switch (fn_exp (&filename, arg))
806     {
807     case 1:
808       *p_error = FALSE;
809       return filename.body;
810     case 0:
811       *p_error = FALSE;
812       return NULL;
813     default:
814       *p_error = TRUE;
815       return filename.body;
816     }
817 }
818
819 #ifndef OLD  /* Newer versions of VMS do provide `system'.  */
820 system (cmd)
821      char *cmd;
822 {
823   error ("%s", "system() function not implemented under VMS");
824 }
825 #endif
826
827 #define VERSION_DELIM   ';'
828 char *massage_name (s)
829      char *s;
830 {
831   char *start = s;
832
833   for ( ; *s; s++)
834     if (*s == VERSION_DELIM)
835       {
836         *s = EOS;
837         break;
838       }
839     else
840       *s = lowcase (*s);
841   return start;
842 }
843 #endif /* VMS */
844
845 \f
846 int
847 main (int argc, char *argv[])
848 {
849   int i;
850   unsigned int nincluded_files;
851   char **included_files;
852   char *this_file;
853   argument *argbuffer;
854   int current_arg, file_count;
855   linebuffer filename_lb;
856 #ifdef VMS
857   bool got_err;
858 #endif
859
860 #ifdef WIN32_NATIVE
861   _fmode = O_BINARY;   /* all of files are treated as binary files */
862 #endif /* WIN32_NATIVE */
863
864   progname = argv[0];
865   nincluded_files = 0;
866   included_files = xnew (argc, char *);
867   current_arg = 0;
868   file_count = 0;
869
870   /* Allocate enough no matter what happens.  Overkill, but each one
871      is small. */
872   argbuffer = xnew (argc, argument);
873
874 #ifdef ETAGS_REGEXPS
875   /* Set syntax for regular expression routines. */
876   re_set_syntax (RE_SYNTAX_EMACS | RE_INTERVALS);
877 #endif /* ETAGS_REGEXPS */
878
879   /*
880    * If etags, always find typedefs and structure tags.  Why not?
881    * Also default is to find macro constants, enum constants and
882    * global variables. 
883    */
884   if (!CTAGS)
885     {
886       typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
887       globals = TRUE;
888       members = FALSE;
889     }
890
891   while (1)
892     {
893       int opt;
894       char *optstring;
895
896 #ifdef ETAGS_REGEXPS
897 #ifndef OO_BROWSER
898       optstring = "-aCdDf:Il:o:r:RStTi:BuvxwVhH";
899 #else
900       optstring = "-aCdDf:Il:o:r:RStTi:BOuvxwVhH";
901 #endif
902 #else
903 #ifndef OO_BROWSER
904       optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
905 #else
906       optstring = "-aCdDf:Il:o:StTi:BOuvxwVhH";
907 #endif
908 #endif /* ETAGS_REGEXPS */
909
910 #ifndef LONG_OPTIONS
911       optstring = optstring + 1;
912 #endif /* LONG_OPTIONS */
913
914       opt = getopt_long (argc, argv, optstring, longopts, 0);
915       if (opt == EOF)
916         break;
917
918       switch (opt)
919         {
920         case 0:
921           /* If getopt returns 0, then it has already processed a
922              long-named option.  We should do nothing.  */
923           break;
924
925         case 1:
926           /* This means that a file name has been seen.  Record it. */
927           argbuffer[current_arg].arg_type = at_filename;
928           argbuffer[current_arg].what = optarg;
929           ++current_arg;
930           ++file_count;
931           break;
932
933           /* Common options. */
934         case 'a': append_to_tagfile = TRUE;     break;
935         case 'C': cplusplus = TRUE;             break;
936         case 'd': constantypedefs = TRUE;       break;
937         case 'D': constantypedefs = FALSE;      break;
938         case 'f':               /* for compatibility with old makefiles */
939         case 'o':
940           if (tagfile)
941             {
942               /* convert char to string, to call error with */
943               char buf[2];
944               sprintf (buf, "%c", opt);
945               error ("-%s option may only be given once.", buf);
946               suggest_asking_for_help ();
947             }
948           tagfile = optarg;
949           break;
950 #ifdef OO_BROWSER
951         case 'O':
952           oo_browser_format = TRUE;
953           break;
954 #endif
955         case 'I':
956         case 'S':               /* for backward compatibility */
957           noindentypedefs = TRUE;
958           break;
959         case 'l':
960           {
961             language *lang = get_language_from_name (optarg);
962             if (lang != NULL)
963               {
964                 argbuffer[current_arg].lang = lang;
965                 argbuffer[current_arg].arg_type = at_language;
966                 ++current_arg;
967               }
968           }
969           break;
970 #ifdef ETAGS_REGEXPS
971         case 'r':
972           argbuffer[current_arg].arg_type = at_regexp;
973           argbuffer[current_arg].what = optarg;
974           ++current_arg;
975           break;
976         case 'R':
977           argbuffer[current_arg].arg_type = at_regexp;
978           argbuffer[current_arg].what = NULL;
979           ++current_arg;
980           break;
981 #endif /* ETAGS_REGEXPS */
982         case 'V':
983           print_version ();
984           break;
985         case 'h':
986         case 'H':
987           print_help ();
988           break;
989         case 't':
990           typedefs = TRUE;
991           break;
992         case 'T':
993           typedefs = typedefs_and_cplusplus = TRUE;
994           break;
995 #if (!CTAGS)
996           /* Etags options */
997         case 'i':
998           included_files[nincluded_files++] = optarg;
999           break;
1000 #else /* CTAGS */
1001           /* Ctags options. */
1002         case 'B': searchar = '?';       break;
1003         case 'u': update = TRUE;        break;
1004         case 'v': vgrind_style = TRUE;  /*FALLTHRU*/
1005         case 'x': cxref_style = TRUE;   break;
1006         case 'w': no_warnings = TRUE;   break;
1007 #endif /* CTAGS */
1008         default:
1009           suggest_asking_for_help ();
1010         }
1011     }
1012
1013   for (; optind < argc; ++optind)
1014     {
1015       argbuffer[current_arg].arg_type = at_filename;
1016       argbuffer[current_arg].what = argv[optind];
1017       ++current_arg;
1018       ++file_count;
1019     }
1020
1021   if (nincluded_files == 0 && file_count == 0)
1022     {
1023       error ("no input files specified.", 0);
1024       suggest_asking_for_help ();
1025     }
1026
1027   if (tagfile == NULL)
1028     tagfile = CTAGS ? "tags" : "TAGS";
1029   cwd = etags_getcwd ();        /* the current working directory */
1030   if (cwd[strlen (cwd) - 1] != '/')
1031     {
1032       char *oldcwd = cwd;
1033       cwd = concat (oldcwd, "/", "");
1034       free (oldcwd);
1035     }
1036   if (streq (tagfile, "-"))
1037     tagfiledir = cwd;
1038   else
1039     tagfiledir = absolute_dirname (tagfile, cwd);
1040
1041   init ();                      /* set up boolean "functions" */
1042
1043   initbuffer (&lb);
1044   initbuffer (&token_name);
1045   initbuffer (&lbs[0].lb);
1046   initbuffer (&lbs[1].lb);
1047   initbuffer (&filename_lb);
1048
1049   if (!CTAGS)
1050     {
1051       if (streq (tagfile, "-"))
1052         {
1053           tagf = stdout;
1054 #ifdef WIN32_NATIVE
1055           /* Switch redirected `stdout' to binary mode (setting `_fmode'
1056              doesn't take effect until after `stdout' is already open). */
1057           if (!isatty (fileno (stdout)))
1058             setmode (fileno (stdout), O_BINARY);
1059 #endif /* WIN32_NATIVE */
1060         }
1061       else
1062         tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1063       if (tagf == NULL)
1064         pfatal (tagfile);
1065     }
1066
1067   /*
1068    * Loop through files finding functions.
1069    */
1070   for (i = 0; i < current_arg; ++i)
1071     {
1072       switch (argbuffer[i].arg_type)
1073         {
1074         case at_language:
1075           forced_lang = argbuffer[i].lang;
1076           break;
1077 #ifdef ETAGS_REGEXPS
1078         case at_regexp:
1079           analyse_regex (argbuffer[i].what);
1080           break;
1081 #endif
1082         case at_filename:
1083 #ifdef VMS
1084           while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
1085             {
1086               if (got_err)
1087                 {
1088                   error ("can't find file %s\n", this_file);
1089                   argc--, argv++;
1090                 }
1091               else
1092                 {
1093                   this_file = massage_name (this_file);
1094                 }
1095 #else
1096               this_file = argbuffer[i].what;
1097 #endif
1098 #ifdef OO_BROWSER
1099               oo_browser_clear_all_globals();
1100 #endif
1101               /* Input file named "-" means read file names from stdin
1102                  (one per line) and use them. */
1103               if (streq (this_file, "-"))
1104                 while (readline_internal (&filename_lb, stdin) > 0)
1105 #ifdef OO_BROWSER
1106                   {
1107                     oo_browser_clear_some_globals();
1108 #endif
1109                   process_file (filename_lb.buffer);
1110 #ifdef OO_BROWSER
1111                   }
1112 #endif
1113               else
1114                 process_file (this_file);
1115 #ifdef VMS
1116             }
1117 #endif
1118           break;
1119         }
1120     }
1121
1122 #ifdef ETAGS_REGEXPS
1123   free_patterns ();
1124 #endif /* ETAGS_REGEXPS */
1125
1126   if (!CTAGS)
1127     {
1128       while (nincluded_files-- > 0)
1129         fprintf (tagf, "\f\n%s,include\n", *included_files++);
1130
1131       fclose (tagf);
1132       exit (GOOD);
1133     }
1134
1135   /* If CTAGS, we are here.  process_file did not write the tags yet,
1136      because we want them ordered.  Let's do it now. */
1137   if (cxref_style)
1138     {
1139       put_entries (head);
1140       exit (GOOD);
1141     }
1142
1143   if (update)
1144     {
1145       char cmd[BUFSIZ];
1146       for (i = 0; i < current_arg; ++i)
1147         {
1148           if (argbuffer[i].arg_type != at_filename)
1149             continue;
1150           sprintf (cmd,
1151                    "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1152                    tagfile, argbuffer[i].what, tagfile);
1153           if (system (cmd) != GOOD)
1154             fatal ("failed to execute shell command", (char *)NULL);
1155         }
1156       append_to_tagfile = TRUE;
1157     }
1158
1159   tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1160   if (tagf == NULL)
1161     pfatal (tagfile);
1162   put_entries (head);
1163   fclose (tagf);
1164
1165   if (update)
1166     {
1167       char cmd[BUFSIZ];
1168       sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
1169       exit (system (cmd));
1170     }
1171   return GOOD;
1172 }
1173
1174
1175 /*
1176  * Return a language given the name.
1177  */
1178 language *
1179 get_language_from_name (name)
1180      char *name;
1181 {
1182   language *lang;
1183
1184   if (name == NULL)
1185     error ("empty language name", (char *)NULL);
1186   else
1187     {
1188       for (lang = lang_names; lang->name != NULL; lang++)
1189         if (streq (name, lang->name))
1190           return lang;
1191       error ("unknown language \"%s\"", name);
1192     }
1193
1194   return NULL;
1195 }
1196
1197
1198 /*
1199  * Return a language given the interpreter name.
1200  */
1201 language *
1202 get_language_from_interpreter (interpreter)
1203      char *interpreter;
1204 {
1205   language *lang;
1206   char **iname;
1207
1208   if (interpreter == NULL)
1209     return NULL;
1210   for (lang = lang_names; lang->name != NULL; lang++)
1211     if (lang->interpreters != NULL)
1212       for (iname = lang->interpreters; *iname != NULL; iname++)
1213         if (streq (*iname, interpreter))
1214             return lang;
1215
1216   return NULL;
1217 }
1218
1219
1220
1221 /*
1222  * Return a language given the file suffix.
1223  */
1224 language *
1225 get_language_from_suffix (suffix)
1226      char *suffix;
1227 {
1228   language *lang;
1229   char **ext;
1230
1231   if (suffix == NULL)
1232     return NULL;
1233   for (lang = lang_names; lang->name != NULL; lang++)
1234     if (lang->suffixes != NULL)
1235       for (ext = lang->suffixes; *ext != NULL; ext++)
1236         if (streq (*ext, suffix))
1237             return lang;
1238
1239   return NULL;
1240 }
1241
1242
1243 /*
1244  * This routine is called on each file argument.
1245  */
1246 void
1247 process_file (file)
1248      char *file;
1249 {
1250   struct stat stat_buf;
1251   FILE *inf;
1252
1253   canonicalize_filename (file);
1254   if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
1255     {
1256       error ("skipping %s: it is not a regular file.", file);
1257       return;
1258     }
1259   if (streq (file, tagfile) && !streq (tagfile, "-"))
1260     {
1261       error ("skipping inclusion of %s in self.", file);
1262       return;
1263     }
1264   inf = fopen (file, "r");
1265   if (inf == NULL)
1266     {
1267       perror (file);
1268       return;
1269     }
1270
1271   find_entries (file, inf);
1272
1273   if (!CTAGS)
1274     {
1275       char *filename;
1276
1277       if (filename_is_absolute (file))
1278         {
1279           /* file is an absolute file name.  Canonicalise it. */
1280           filename = absolute_filename (file, cwd);
1281         }
1282       else
1283         {
1284           /* file is a file name relative to cwd.  Make it relative
1285              to the directory of the tags file. */
1286           filename = relative_filename (file, tagfiledir);
1287         }
1288 #ifdef OO_BROWSER
1289       if (oo_browser_format)
1290         fprintf (tagf, "\f\n%s\n", filename);
1291       else
1292 #endif
1293       fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1294       free (filename);
1295       put_entries (head);
1296       free_tree (head);
1297       head = NULL;
1298     }
1299 }
1300
1301 /*
1302  * This routine sets up the boolean pseudo-functions which work
1303  * by setting boolean flags dependent upon the corresponding character.
1304  * Every char which is NOT in that string is not a white char.  Therefore,
1305  * all of the array "_wht" is set to FALSE, and then the elements
1306  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
1307  * of a char is TRUE if it is the string "white", else FALSE.
1308  */
1309 void
1310 init ()
1311 {
1312   register char *sp;
1313   register int i;
1314
1315   for (i = 0; i < CHARS; i++)
1316     iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1317   for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1318   for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1319   for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1320   for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1321   for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1322   iswhite('\0') = iswhite('\n');
1323   notinname('\0') = notinname('\n');
1324   begtoken('\0') = begtoken('\n');
1325   intoken('\0') = intoken('\n');
1326   endtoken('\0') = endtoken('\n');
1327 }
1328
1329 /*
1330  * This routine opens the specified file and calls the function
1331  * which finds the function and type definitions.
1332  */
1333 node *last_node = NULL;
1334
1335 void
1336 find_entries (file, inf)
1337      char *file;
1338      FILE *inf;
1339 {
1340   char *cp;
1341   language *lang;
1342   node *old_last_node;
1343
1344   curfile = savestr (file);
1345
1346   /* If user specified a language, use it. */
1347   lang = forced_lang;
1348   if (lang != NULL && lang->function != NULL)
1349     {
1350       curlang = lang;
1351       lang->function (inf);
1352       free (curfile);
1353       fclose (inf);
1354       return;
1355     }
1356
1357   cp = etags_strrchr (file, '.');
1358   if (cp != NULL)
1359     {
1360       cp += 1;
1361       lang = get_language_from_suffix (cp);
1362       if (lang != NULL && lang->function != NULL)
1363         {
1364           curlang = lang;
1365           lang->function (inf);
1366           free (curfile);
1367           fclose (inf);
1368           return;
1369         }
1370     }
1371
1372   /* Look for sharp-bang as the first two characters. */
1373   if (readline_internal (&lb, inf) > 0
1374       && lb.len >= 2
1375       && lb.buffer[0] == '#'
1376       && lb.buffer[1] == '!')
1377     {
1378       char *lp;
1379
1380       /* Set lp to point at the first char after the last slash in the
1381          line or, if no slashes, at the first nonblank.  Then set cp to
1382          the first successive blank and terminate the string. */
1383       lp = etags_strrchr (lb.buffer+2, '/');
1384       if (lp != NULL)
1385         lp += 1;
1386       else
1387         lp = skip_spaces (lb.buffer + 2);
1388       cp = skip_non_spaces (lp);
1389       *cp = '\0';
1390
1391       if (strlen (lp) > 0)
1392         {
1393           lang = get_language_from_interpreter (lp);
1394           if (lang != NULL && lang->function != NULL)
1395             {
1396               curlang = lang;
1397               lang->function (inf);
1398               fclose (inf);
1399               free (curfile);
1400               return;
1401             }
1402         }
1403     }
1404   rewind (inf);
1405
1406   /* Try Fortran. */
1407   old_last_node = last_node;
1408   curlang = get_language_from_name ("fortran");
1409   Fortran_functions (inf);
1410
1411   /* No Fortran entries found.  Try C. */
1412   if (old_last_node == last_node)
1413     {
1414       rewind (inf);
1415       curlang = get_language_from_name (cplusplus ? "c++" : "c");
1416       default_C_entries (inf);
1417     }
1418   free (curfile);
1419   fclose (inf);
1420   return;
1421 }
1422 \f
1423 /* Record a tag. */
1424 void
1425 pfnote (name, is_func, linestart, linelen, lno, cno)
1426      char *name;                /* tag name, or NULL if unnamed */
1427      bool is_func;              /* tag is a function */
1428      char *linestart;           /* start of the line where tag is */
1429      int linelen;               /* length of the line where tag is */
1430      int lno;                   /* line number */
1431      long cno;                  /* character number */
1432 {
1433   register node *np;
1434
1435   if (CTAGS && name == NULL)
1436     return;
1437
1438   np = xnew (1, node);
1439
1440   /* If ctags mode, change name "main" to M<thisfilename>. */
1441   if (CTAGS && !cxref_style && streq (name, "main"))
1442     {
1443       register char *fp = etags_strrchr (curfile, '/');
1444       np->name = concat ("M", fp == 0 ? curfile : fp + 1, "");
1445       fp = etags_strrchr (np->name, '.');
1446       if (fp && fp[1] != '\0' && fp[2] == '\0')
1447         fp[0] = 0;
1448     }
1449   else
1450     np->name = name;
1451   np->been_warned = FALSE;
1452   np->file = curfile;
1453   np->is_func = is_func;
1454   np->lno = lno;
1455   /* Our char numbers are 0-base, because of C language tradition?
1456      ctags compatibility?  old versions compatibility?   I don't know.
1457      Anyway, since emacs's are 1-base we expect etags.el to take care
1458      of the difference.  If we wanted to have 1-based numbers, we would
1459      uncomment the +1 below. */
1460   np->cno = cno /* + 1 */ ;
1461   np->left = np->right = NULL;
1462   if (CTAGS && !cxref_style)
1463     {
1464       if (strlen (linestart) < 50)
1465         np->pat = concat (linestart, "$", "");
1466       else
1467         np->pat = savenstr (linestart, 50);
1468     }
1469   else
1470     np->pat = savenstr (linestart, linelen);
1471
1472 #ifdef OO_BROWSER
1473   if (oo_browser_format)
1474     np->construct = oo_browser_construct;
1475   oo_browser_construct = C_NULL;
1476   oo_browser_check_and_clear_structtype();
1477 #endif
1478
1479   add_node (np, &head);
1480 }
1481
1482 /* Date: Wed, 22 Jan 1997 02:56:31 -0500 [last amended 18 Sep 1997]
1483  * From: Sam Kendall <kendall@mv.mv.com>
1484  * Subject: Proposal for firming up the TAGS format specification
1485  * To: F.Potorti@cnuce.cnr.it
1486  *
1487  * pfnote should emit the optimized form [unnamed tag] only if:
1488  *  1. name does not contain any of the characters " \t\r\n(),;";
1489  *  2. linestart contains name as either a rightmost, or rightmost but
1490  *     one character, substring;
1491  *  3. the character, if any, immediately before name in linestart must
1492  *     be one of the characters " \t(),;";
1493  *  4. the character, if any, immediately after name in linestart must
1494  *     also be one of the characters " \t(),;".
1495  *
1496  * The real implementation uses the notinname() macro, which recognises
1497  * characters slightly different form " \t\r\n(),;".  See the variable
1498  * `nonam'.
1499  */
1500 #define traditional_tag_style TRUE
1501 void
1502 new_pfnote (name, namelen, is_func, linestart, linelen, lno, cno)
1503      char *name;                /* tag name, or NULL if unnamed */
1504      int namelen;               /* tag length */
1505      bool is_func;              /* tag is a function */
1506      char *linestart;           /* start of the line where tag is */
1507      int linelen;               /* length of the line where tag is */
1508      int lno;                   /* line number */
1509      long cno;                  /* character number */
1510 {
1511   register char *cp;
1512   bool named;
1513
1514   named = TRUE;
1515   if (!CTAGS)
1516     {
1517       for (cp = name; !notinname (*cp); cp++)
1518         continue;
1519       if (*cp == '\0')                          /* rule #1 */
1520         {
1521           cp = linestart + linelen - namelen;
1522           if (notinname (linestart[linelen-1]))
1523             cp -= 1;                            /* rule #4 */
1524 #ifdef OO_BROWSER
1525           if (!oo_browser_format
1526               && cp >= linestart                /* rule #2 */
1527 #else
1528           if (cp >= linestart                   /* rule #2 */
1529 #endif
1530               && (cp == linestart
1531                   || notinname (cp[-1]))        /* rule #3 */
1532               && strneq (name, cp, namelen))    /* rule #2 */
1533             named = FALSE;      /* use unnamed tag */
1534         }
1535     }
1536   
1537   if (named)
1538     name = savenstr (name, namelen);
1539   else
1540     name = NULL;
1541   pfnote (name, is_func, linestart, linelen, lno, cno);
1542 }
1543
1544 /*
1545  * free_tree ()
1546  *      recurse on left children, iterate on right children.
1547  */
1548 void
1549 free_tree (np)
1550      register node *np;
1551 {
1552   while (np)
1553     {
1554       register node *node_right = np->right;
1555       free_tree (np->left);
1556       if (np->name != NULL)
1557         free (np->name);
1558       free (np->pat);
1559       free (np);
1560       np = node_right;
1561     }
1562 }
1563
1564 /*
1565  * add_node ()
1566  *      Adds a node to the tree of nodes.  In etags mode, we don't keep
1567  *      it sorted; we just keep a linear list.  In ctags mode, maintain
1568  *      an ordered tree, with no attempt at balancing.
1569  *
1570  *      add_node is the only function allowed to add nodes, so it can
1571  *      maintain state.
1572  */
1573 void
1574 add_node (np, cur_node_p)
1575      node *np, **cur_node_p;
1576 {
1577   register int dif;
1578   register node *cur_node = *cur_node_p;
1579
1580   if (cur_node == NULL)
1581     {
1582       *cur_node_p = np;
1583       last_node = np;
1584       return;
1585     }
1586
1587   if (!CTAGS)
1588     {
1589       /* Etags Mode */
1590       if (last_node == NULL)
1591         fatal ("internal error in add_node", (char *)NULL);
1592       last_node->right = np;
1593       last_node = np;
1594     }
1595   else
1596     {
1597       /* Ctags Mode */
1598       dif = strcmp (np->name, cur_node->name);
1599
1600       /*
1601        * If this tag name matches an existing one, then
1602        * do not add the node, but maybe print a warning.
1603        */
1604       if (!dif)
1605         {
1606           if (streq (np->file, cur_node->file))
1607             {
1608               if (!no_warnings)
1609                 {
1610                   fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1611                            np->file, lineno, np->name);
1612                   fprintf (stderr, "Second entry ignored\n");
1613                 }
1614             }
1615           else if (!cur_node->been_warned && !no_warnings)
1616             {
1617               fprintf
1618                 (stderr,
1619                  "Duplicate entry in files %s and %s: %s (Warning only)\n",
1620                  np->file, cur_node->file, np->name);
1621               cur_node->been_warned = TRUE;
1622             }
1623           return;
1624         }
1625
1626       /* Actually add the node */
1627       add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
1628     }
1629 }
1630 \f
1631 #ifdef OO_BROWSER
1632 /* Default class name for the current OO-Browser tag. */
1633 static char *oo_browser_class;
1634 /* Prefix character to use in OO-Browser listings for the current tag. */
1635 static char oo_browser_prefix;
1636 #endif
1637
1638 void
1639 put_entries (node *np)
1640 {
1641   register char *sp;
1642
1643   if (np == NULL)
1644     return;
1645
1646   /* Output subentries that precede this one */
1647   put_entries (np->left);
1648
1649   /* Output this entry */
1650
1651   if (!CTAGS)
1652     {
1653 #ifdef OO_BROWSER
1654       if (oo_browser_format)
1655         {
1656           /* Omit C++ `class' and `method' entries as well as Objective-C
1657              entries from this OO-Browser tags file since the browser handles
1658              them independently of this file.  Omit `extern' variable declarations
1659              as they are unused by the OO-Browser. */
1660           if (np->construct != C_CLASS
1661               && np->construct != C_METHOD
1662               && np->construct != C_EXTERN
1663               && np->construct != C_OBJC)
1664             {
1665               oo_browser_class = oo_browser_default_classes[np->construct];
1666               switch (np->construct)
1667                 {
1668                 case C_CONSTANT:
1669                 case C_ENUMERATION:
1670                 case C_ENUM_LABEL:
1671                 case C_STRUCTURE:
1672                 case C_TYPE:
1673                 case C_UNION:
1674                 case C_VARIABLE:
1675                   oo_browser_prefix = '=';
1676                   break;
1677                 case C_FUNCTION:
1678                 case C_MACRO:
1679                   oo_browser_prefix = '-';
1680                   break;
1681                 }
1682               if (np->name != NULL)
1683                 fprintf (tagf, "%s@%c %s@%s\n",
1684                          oo_browser_class, oo_browser_prefix,
1685                          np->name, np->pat);
1686               else
1687                 fprintf (tagf, "%s@%c ???@%s\n",
1688                          oo_browser_class, oo_browser_prefix, np->pat);
1689             }
1690         }
1691       else
1692         {
1693 #endif
1694       if (np->name != NULL)
1695         fprintf (tagf, "%s\177%s\001%d,%ld\n",
1696                  np->pat, np->name, np->lno, np->cno);
1697       else
1698         fprintf (tagf, "%s\177%d,%ld\n",
1699                  np->pat, np->lno, np->cno);
1700 #ifdef OO_BROWSER
1701         }
1702 #endif
1703     }
1704   else
1705     {
1706       if (np->name == NULL)
1707         error ("internal error: NULL name in ctags mode.", (char *)NULL);
1708
1709       if (cxref_style)
1710         {
1711           if (vgrind_style)
1712             fprintf (stdout, "%s %s %d\n",
1713                      np->name, np->file, (np->lno + 63) / 64);
1714           else
1715             fprintf (stdout, "%-16s %3d %-16s %s\n",
1716                      np->name, np->lno, np->file, np->pat);
1717         }
1718       else
1719         {
1720           fprintf (tagf, "%s\t%s\t", np->name, np->file);
1721
1722           if (np->is_func)
1723             {                   /* a function */
1724               putc (searchar, tagf);
1725               putc ('^', tagf);
1726
1727               for (sp = np->pat; *sp; sp++)
1728                 {
1729                   if (*sp == '\\' || *sp == searchar)
1730                     putc ('\\', tagf);
1731                   putc (*sp, tagf);
1732                 }
1733               putc (searchar, tagf);
1734             }
1735           else
1736             {                   /* a typedef; text pattern inadequate */
1737               fprintf (tagf, "%d", np->lno);
1738             }
1739           putc ('\n', tagf);
1740         }
1741     }
1742
1743   /* Output subentries that follow this one */
1744   put_entries (np->right);
1745 }
1746
1747 /* Length of a number's decimal representation. */
1748 int number_len PP ((long num));
1749 int
1750 number_len (num)
1751      long num;
1752 {
1753   int len = 1;
1754   while ((num /= 10) > 0)
1755     len += 1;
1756   return len;
1757 }
1758
1759 /*
1760  * Return total number of characters that put_entries will output for
1761  * the nodes in the subtree of the specified node.  Works only if
1762  * we are not ctags, but called only in that case.  This count
1763  * is irrelevant with the new tags.el, but is still supplied for
1764  * backward compatibility.
1765  */
1766 int
1767 total_size_of_entries (np)
1768      register node *np;
1769 {
1770   register int total;
1771
1772   if (np == NULL)
1773     return 0;
1774
1775   for (total = 0; np != NULL; np = np->right)
1776     {
1777       /* Count left subentries. */
1778       total += total_size_of_entries (np->left);
1779
1780       /* Count this entry */
1781       total += strlen (np->pat) + 1;
1782       total += number_len ((long) np->lno) + 1 + number_len (np->cno) + 1;
1783       if (np->name != NULL)
1784         total += 1 + strlen (np->name); /* \001name */
1785     }
1786
1787   return total;
1788 }
1789 \f
1790 /*
1791  * The C symbol tables.
1792  */
1793 enum sym_type
1794 {
1795   st_none,
1796   st_C_objprot, st_C_objimpl, st_C_objend,
1797   st_C_gnumacro,
1798   st_C_ignore,
1799   st_C_javastruct,
1800   st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec,
1801   st_C_const
1802 #ifdef OO_BROWSER
1803   , st_C_union, st_C_class, st_C_extern, st_C_inline
1804 #endif
1805 };
1806
1807 /* Feed stuff between (but not including) %[ and %] lines to:
1808       gperf -c -k 1,3 -o -p -r -t
1809 %[
1810 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1811 %%
1812 @interface,     0,      st_C_objprot
1813 @protocol,      0,      st_C_objprot
1814 @implementation,0,      st_C_objimpl
1815 @end,           0,      st_C_objend
1816 import,         C_JAVA, st_C_ignore
1817 package,        C_JAVA, st_C_ignore
1818 friend,         C_PLPL, st_C_ignore
1819 extends,        C_JAVA, st_C_javastruct
1820 implements,     C_JAVA, st_C_javastruct
1821 interface,      C_JAVA, st_C_struct
1822 class,          C_PLPL, st_C_class
1823 namespace,      C_PLPL, st_C_struct
1824 domain,         C_STAR, st_C_struct
1825 union,          0,      st_C_union
1826 struct,         0,      st_C_struct
1827 enum,           0,      st_C_enum
1828 typedef,        0,      st_C_typedef
1829 define,         0,      st_C_define
1830 inline,         0,      st_C_inline
1831 bool,           C_PLPL, st_C_typespec
1832 long,           0,      st_C_typespec
1833 short,          0,      st_C_typespec
1834 int,            0,      st_C_typespec
1835 char,           0,      st_C_typespec
1836 float,          0,      st_C_typespec
1837 double,         0,      st_C_typespec
1838 signed,         0,      st_C_typespec
1839 unsigned,       0,      st_C_typespec
1840 auto,           0,      st_C_typespec
1841 void,           0,      st_C_typespec
1842 extern,         0,      st_C_extern
1843 static,         0,      st_C_typespec
1844 const,          0,      st_C_const
1845 volatile,       0,      st_C_typespec
1846 explicit,       C_PLPL, st_C_typespec
1847 mutable,        C_PLPL, st_C_typespec
1848 typename,       C_PLPL, st_C_typespec
1849 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
1850 DEFUN,          0,      st_C_gnumacro
1851 SYSCALL,        0,      st_C_gnumacro
1852 ENTRY,          0,      st_C_gnumacro
1853 PSEUDO,         0,      st_C_gnumacro
1854 # These are defined inside C functions, so currently they are not met.
1855 # EXFUN used in glibc, DEFVAR_* in emacs.
1856 #EXFUN,         0,      st_C_gnumacro
1857 #DEFVAR_,       0,      st_C_gnumacro
1858 %]
1859 and replace lines between %< and %> with its output. */
1860 /*%<*/
1861 /* C code produced by gperf version 2.5 (GNU C++ version) */
1862 /* Command-line: gperf -c -k 1,3 -o -p -r -t  */
1863 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1864
1865 #define TOTAL_KEYWORDS 41
1866 #define MIN_WORD_LENGTH 3
1867 #define MAX_WORD_LENGTH 15
1868 #define MIN_HASH_VALUE 13
1869 #define MAX_HASH_VALUE 129
1870 /* maximum key range = 117, duplicates = 0 */
1871
1872 static unsigned int
1873 hash (char *str, unsigned int len)
1874 {
1875   static unsigned char asso_values[] =
1876     {
1877      130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1878      130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1879      130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1880      130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1881      130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1882      130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1883      130, 130, 130, 130,  13, 130, 130, 130,  33,  32,
1884       47, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1885        5, 130, 130,  20,  32, 130, 130, 130, 130, 130,
1886      130, 130, 130, 130, 130, 130, 130,  47,  55,   8,
1887       15,  33,  61,  38, 130,  60, 130, 130,   2,   9,
1888       10,  62,  59, 130,  28,  27,  50,  19,   3, 130,
1889      130, 130, 130, 130, 130, 130, 130, 130,
1890     };
1891   return len +
1892     asso_values[(unsigned char) str[2]] +
1893     asso_values[(unsigned char) str[0]];
1894 }
1895
1896 static struct C_stab_entry *
1897 in_word_set (char *str, unsigned int len)
1898 {
1899   static struct C_stab_entry wordlist[] =
1900     {
1901       {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
1902       {"",}, {"",}, {"",}, {"",}, 
1903       {"volatile",      0,      st_C_typespec},
1904       {"",}, {"",}, 
1905       {"long",          0,      st_C_typespec},
1906       {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
1907       {"const",         0,      st_C_const},
1908       {"",}, {"",}, {"",}, 
1909       {"@end",          0,      st_C_objend},
1910       {"namespace",     C_PLPL, st_C_struct},
1911       {"",}, 
1912       {"domain",        C_STAR, st_C_struct},
1913       {"",}, {"",}, 
1914       {"@interface",    0,      st_C_objprot},
1915       {"",}, {"",}, {"",}, 
1916       {"@implementation", 0,    st_C_objimpl},
1917       {"",}, {"",}, 
1918       {"double",        0,      st_C_typespec},
1919       {"",}, {"",}, 
1920       {"PSEUDO",                0,      st_C_gnumacro},
1921       {"",}, {"",}, {"",}, 
1922       {"SYSCALL",       0,      st_C_gnumacro},
1923       {"",}, {"",}, 
1924       {"@protocol",     0,      st_C_objprot},
1925       {"",}, {"",}, {"",}, 
1926       {"unsigned",      0,      st_C_typespec},
1927       {"",}, 
1928       {"enum",          0,      st_C_enum},
1929       {"",}, {"",}, 
1930       {"char",          0,      st_C_typespec},
1931       {"class",         C_PLPL, st_C_class},
1932       {"struct",        0,      st_C_struct},
1933       {"",}, {"",}, {"",}, {"",}, 
1934       {"mutable",       C_PLPL, st_C_typespec},
1935       {"void",          0,      st_C_typespec},
1936       {"inline",                0,      st_C_inline},
1937       {"ENTRY",                 0,      st_C_gnumacro},
1938       {"",}, 
1939       {"signed",        0,      st_C_typespec},
1940       {"",}, {"",}, 
1941       {"package",       C_JAVA, st_C_ignore},
1942       {"",}, {"",}, {"",}, {"",}, {"",}, 
1943       {"static",        0,      st_C_typespec},
1944       {"",}, 
1945       {"define",        0,      st_C_define},
1946       {"",}, 
1947       {"union",         0,      st_C_union},
1948       {"DEFUN",                 0,      st_C_gnumacro},
1949       {"",}, {"",}, {"",}, 
1950       {"extern",        0,      st_C_extern},
1951       {"extends",       C_JAVA, st_C_javastruct},
1952       {"",}, {"",}, {"",}, 
1953       {"short",         0,      st_C_typespec},
1954       {"",}, {"",}, {"",}, {"",}, {"",}, 
1955       {"explicit",      C_PLPL, st_C_typespec},
1956       {"auto",          0,      st_C_typespec},
1957       {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
1958       {"",}, {"",}, 
1959       {"int",           0,      st_C_typespec},
1960       {"",}, {"",}, 
1961       {"typedef",       0,      st_C_typedef},
1962       {"typename",      C_PLPL, st_C_typespec},
1963       {"",}, 
1964       {"interface",     C_JAVA, st_C_struct},
1965       {"",}, 
1966       {"bool",          C_PLPL, st_C_typespec},
1967       {"",}, {"",}, {"",}, 
1968       {"import",                C_JAVA, st_C_ignore},
1969       {"",}, 
1970       {"friend",                C_PLPL, st_C_ignore},
1971       {"float",         0,      st_C_typespec},
1972       {"implements",    C_JAVA, st_C_javastruct},
1973     };
1974
1975   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1976     {
1977       register int key = hash (str, len);
1978
1979       if (key <= MAX_HASH_VALUE && key >= 0)
1980         {
1981           register char *s = wordlist[key].name;
1982
1983           if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
1984             return &wordlist[key];
1985         }
1986     }
1987   return 0;
1988 }
1989 /*%>*/
1990
1991 enum sym_type C_symtype PP ((char *str, int len, int c_ext));
1992 enum sym_type
1993 C_symtype (str, len, c_ext)
1994      char *str;
1995      int len;
1996      int c_ext;
1997 {
1998   register struct C_stab_entry *se = in_word_set (str, len);
1999
2000   if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2001     return st_none;
2002   return se->type;
2003 }
2004 \f
2005  /*
2006   * C functions and variables are recognized using a simple
2007   * finite automaton.  fvdef is its state variable.
2008   */
2009 enum
2010 {
2011   fvnone,                       /* nothing seen */
2012   fvnameseen,                   /* function or variable name seen */
2013   fstartlist,                   /* func: just after open parenthesis */
2014   finlist,                      /* func: in parameter list */
2015   flistseen,                    /* func: after parameter list */
2016   fignore,                      /* func: before open brace */
2017   vignore                       /* var-like: ignore until ';' */
2018 } fvdef;
2019
2020
2021  /*
2022   * typedefs are recognized using a simple finite automaton.
2023   * typdef is its state variable.
2024   */
2025 enum
2026 {
2027   tnone,                        /* nothing seen */
2028   ttypedseen,                   /* typedef keyword seen */
2029   tinbody,                      /* inside typedef body */
2030   tend,                         /* just before typedef tag */
2031   tignore                       /* junk after typedef tag */
2032 } typdef;
2033
2034
2035  /*
2036   * struct-like structures (enum, struct and union) are recognized
2037   * using another simple finite automaton.  `structdef' is its state
2038   * variable.
2039   */
2040 enum
2041 {
2042   snone,                        /* nothing seen yet */
2043   skeyseen,                     /* struct-like keyword seen */
2044   stagseen,                     /* struct-like tag seen */
2045   scolonseen,                   /* colon seen after struct-like tag */
2046   sinbody                       /* in struct body: recognize member func defs*/
2047 } structdef;
2048
2049 /*
2050  * When structdef is stagseen, scolonseen, or sinbody, structtag is the
2051  * struct tag, and structtype is the type of the preceding struct-like
2052  * keyword.
2053  */
2054 char *structtag = "<uninited>";
2055 enum sym_type structtype;
2056
2057 #ifdef OO_BROWSER
2058 void
2059 oo_browser_check_and_clear_structtype(void)
2060 {
2061   /* Allow for multiple enum_label tags. */
2062   if (structtype != st_C_enum)
2063     structtype = st_none;
2064 }
2065 #endif
2066
2067 /*
2068  * When objdef is different from onone, objtag is the name of the class.
2069  */
2070 char *objtag = "<uninited>";
2071
2072 /*
2073  * Yet another little state machine to deal with preprocessor lines.
2074  */
2075 enum
2076 {
2077   dnone,                        /* nothing seen */
2078   dsharpseen,                   /* '#' seen as first char on line */
2079   ddefineseen,                  /* '#' and 'define' seen */
2080   dignorerest                   /* ignore rest of line */
2081 } definedef;
2082
2083 /*
2084  * State machine for Objective C protocols and implementations.
2085  * Tom R.Hageman <tom@basil.icce.rug.nl>
2086  */
2087 enum
2088 {
2089   onone,                        /* nothing seen */
2090   oprotocol,                    /* @interface or @protocol seen */
2091   oimplementation,              /* @implementations seen */
2092   otagseen,                     /* class name seen */
2093   oparenseen,                   /* parenthesis before category seen */
2094   ocatseen,                     /* category name seen */
2095   oinbody,                      /* in @implementation body */
2096   omethodsign,                  /* in @implementation body, after +/- */
2097   omethodtag,                   /* after method name */
2098   omethodcolon,                 /* after method colon */
2099   omethodparm,                  /* after method parameter */
2100   oignore                       /* wait for @end */
2101 } objdef;
2102
2103 /*
2104  * Use this structure to keep info about the token read, and how it
2105  * should be tagged.  Used by the make_C_tag function to build a tag.
2106  */
2107 typedef struct
2108 {
2109   bool valid;
2110   char *str;
2111   bool named;
2112   int linelen;
2113   int lineno;
2114   long linepos;
2115   char *buffer;
2116 } token;
2117
2118 token tok;                      /* latest token read */
2119
2120 /*
2121  * Set this to TRUE, and the next token considered is called a function.
2122  * Used only for GNU emacs's function-defining macros.
2123  */
2124 bool next_token_is_func;
2125
2126 /*
2127  * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
2128  */
2129 bool yacc_rules;
2130
2131 /*
2132  * methodlen is the length of the method name stored in token_name.
2133  */
2134 int methodlen;
2135
2136 #ifdef OO_BROWSER
2137 void
2138 oo_browser_clear_all_globals(void)
2139 {
2140   /* Initialize globals so there is no carry over between files. */
2141   oo_browser_construct = C_NULL;
2142   fvdef = fvnone; typdef = tnone; structdef = snone;
2143   definedef = dnone; objdef = onone;
2144   structtype = st_none;
2145   next_token_is_func = yacc_rules = FALSE;
2146 }
2147
2148 void
2149 oo_browser_clear_some_globals(void)
2150 {
2151   oo_browser_construct = C_NULL;
2152   structtype = st_none;
2153 }
2154 #endif
2155
2156 /*
2157  * consider_token ()
2158  *      checks to see if the current token is at the start of a
2159  *      function or variable, or corresponds to a typedef, or
2160  *      is a struct/union/enum tag, or #define, or an enum constant.
2161  *
2162  *      *IS_FUNC gets TRUE iff the token is a function or #define macro
2163  *      with args.  C_EXT is which language we are looking at.
2164  *
2165  *      In the future we will need some way to adjust where the end of
2166  *      the token is; for instance, implementing the C++ keyword
2167  *      `operator' properly will adjust the end of the token to be after
2168  *      whatever follows `operator'.
2169  *
2170  * Globals
2171  *      fvdef                   IN OUT
2172  *      structdef               IN OUT
2173  *      definedef               IN OUT
2174  *      typdef                  IN OUT
2175  *      objdef                  IN OUT
2176  *      next_token_is_func      IN OUT
2177  */
2178 bool consider_token PP ((char *str, int len, int c, int c_ext,
2179                          int cblev, int parlev, bool *is_func_or_var));
2180 bool
2181 consider_token (str, len, c, c_ext, cblev, parlev, is_func_or_var)
2182      register char *str;        /* IN: token pointer */
2183      register int len;          /* IN: token length */
2184      register int c;            /* IN: first char after the token */
2185      int c_ext;                 /* IN: C extensions mask */
2186      int cblev;                 /* IN: curly brace level */
2187      int parlev;                /* IN: parenthesis level */
2188      bool *is_func_or_var;      /* OUT: function or variable found */
2189 {
2190   enum sym_type toktype = C_symtype (str, len, c_ext);
2191
2192 #ifdef OO_BROWSER
2193   switch (toktype)
2194     {
2195       case st_C_struct:
2196         set_construct(C_STRUCTURE);
2197         break;
2198       case st_C_union:
2199         set_construct(C_UNION);
2200         break;
2201       case st_C_class:
2202         set_construct(C_CLASS);
2203         break;
2204       case st_C_enum:
2205         set_construct(C_ENUMERATION);
2206         break;
2207       case st_C_typedef:
2208         set_construct(C_TYPE);
2209         break;
2210       case st_C_extern:
2211         set_construct(C_EXTERN);
2212         break;
2213       case st_C_inline:
2214         set_construct(C_FUNCTION);
2215         break;
2216     }
2217 #endif
2218
2219   /*
2220    * Advance the definedef state machine.
2221    */
2222   switch (definedef)
2223     {
2224     case dnone:
2225       /* We're not on a preprocessor line. */
2226       break;
2227     case dsharpseen:
2228       if (toktype == st_C_define)
2229         {
2230           definedef = ddefineseen;
2231         }
2232       else
2233         {
2234           definedef = dignorerest;
2235         }
2236       return FALSE;
2237     case ddefineseen:
2238       /*
2239        * Make a tag for any macro, unless it is a constant
2240        * and constantypedefs is FALSE.
2241        */
2242       definedef = dignorerest;
2243 #ifndef OO_BROWSER
2244       *is_func_or_var = (c == '(');
2245 #else
2246       {
2247         char *p = str + len * sizeof(char);
2248
2249         if (*p == '(')
2250           /* This must be a macro since there is no
2251              whitespace between the opening parenthesis
2252              and the definition name. */
2253           *is_func_or_var = TRUE;
2254         else
2255           {
2256             *is_func_or_var = FALSE;
2257
2258             /* Handle possible whitespace between macro tag and opening
2259                parenthesis and ensure this is an actual macro.
2260                -- Bob Weiner, Altrasoft, 11/19/1997 */
2261             while (*p && isspace(*p)) p++;
2262             if (*p) c = *p;
2263
2264             /* Skip over nested parentheses. */
2265             if (c == '(')
2266               {
2267                 short depth = 1;
2268
2269                 while (*++p && depth > 0 && *p != '\n')
2270                   {
2271                     switch (*p)
2272                       {
2273                       case '(':
2274                         depth++; break;
2275                       case ')':
2276                         depth--; break;
2277                       }
2278                   }
2279
2280                 /* If this is a macro, we have just passed
2281                    the arguments and there will be more on
2282                    the line before the NULL character that marks
2283                    the end of the line token. */
2284                 while (*p == ' ' || *p == '\t') p++;
2285                 if (*p) *is_func_or_var = TRUE;
2286               }
2287           }
2288       }
2289
2290       set_construct((*is_func_or_var) ? C_MACRO : C_CONSTANT);
2291 #endif
2292       if (!*is_func_or_var && !constantypedefs)
2293         return FALSE;
2294       else
2295         return TRUE;
2296     case dignorerest:
2297       return FALSE;
2298     default:
2299       error ("internal error: definedef value.", (char *)NULL);
2300     }
2301
2302   /*
2303    * Now typedefs
2304    */
2305   switch (typdef)
2306     {
2307     case tnone:
2308       if (toktype == st_C_typedef)
2309         {
2310           if (typedefs)
2311             typdef = ttypedseen;
2312           fvdef = fvnone;
2313           return FALSE;
2314         }
2315       break;
2316     case ttypedseen:
2317       switch (toktype)
2318         {
2319         case st_C_const:
2320           set_construct(C_CONSTANT);
2321           /* fall through */
2322         case st_none:
2323         case st_C_typespec:
2324 #ifdef OO_BROWSER
2325         case st_C_extern:
2326 #endif
2327           typdef = tend;
2328           break;
2329         case st_C_struct:
2330         case st_C_enum:
2331 #ifdef OO_BROWSER
2332         case st_C_union:
2333         case st_C_class:
2334 #endif
2335           break;
2336         }
2337       /* Do not return here, so the structdef stuff has a chance. */
2338       break;
2339     case tend:
2340       switch (toktype)
2341         {
2342         case st_C_const:
2343           set_construct(C_CONSTANT);
2344           /* fall through */
2345         case st_C_typespec:
2346         case st_C_struct:
2347         case st_C_enum:
2348 #ifdef OO_BROWSER
2349         case st_C_extern:
2350         case st_C_union:
2351         case st_C_class:
2352 #endif
2353           return FALSE;
2354         }
2355       return TRUE;
2356     }
2357
2358   /*
2359    * This structdef business is currently only invoked when cblev==0.
2360    * It should be recursively invoked whatever the curly brace level,
2361    * and a stack of states kept, to allow for definitions of structs
2362    * within structs.
2363    *
2364    * This structdef business is NOT invoked when we are ctags and the
2365    * file is plain C.  This is because a struct tag may have the same
2366    * name as another tag, and this loses with ctags.
2367    */
2368   switch (toktype)
2369     {
2370     case st_C_javastruct:
2371       if (structdef == stagseen)
2372         structdef = scolonseen;
2373       return FALSE;
2374     case st_C_struct:
2375     case st_C_enum:
2376 #ifdef OO_BROWSER
2377     case st_C_union:
2378     case st_C_class:
2379     case st_C_extern:
2380 #endif
2381       if (typdef == ttypedseen
2382           || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
2383         {
2384           structdef = skeyseen;
2385           structtype = toktype;
2386         }
2387       return FALSE;
2388     }
2389
2390   if (structdef == skeyseen)
2391     {
2392       /* Save the tag for struct/union/class, for functions and variables
2393          that may be defined inside. */
2394 #ifndef OO_BROWSER
2395       if (structtype == st_C_struct)
2396 #else
2397       if (structtype == st_C_struct
2398           || structtype == st_C_union
2399           || structtype == st_C_class)
2400 #endif
2401         structtag = savenstr (str, len);
2402       else
2403         structtag = "<enum>";
2404       structdef = stagseen;
2405       return TRUE;
2406     }
2407
2408   /* Avoid entering fvdef stuff if typdef is going on. */
2409   if (typdef != tnone)
2410     {
2411       definedef = dnone;
2412       return FALSE;
2413     }
2414
2415   /* Detect GNU macros.
2416
2417      DEFUN note for writers of emacs C code:
2418       The DEFUN macro, used in emacs C source code, has a first arg
2419      that is a string (the lisp function name), and a second arg that
2420      is a C function name.  Since etags skips strings, the second arg
2421      is tagged.  This is unfortunate, as it would be better to tag the
2422      first arg.  The simplest way to deal with this problem would be
2423      to name the tag with a name built from the function name, by
2424      removing the initial 'F' character and substituting '-' for '_'.
2425      Anyway, this assumes that the conventions of naming lisp
2426      functions will never change.  Currently, this method is not
2427      implemented, so writers of emacs code are recommended to put the
2428      first two args of a DEFUN on the same line. */
2429   if (definedef == dnone && toktype == st_C_gnumacro)
2430     {
2431       next_token_is_func = TRUE;
2432       return FALSE;
2433     }
2434   if (next_token_is_func)
2435     {
2436       next_token_is_func = FALSE;
2437       fvdef = fignore;
2438       *is_func_or_var = TRUE;
2439       return TRUE;
2440     }
2441
2442   /* Detect Objective C constructs. */
2443   switch (objdef)
2444     {
2445     case onone:
2446       switch (toktype)
2447         {
2448         case st_C_objprot:
2449 #ifdef OO_BROWSER
2450           set_construct(C_OBJC);
2451 #endif
2452           objdef = oprotocol;
2453           return FALSE;
2454         case st_C_objimpl:
2455 #ifdef OO_BROWSER
2456           set_construct(C_OBJC);
2457 #endif
2458           objdef = oimplementation;
2459           return FALSE;
2460         }
2461       break;
2462     case oimplementation:
2463       /* Save the class tag for functions or variables defined inside. */
2464       objtag = savenstr (str, len);
2465       objdef = oinbody;
2466       return FALSE;
2467     case oprotocol:
2468       /* Save the class tag for categories. */
2469       objtag = savenstr (str, len);
2470       objdef = otagseen;
2471       *is_func_or_var = TRUE;
2472       return TRUE;
2473     case oparenseen:
2474       objdef = ocatseen;
2475       *is_func_or_var = TRUE;
2476       return TRUE;
2477     case oinbody:
2478       break;
2479     case omethodsign:
2480       if (parlev == 0)
2481         {
2482           objdef = omethodtag;
2483           methodlen = len;
2484           grow_linebuffer (&token_name, methodlen + 1);
2485           strncpy (token_name.buffer, str, len);
2486           token_name.buffer[methodlen] = '\0';
2487           token_name.len = methodlen;
2488           return TRUE;
2489         }
2490       return FALSE;
2491     case omethodcolon:
2492       if (parlev == 0)
2493         objdef = omethodparm;
2494       return FALSE;
2495     case omethodparm:
2496       if (parlev == 0)
2497         {
2498           objdef = omethodtag;
2499           methodlen += len;
2500           grow_linebuffer (&token_name, methodlen + 1);
2501           strncat (token_name.buffer, str, len);
2502           token_name.len = methodlen;
2503           return TRUE;
2504         }
2505       return FALSE;
2506     case oignore:
2507       if (toktype == st_C_objend)
2508         {
2509           /* Memory leakage here: the string pointed by objtag is
2510              never released, because many tests would be needed to
2511              avoid breaking on incorrect input code.  The amount of
2512              memory leaked here is the sum of the lengths of the
2513              class tags.
2514           free (objtag); */
2515           objdef = onone;
2516         }
2517       return FALSE;
2518     }
2519
2520   /* A function, variable or enum constant? */
2521   switch (toktype)
2522     {
2523     case st_C_const:
2524       set_construct(C_CONSTANT);
2525       /* fall through */
2526     case st_C_typespec:
2527 #ifdef OO_BROWSER
2528     case st_C_extern:
2529 #endif
2530       if (fvdef != finlist && fvdef != fignore  && fvdef != vignore)
2531         fvdef = fvnone;         /* should be useless */
2532       return FALSE;
2533     case st_C_ignore:
2534       fvdef = vignore;
2535       return FALSE;
2536     case st_none:
2537       if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
2538 #ifdef OO_BROWSER
2539         {
2540           oo_browser_construct = C_ENUM_LABEL;
2541 #endif
2542         return TRUE;
2543 #ifdef OO_BROWSER
2544         }
2545 #endif
2546       if (fvdef == fvnone)
2547         {
2548           fvdef = fvnameseen;   /* function or variable */
2549           *is_func_or_var = TRUE;
2550           return TRUE;
2551         }
2552     }
2553
2554   return FALSE;
2555 }
2556
2557 /*
2558  * C_entries ()
2559  *      This routine finds functions, variables, typedefs,
2560  *      #define's, enum constants and struct/union/enum definitions in
2561  *      #C syntax and adds them to the list.
2562  */
2563 #define current_lb_is_new (newndx == curndx)
2564 #define switch_line_buffers() (curndx = 1 - curndx)
2565
2566 #define curlb (lbs[curndx].lb)
2567 #define othlb (lbs[1-curndx].lb)
2568 #define newlb (lbs[newndx].lb)
2569 #define curlinepos (lbs[curndx].linepos)
2570 #define othlinepos (lbs[1-curndx].linepos)
2571 #define newlinepos (lbs[newndx].linepos)
2572
2573 #define CNL_SAVE_DEFINEDEF()                                            \
2574 do {                                                                    \
2575   curlinepos = charno;                                                  \
2576   lineno++;                                                             \
2577   linecharno = charno;                                                  \
2578   charno += readline (&curlb, inf);                                     \
2579   lp = curlb.buffer;                                                    \
2580   quotednl = FALSE;                                                     \
2581   newndx = curndx;                                                      \
2582 } while (0)
2583
2584 #define CNL()                                                           \
2585 do {                                                                    \
2586   CNL_SAVE_DEFINEDEF();                                                 \
2587   if (savetok.valid)                                                    \
2588     {                                                                   \
2589       tok = savetok;                                                    \
2590       savetok.valid = FALSE;                                            \
2591     }                                                                   \
2592   definedef = dnone;                                                    \
2593 } while (0)
2594
2595
2596 void make_C_tag PP ((bool isfun));
2597 void
2598 make_C_tag (isfun)
2599      bool isfun;
2600 {
2601   /* This function should never be called when tok.valid is FALSE, but
2602      we must protect against invalid input or internal errors. */
2603   if (tok.valid)
2604     {
2605       if (traditional_tag_style)
2606         {
2607           /* This was the original code.  Now we call new_pfnote instead,
2608              which uses the new method for naming tags (see new_pfnote). */
2609           char *name = NULL;
2610
2611           if (CTAGS || tok.named)
2612             name = savestr (token_name.buffer);
2613           pfnote (name, isfun,
2614                   tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2615         }
2616       else
2617         new_pfnote (token_name.buffer, token_name.len, isfun,
2618                     tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2619       tok.valid = FALSE;
2620     }
2621   else if (DEBUG)
2622     abort ();
2623 }
2624
2625
2626 void
2627 C_entries (c_ext, inf)
2628      int c_ext;                 /* extension of C */
2629      FILE *inf;                 /* input file */
2630 {
2631   register char c;              /* latest char read; '\0' for end of line */
2632   register char *lp;            /* pointer one beyond the character `c' */
2633   int curndx, newndx;           /* indices for current and new lb */
2634   register int tokoff;          /* offset in line of start of current token */
2635   register int toklen;          /* length of current token */
2636   char *qualifier;              /* string used to qualify names */
2637   int qlen;                     /* length of qualifier */
2638   int cblev;                    /* current curly brace level */
2639   int parlev;                   /* current parenthesis level */
2640   bool incomm, inquote, inchar, quotednl, midtoken;
2641   bool cplpl, cjava;
2642   token savetok;                /* token saved during preprocessor handling */
2643
2644
2645   tokoff = toklen = 0;          /* keep compiler quiet */
2646   curndx = newndx = 0;
2647   lineno = 0;
2648   charno = 0;
2649   lp = curlb.buffer;
2650   *lp = 0;
2651
2652   fvdef = fvnone; typdef = tnone; structdef = snone;
2653   definedef = dnone; objdef = onone;
2654   next_token_is_func = yacc_rules = FALSE;
2655   midtoken = inquote = inchar = incomm = quotednl = FALSE;
2656   tok.valid = savetok.valid = FALSE;
2657   cblev = 0;
2658   parlev = 0;
2659   cplpl = (c_ext & C_PLPL) == C_PLPL;
2660   cjava = (c_ext & C_JAVA) == C_JAVA;
2661   if (cjava)
2662     { qualifier = "."; qlen = 1; }
2663   else
2664     { qualifier = "::"; qlen = 2; }
2665
2666   while (!feof (inf))
2667     {
2668       c = *lp++;
2669       if (c == '\\')
2670         {
2671           /* If we're at the end of the line, the next character is a
2672              '\0'; don't skip it, because it's the thing that tells us
2673              to read the next line.  */
2674           if (*lp == '\0')
2675             {
2676               quotednl = TRUE;
2677               continue;
2678             }
2679           lp++;
2680           c = ' ';
2681         }
2682       else if (incomm)
2683         {
2684           switch (c)
2685             {
2686             case '*':
2687               if (*lp == '/')
2688                 {
2689                   c = *lp++;
2690                   incomm = FALSE;
2691                 }
2692               break;
2693             case '\0':
2694               /* Newlines inside comments do not end macro definitions in
2695                  traditional cpp. */
2696               CNL_SAVE_DEFINEDEF ();
2697               break;
2698             }
2699           continue;
2700         }
2701       else if (inquote)
2702         {
2703           switch (c)
2704             {
2705             case '"':
2706               inquote = FALSE;
2707               break;
2708             case '\0':
2709               /* Newlines inside strings do not end macro definitions
2710                  in traditional cpp, even though compilers don't
2711                  usually accept them. */
2712               CNL_SAVE_DEFINEDEF ();
2713               break;
2714             }
2715           continue;
2716         }
2717       else if (inchar)
2718         {
2719           switch (c)
2720             {
2721             case '\0':
2722               /* Hmmm, something went wrong. */
2723               CNL ();
2724               /* FALLTHRU */
2725             case '\'':
2726               inchar = FALSE;
2727               break;
2728             }
2729           continue;
2730         }
2731       else
2732         switch (c)
2733           {
2734           case '"':
2735             inquote = TRUE;
2736             if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
2737               fvdef = fvnone;
2738             continue;
2739           case '\'':
2740             inchar = TRUE;
2741             if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
2742               fvdef = fvnone;
2743             continue;
2744           case '/':
2745             if (*lp == '*')
2746               {
2747                 lp++;
2748                 incomm = TRUE;
2749                 continue;
2750               }
2751             else if (/* cplpl && */ *lp == '/')
2752               {
2753                 c = '\0';
2754                 break;
2755               }
2756             else
2757               break;
2758           case '%':
2759             if ((c_ext & YACC) && *lp == '%')
2760               {
2761                 /* entering or exiting rules section in yacc file */
2762                 lp++;
2763                 definedef = dnone; fvdef = fvnone;
2764                 typdef = tnone; structdef = snone;
2765                 next_token_is_func = FALSE;
2766                 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2767                 cblev = 0;
2768                 yacc_rules = !yacc_rules;
2769                 continue;
2770               }
2771             else
2772               break;
2773           case '#':
2774             if (definedef == dnone)
2775               {
2776                 char *cp;
2777                 bool cpptoken = TRUE;
2778
2779                 /* Look back on this line.  If all blanks, or nonblanks
2780                    followed by an end of comment, this is a preprocessor
2781                    token. */
2782                 for (cp = newlb.buffer; cp < lp-1; cp++)
2783                   if (!iswhite (*cp))
2784                     {
2785                       if (*cp == '*' && *(cp+1) == '/')
2786                         {
2787                           cp++;
2788                           cpptoken = TRUE;
2789                         }
2790                       else
2791                         cpptoken = FALSE;
2792                     }
2793                 if (cpptoken)
2794                   definedef = dsharpseen;
2795               } /* if (definedef == dnone) */
2796
2797             continue;
2798           } /* switch (c) */
2799
2800
2801       /* Consider token only if some complicated conditions are satisfied. */
2802       if ((definedef != dnone
2803            || (cblev == 0 && structdef != scolonseen)
2804            || (cblev == 1 && cplpl && structdef == sinbody)
2805            || (structdef == sinbody && structtype == st_C_enum))
2806           && typdef != tignore
2807           && definedef != dignorerest
2808           && fvdef != finlist)
2809         {
2810           if (midtoken)
2811             {
2812               if (endtoken (c))
2813                 {
2814                   if (c == ':' && cplpl && *lp == ':' && begtoken(*(lp + 1)))
2815                     {
2816                       /*
2817                        * This handles :: in the middle, but not at the
2818                        * beginning of an identifier.
2819                        */
2820                       lp += 2;
2821                       toklen += 3;
2822 #ifdef OO_BROWSER
2823                       set_construct(C_METHOD);
2824 #endif
2825                     }
2826                   else
2827                     {
2828                       bool funorvar = FALSE;
2829
2830                       if (yacc_rules
2831                           || consider_token (newlb.buffer + tokoff, toklen, c,
2832                                              c_ext, cblev, parlev, &funorvar))
2833                         {
2834                           tok.named = FALSE;
2835                           if (structdef == sinbody
2836                               && definedef == dnone
2837                               && funorvar)
2838                             /* function or var defined in C++ class body */
2839                             {
2840                               int len = strlen (structtag) + qlen + toklen;
2841                               grow_linebuffer (&token_name, len + 1);
2842                               strcpy (token_name.buffer, structtag);
2843                               strcat (token_name.buffer, qualifier);
2844                               strncat (token_name.buffer,
2845                                        newlb.buffer + tokoff, toklen);
2846                               token_name.len = len;
2847                               tok.named = TRUE;
2848 #ifdef OO_BROWSER
2849                               oo_browser_construct = C_METHOD;
2850 #endif
2851                             }
2852                           else if (objdef == ocatseen)
2853                             /* Objective C category */
2854                             {
2855                               int len = strlen (objtag) + 2 + toklen;
2856                               grow_linebuffer (&token_name, len + 1);
2857                               strcpy (token_name.buffer, objtag);
2858                               strcat (token_name.buffer, "(");
2859                               strncat (token_name.buffer,
2860                                        newlb.buffer + tokoff, toklen);
2861                               strcat (token_name.buffer, ")");
2862                               token_name.len = len;
2863                               tok.named = TRUE;
2864 #ifdef OO_BROWSER
2865                               oo_browser_construct = C_OBJC;
2866 #endif
2867                             }
2868                           else if (objdef == omethodtag
2869                                    || objdef == omethodparm)
2870                             /* Objective C method */
2871                             {
2872                               tok.named = TRUE;
2873 #ifdef OO_BROWSER
2874                               oo_browser_construct = C_OBJC;
2875 #endif
2876                             }
2877                           else
2878                             {
2879                               grow_linebuffer (&token_name, toklen + 1);
2880                               strncpy (token_name.buffer,
2881                                        newlb.buffer + tokoff, toklen);
2882                               token_name.buffer[toklen] = '\0';
2883                               token_name.len = toklen;
2884                               /* Name macros. */
2885                               tok.named
2886                                 = (structdef == stagseen
2887                                    || typdef == tend
2888 #ifdef OO_BROWSER
2889                                    /* Also name #define constants,
2890                                       enumerations and enum_labels.
2891                                       Conditionalize `funorvar' reference
2892                                       here or #defines will appear without
2893                                       their #names.
2894                                       -- Bob Weiner, Altrasoft, 4/25/1998 */
2895                                    || ((oo_browser_format || funorvar)
2896                                        && definedef == dignorerest)
2897                                    || (oo_browser_format
2898                                        && (oo_browser_construct == C_ENUMERATION
2899                                            || oo_browser_construct == C_ENUM_LABEL))
2900 #else
2901                                    || (funorvar
2902                                        && definedef == dignorerest)
2903 #endif
2904                                    );
2905                             }
2906                           tok.lineno = lineno;
2907                           tok.linelen = tokoff + toklen + 1;
2908                           tok.buffer = newlb.buffer;
2909                           tok.linepos = newlinepos;
2910                           tok.valid = TRUE;
2911
2912                           if (definedef == dnone
2913                               && (fvdef == fvnameseen
2914                                   || structdef == stagseen
2915                                   || typdef == tend
2916                                   || objdef != onone))
2917                             {
2918                               if (current_lb_is_new)
2919                                 switch_line_buffers ();
2920                             }
2921                           else
2922                             make_C_tag (funorvar);
2923                         }
2924                       midtoken = FALSE;
2925                     }
2926                 } /* if (endtoken (c)) */
2927               else if (intoken (c))
2928                 {
2929                   toklen++;
2930                   continue;
2931                 }
2932             } /* if (midtoken) */
2933           else if (begtoken (c))
2934             {
2935               switch (definedef)
2936                 {
2937                 case dnone:
2938                   switch (fvdef)
2939                     {
2940                     case fstartlist:
2941                       fvdef = finlist;
2942                       continue;
2943                     case flistseen:
2944 #ifdef OO_BROWSER
2945                       set_construct(C_MACRO);
2946 #endif
2947                       make_C_tag (TRUE); /* a function */
2948                       fvdef = fignore;
2949                       break;
2950                     case fvnameseen:
2951                       fvdef = fvnone;
2952                       break;
2953                     }
2954                   if (structdef == stagseen && !cjava)
2955                     structdef = snone;
2956                   break;
2957                 case dsharpseen:
2958                   savetok = tok;
2959                 }
2960               if (!yacc_rules || lp == newlb.buffer + 1)
2961                 {
2962                   tokoff = lp - 1 - newlb.buffer;
2963                   toklen = 1;
2964                   midtoken = TRUE;
2965                 }
2966               continue;
2967             } /* if (begtoken) */
2968         } /* if must look at token */
2969
2970
2971       /* Detect end of line, colon, comma, semicolon and various braces
2972          after having handled a token.*/
2973       switch (c)
2974         {
2975         case ':':
2976           if (definedef != dnone)
2977             break;
2978           switch (objdef)
2979             {
2980             case  otagseen:
2981               objdef = oignore;
2982               make_C_tag (TRUE); /* an Objective C class */
2983               break;
2984             case omethodtag:
2985             case omethodparm:
2986               objdef = omethodcolon;
2987               methodlen += 1;
2988               grow_linebuffer (&token_name, methodlen + 1);
2989               strcat (token_name.buffer, ":");
2990               token_name.len = methodlen;
2991               break;
2992             }
2993           if (structdef == stagseen)
2994             structdef = scolonseen;
2995           else
2996             switch (fvdef)
2997               {
2998               case fvnameseen:
2999                 if (yacc_rules)
3000                   {
3001                     make_C_tag (FALSE); /* a yacc function */
3002                     fvdef = fignore;
3003                   }
3004                 break;
3005               case fstartlist:
3006                 fvdef = fvnone;
3007                 break;
3008               }
3009           break;
3010         case ';':
3011           if (definedef != dnone)
3012             break;
3013           if (cblev == 0)
3014             switch (typdef)
3015               {
3016               case tend:
3017 #ifdef OO_BROWSER
3018                 set_construct(C_TYPE);
3019 #endif
3020                 make_C_tag (FALSE); /* a typedef */
3021                 /* FALLTHRU */
3022               default:
3023                 typdef = tnone;
3024               }
3025           switch (fvdef)
3026             {
3027             case fignore:
3028               break;
3029             case fvnameseen:
3030               if ((globals && cblev == 0) || (members && cblev == 1))
3031 #ifndef OO_BROWSER
3032                 make_C_tag (FALSE); /* a variable */
3033 #else
3034 /*            if (constantypedefs && structdef == snone)*/
3035                 {
3036                   tok.named = TRUE;
3037                   switch (structtype)
3038                     {
3039                       case st_C_enum:
3040                         set_construct(C_ENUMERATION);
3041                         break;
3042                       case st_C_class:
3043                         set_construct(C_CLASS);
3044                         break;
3045                       default:
3046                         set_construct(C_VARIABLE);
3047                         break;
3048                     }
3049                   make_C_tag (FALSE);
3050                   /* Force reset of st_C_enum structtype value. */
3051                   structtype = st_none;
3052                 }
3053 #endif
3054               /* FALLTHRU */
3055             default:
3056               fvdef = fvnone;
3057               /* The following instruction invalidates the token.
3058                  Probably the token should be invalidated in all
3059                  other cases  where some state machine is reset. */
3060               tok.valid = FALSE;
3061             }
3062           if (structdef == stagseen)
3063             structdef = snone;
3064           break;
3065         case ',':
3066           if (definedef != dnone)
3067             break;
3068           switch (objdef)
3069             {
3070             case omethodtag:
3071             case omethodparm:
3072               make_C_tag (TRUE); /* an Objective C method */
3073               objdef = oinbody;
3074               break;
3075             }
3076           switch (fvdef)
3077             {
3078             case finlist:
3079             case fignore:
3080             case vignore:
3081               break;
3082             case fvnameseen:
3083               if ((globals && cblev == 0) || (members && cblev == 1))
3084                 make_C_tag (FALSE); /* a variable */
3085               break;
3086             default:
3087               fvdef = fvnone;
3088             }
3089           if (structdef == stagseen)
3090             structdef = snone;
3091           break;
3092         case '[':
3093           if (definedef != dnone)
3094             break;
3095           if (cblev == 0 && typdef == tend)
3096             {
3097 #ifdef OO_BROWSER
3098               set_construct(C_TYPE);
3099 #endif
3100               typdef = tignore;
3101               make_C_tag (FALSE);       /* a typedef */
3102               break;
3103             }
3104           switch (fvdef)
3105             {
3106             case finlist:
3107             case fignore:
3108             case vignore:
3109               break;
3110             case fvnameseen:
3111 #ifndef OO_BROWSER
3112               if ((globals && cblev == 0) || (members && cblev == 1))
3113                 make_C_tag (FALSE); /* a variable */
3114 #else
3115               if (constantypedefs && structdef == snone)
3116                 {
3117                   tok.named = TRUE;
3118                   switch (structtype)
3119                     {
3120                       case st_C_enum:
3121                         set_construct(C_ENUMERATION);
3122                         break;
3123                       case st_C_class:
3124                         set_construct(C_CLASS);
3125                         break;
3126                       default:
3127                         set_construct(C_VARIABLE);
3128                         break;
3129                     }
3130                   make_C_tag (FALSE);
3131                   /* Force reset of st_C_enum structtype value. */
3132                   structtype = st_none;
3133                 }
3134 #endif
3135               /* FALLTHRU */
3136             default:
3137               fvdef = fvnone;
3138             }
3139           if (structdef == stagseen)
3140             structdef = snone;
3141           break;
3142         case '(':
3143           if (definedef != dnone)
3144             break;
3145           if (objdef == otagseen && parlev == 0)
3146             objdef = oparenseen;
3147           switch (fvdef)
3148             {
3149             case fvnone:
3150               switch (typdef)
3151                 {
3152                 case ttypedseen:
3153                 case tend:
3154                   if (tok.valid && *lp != '*')
3155                     {
3156                       /* This handles constructs like:
3157                          typedef void OperatorFun (int fun); */
3158                       typdef = tignore;
3159 #ifdef OO_BROWSER
3160                       set_construct(C_TYPE);
3161 #endif
3162                       make_C_tag (FALSE);
3163                     }
3164                   break;
3165                 } /* switch (typdef) */
3166               break;
3167             case fvnameseen:
3168               fvdef = fstartlist;
3169               break;
3170             case flistseen:
3171               fvdef = finlist;
3172               break;
3173             }
3174           parlev++;
3175           break;
3176         case ')':
3177           if (definedef != dnone)
3178             break;
3179           if (objdef == ocatseen && parlev == 1)
3180             {
3181               make_C_tag (TRUE); /* an Objective C category */
3182               objdef = oignore;
3183             }
3184           if (--parlev == 0)
3185             {
3186               switch (fvdef)
3187                 {
3188                 case fstartlist:
3189                 case finlist:
3190                   fvdef = flistseen;
3191                   break;
3192                 }
3193               if (cblev == 0 && typdef == tend)
3194                 {
3195 #ifdef OO_BROWSER
3196                   set_construct(C_TYPE);
3197 #endif
3198                   typdef = tignore;
3199                   make_C_tag (FALSE); /* a typedef */
3200                 }
3201             }
3202           else if (parlev < 0)  /* can happen due to ill-conceived #if's. */
3203             parlev = 0;
3204           break;
3205         case '{':
3206           if (definedef != dnone)
3207             break;
3208           if (typdef == ttypedseen)
3209             typdef = tinbody;
3210           switch (structdef)
3211             {
3212             case skeyseen:      /* unnamed struct */
3213               structdef = sinbody;
3214               structtag = "_anonymous_";
3215               break;
3216             case stagseen:
3217             case scolonseen:    /* named struct */
3218               structdef = sinbody;
3219               make_C_tag (FALSE);       /* a struct */
3220               break;
3221             }
3222           switch (fvdef)
3223             {
3224             case flistseen:
3225 #ifdef OO_BROWSER
3226               set_construct(C_FUNCTION);
3227               /* Ensure function name is recorded.
3228                  -- Bob Weiner, Altrasoft */
3229               tok.named = TRUE;
3230 #endif
3231               make_C_tag (TRUE); /* a function */
3232               /* FALLTHRU */
3233             case fignore:
3234               fvdef = fvnone;
3235               break;
3236             case fvnone:
3237               switch (objdef)
3238                 {
3239                 case otagseen:
3240                   make_C_tag (TRUE); /* an Objective C class */
3241                   objdef = oignore;
3242                   break;
3243                 case omethodtag:
3244                 case omethodparm:
3245                   make_C_tag (TRUE); /* an Objective C method */
3246                   objdef = oinbody;
3247                   break;
3248                 default:
3249                   /* Neutralize `extern "C" {' grot. */
3250                   if (cblev == 0 && structdef == snone && typdef == tnone)
3251                     cblev = -1;
3252                 }
3253             }
3254           cblev++;
3255           break;
3256         case '*':
3257           if (definedef != dnone)
3258             break;
3259           if (fvdef == fstartlist)
3260             fvdef = fvnone;     /* avoid tagging `foo' in `foo (*bar()) ()' */
3261           break;
3262         case '}':
3263           if (definedef != dnone)
3264             break;
3265           if (!noindentypedefs && lp == newlb.buffer + 1)
3266             {
3267               cblev = 0;        /* reset curly brace level if first column */
3268               parlev = 0;       /* also reset paren level, just in case... */
3269             }
3270           else if (cblev > 0)
3271             cblev--;
3272           if (cblev == 0)
3273             {
3274               if (typdef == tinbody)
3275                 typdef = tend;
3276               /* Memory leakage here: the string pointed by structtag is
3277                  never released, because I fear to miss something and
3278                  break things while freeing the area.  The amount of
3279                  memory leaked here is the sum of the lengths of the
3280                  struct tags.
3281               if (structdef == sinbody)
3282                 free (structtag); */
3283
3284               structdef = snone;
3285               structtag = "<error>";
3286 #ifdef OO_BROWSER
3287               /* Next line added to avoid any state carryover between
3288                  functions. -- Bob Weiner, Altrasoft, 11/19/1997 */
3289               fvdef = fvnone; oo_browser_construct = C_NULL;
3290 #endif
3291             }
3292           break;
3293         case '=':
3294           if (definedef != dnone)
3295             break;
3296 #ifdef OO_BROWSER
3297           {
3298             int is_method = 0;
3299 #endif
3300           switch (fvdef)
3301             {
3302             case finlist:
3303             case fignore:
3304             case vignore:
3305               break;
3306             case fvnameseen:
3307               if ((globals && cblev == 0) || (members && cblev == 1))
3308 #ifndef OO_BROWSER
3309                 make_C_tag (FALSE); /* a variable */
3310 #else
3311                 {
3312                   tok.named = TRUE;
3313                   switch (structtype)
3314                     {
3315                       case st_C_enum:
3316                         set_construct(C_ENUMERATION);
3317                         break;
3318                       case st_C_class:
3319                         set_construct(C_CLASS);
3320                         break;
3321                       default:
3322                         /* a global variable */
3323                         set_construct(C_VARIABLE);
3324                         break;
3325                     }
3326
3327                   /* ootags categorizes each tag found whereas etags doesn't.
3328                      Set the is_method flag if this tag has been marked as
3329                      such by an earlier section of code.
3330                      -- Steve Baur, Altrasoft, 5/7/1998 */
3331                   is_method = (oo_browser_construct == C_METHOD);
3332
3333                   make_C_tag (FALSE);
3334                   /* Force reset of st_C_enum structtype value. */
3335                   structtype = st_none;
3336                 }
3337 #endif
3338               /* FALLTHRU */
3339             default:
3340 #ifdef OO_BROWSER
3341               fvdef = is_method ? fignore : vignore;
3342 #else
3343               fvdef = vignore;
3344 #endif
3345             }
3346 #ifdef OO_BROWSER
3347           }
3348 #endif
3349           break;
3350         case '+':
3351         case '-':
3352           if (objdef == oinbody && cblev == 0)
3353             {
3354               objdef = omethodsign;
3355               break;
3356             }
3357           /* FALLTHRU */
3358         case '#': case '~': case '&': case '%': case '/': case '|':
3359         case '^': case '!': case '<': case '>': case '.': case '?': case ']':
3360           if (definedef != dnone)
3361             break;
3362 #ifdef OO_BROWSER
3363           if (!cplpl)
3364             {
3365 #endif
3366               /* The above characters cannot follow a function tag in C, so
3367                  unmark this as a function entry.  For C++, these characters
3368                  may follow an `operator' function construct, so skip the
3369                  unmarking conditional below.
3370                  -- Steve Baur, Altrasoft, 5/7/1998 */
3371               if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
3372                 fvdef = fvnone;
3373 #ifdef OO_BROWSER
3374             }
3375 #endif
3376           break;
3377         case '\0':
3378           if (objdef == otagseen)
3379             {
3380               make_C_tag (TRUE); /* an Objective C class */
3381               objdef = oignore;
3382             }
3383           /* If a macro spans multiple lines don't reset its state. */
3384           if (quotednl)
3385             CNL_SAVE_DEFINEDEF ();
3386           else
3387             CNL ();
3388           break;
3389         } /* switch (c) */
3390
3391     } /* while not eof */
3392 }
3393
3394 /*
3395  * Process either a C++ file or a C file depending on the setting
3396  * of a global flag.
3397  */
3398 void
3399 default_C_entries (inf)
3400      FILE *inf;
3401 {
3402   C_entries (cplusplus ? C_PLPL : 0, inf);
3403 }
3404
3405 /* Always do plain ANSI C. */
3406 void
3407 plain_C_entries (inf)
3408      FILE *inf;
3409 {
3410   C_entries (0, inf);
3411 }
3412
3413 /* Always do C++. */
3414 void
3415 Cplusplus_entries (inf)
3416      FILE *inf;
3417 {
3418   C_entries (C_PLPL, inf);
3419 }
3420
3421 /* Always do Java. */
3422 void
3423 Cjava_entries (inf)
3424      FILE *inf;
3425 {
3426   C_entries (C_JAVA, inf);
3427 }
3428
3429 /* Always do C*. */
3430 void
3431 Cstar_entries (inf)
3432      FILE *inf;
3433 {
3434   C_entries (C_STAR, inf);
3435 }
3436
3437 /* Always do Yacc. */
3438 void
3439 Yacc_entries (inf)
3440      FILE *inf;
3441 {
3442   C_entries (YACC, inf);
3443 }
3444 \f
3445 /* A useful macro. */  
3446 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer)    \
3447   for (lineno = charno = 0;     /* loop initialization */               \
3448        !feof (file_pointer)     /* loop test */                         \
3449        && (lineno++,            /* instructions at start of loop */     \
3450            linecharno = charno,                                         \
3451            charno += readline (&line_buffer, file_pointer),             \
3452            char_pointer = lb.buffer,                                    \
3453            TRUE);                                                       \
3454       )
3455
3456
3457 /*
3458  * Read a file, but do no processing.  This is used to do regexp
3459  * matching on files that have no language defined.
3460  */
3461 void
3462 just_read_file (inf)
3463      FILE *inf;
3464 {
3465   register char *dummy;
3466
3467   LOOP_ON_INPUT_LINES (inf, lb, dummy)
3468     continue;
3469 }
3470 \f
3471 /* Fortran parsing */
3472
3473 bool tail PP ((char *cp));
3474 bool
3475 tail (cp)
3476      char *cp;
3477 {
3478   register int len = 0;
3479
3480   while (*cp && lowcase(*cp) == lowcase(dbp[len]))
3481     cp++, len++;
3482   if (*cp == '\0' && !intoken(dbp[len]))
3483     {
3484       dbp += len;
3485       return TRUE;
3486     }
3487   return FALSE;
3488 }
3489
3490 void
3491 takeprec ()
3492 {
3493   dbp = skip_spaces (dbp);
3494   if (*dbp != '*')
3495     return;
3496   dbp++;
3497   dbp = skip_spaces (dbp);
3498   if (strneq (dbp, "(*)", 3))
3499     {
3500       dbp += 3;
3501       return;
3502     }
3503   if (!isdigit (*dbp))
3504     {
3505       --dbp;                    /* force failure */
3506       return;
3507     }
3508   do
3509     dbp++;
3510   while (isdigit (*dbp));
3511 }
3512
3513 void getit PP ((FILE *inf));
3514 void
3515 getit (inf)
3516      FILE *inf;
3517 {
3518   register char *cp;
3519
3520   dbp = skip_spaces (dbp);
3521   if (*dbp == '\0')
3522     {
3523       lineno++;
3524       linecharno = charno;
3525       charno += readline (&lb, inf);
3526       dbp = lb.buffer;
3527       if (dbp[5] != '&')
3528         return;
3529       dbp += 6;
3530       dbp = skip_spaces (dbp);
3531     }
3532   if (!isalpha (*dbp)
3533       && *dbp != '_'
3534       && *dbp != '$')
3535     return;
3536   for (cp = dbp + 1; *cp && intoken (*cp); cp++)
3537     continue;
3538   pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
3539           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3540 }
3541
3542
3543 void
3544 Fortran_functions (inf)
3545      FILE *inf;
3546 {
3547   LOOP_ON_INPUT_LINES (inf, lb, dbp)
3548     {
3549       if (*dbp == '%')
3550         dbp++;                  /* Ratfor escape to fortran */
3551       dbp = skip_spaces (dbp);
3552       if (*dbp == '\0')
3553         continue;
3554       switch (lowcase (*dbp))
3555         {
3556         case 'i':
3557           if (tail ("integer"))
3558             takeprec ();
3559           break;
3560         case 'r':
3561           if (tail ("real"))
3562             takeprec ();
3563           break;
3564         case 'l':
3565           if (tail ("logical"))
3566             takeprec ();
3567           break;
3568         case 'c':
3569           if (tail ("complex") || tail ("character"))
3570             takeprec ();
3571           break;
3572         case 'd':
3573           if (tail ("double"))
3574             {
3575               dbp = skip_spaces (dbp);
3576               if (*dbp == '\0')
3577                 continue;
3578               if (tail ("precision"))
3579                 break;
3580               continue;
3581             }
3582           break;
3583         }
3584       dbp = skip_spaces (dbp);
3585       if (*dbp == '\0')
3586         continue;
3587       switch (lowcase (*dbp))
3588         {
3589         case 'f':
3590           if (tail ("function"))
3591             getit (inf);
3592           continue;
3593         case 's':
3594           if (tail ("subroutine"))
3595             getit (inf);
3596           continue;
3597         case 'e':
3598           if (tail ("entry"))
3599             getit (inf);
3600           continue;
3601         case 'p':
3602           if (tail ("program"))
3603             {
3604               getit (inf);
3605               continue;
3606             }
3607           if (tail ("procedure"))
3608             getit (inf);
3609           continue;
3610         }
3611     }
3612 }
3613 \f
3614 /*
3615  * Bob Weiner, Motorola Inc., 4/3/94
3616  * Unix and microcontroller assembly tag handling
3617  * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3618  */
3619 void
3620 Asm_labels (FILE *inf)
3621 {
3622   register char *cp;
3623
3624   LOOP_ON_INPUT_LINES (inf, lb, cp)
3625     {
3626       /* If first char is alphabetic or one of [_.$], test for colon
3627          following identifier. */
3628       if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3629         {
3630           /* Read past label. */
3631           cp++;
3632           while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3633             cp++;
3634           if (*cp == ':' || isspace (*cp))
3635             {
3636               /* Found end of label, so copy it and add it to the table. */
3637               pfnote ((CTAGS) ? savenstr(lb.buffer, cp-lb.buffer) : NULL, TRUE,
3638                       lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3639             }
3640         }
3641     }
3642 }
3643 \f
3644 /*
3645  * Perl support by Bart Robinson <lomew@cs.utah.edu>
3646  *              enhanced by Michael Ernst <mernst@alum.mit.edu>
3647  * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
3648  * Perl variable names: /^(my|local).../
3649  */
3650 void
3651 Perl_functions (inf)
3652      FILE *inf;
3653 {
3654   register char *cp;
3655
3656   LOOP_ON_INPUT_LINES (inf, lb, cp)
3657     {
3658       if (*cp++ == 's'
3659           && *cp++ == 'u'
3660           && *cp++ == 'b' && isspace (*cp++))
3661         {
3662           cp = skip_spaces (cp);
3663           if (*cp != '\0')
3664             {
3665               while (*cp != '\0'
3666                      && !isspace (*cp) && *cp != '{' && *cp != '(')
3667                 cp++;
3668               pfnote ((CTAGS) ? savenstr(lb.buffer, cp-lb.buffer) : NULL, TRUE,
3669                       lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3670             }         
3671         }
3672        else if (globals         /* only if tagging global vars is enabled */
3673                 && ((cp = lb.buffer,
3674                      *cp++ == 'm'
3675                      && *cp++ == 'y')
3676                     || (cp = lb.buffer,
3677                         *cp++ == 'l'
3678                         && *cp++ == 'o'
3679                         && *cp++ == 'c'
3680                         && *cp++ == 'a'
3681                         && *cp++ == 'l'))
3682                 && (*cp == '(' || isspace (*cp)))
3683         {
3684           /* After "my" or "local", but before any following paren or space. */
3685           char *varname = NULL;
3686
3687           cp = skip_spaces (cp);
3688           if (*cp == '$' || *cp == '@' || *cp == '%')
3689             {
3690               char* varstart = ++cp;
3691               while (isalnum (*cp) || *cp == '_')
3692                 cp++;
3693               varname = savenstr (varstart, cp-varstart);
3694             }
3695           else
3696             {
3697               /* Should be examining a variable list at this point;
3698                  could insist on seeing an open parenthesis. */
3699               while (*cp != '\0' && *cp != ';' && *cp != '=' &&  *cp != ')')
3700                 cp++;
3701             }
3702  
3703           /* Perhaps I should back cp up one character, so the TAGS table
3704              doesn't mention (and so depend upon) the following char. */
3705           pfnote ((CTAGS) ? savenstr (lb.buffer, cp-lb.buffer) : varname,
3706                   FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3707         }
3708     }
3709 }
3710 \f
3711 /*
3712  * Python support by Eric S. Raymond <esr@thyrsus.com>
3713  * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3714  */
3715 void
3716 Python_functions (inf)
3717      FILE *inf;
3718 {
3719   register char *cp;
3720
3721   LOOP_ON_INPUT_LINES (inf, lb, cp)
3722     {
3723       if (*cp++ == 'd'
3724           && *cp++ == 'e'
3725           && *cp++ == 'f' && isspace (*cp++))
3726         {
3727           cp = skip_spaces (cp);
3728           while (*cp != '\0' && !isspace (*cp) && *cp != '(' && *cp != ':')
3729             cp++;
3730           pfnote ((char *) NULL, TRUE,
3731                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3732         }
3733
3734       cp = lb.buffer;
3735       if (*cp++ == 'c'
3736           && *cp++ == 'l'
3737           && *cp++ == 'a'
3738           && *cp++ == 's'
3739           && *cp++ == 's' && isspace (*cp++))
3740         {
3741           cp = skip_spaces (cp);
3742           while (*cp != '\0' && !isspace (*cp) && *cp != '(' && *cp != ':')
3743             cp++;
3744           pfnote ((char *) NULL, TRUE,
3745                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3746         }
3747     }
3748 }
3749 \f
3750 /* Idea by Corny de Souza
3751  * Cobol tag functions
3752  * We could look for anything that could be a paragraph name.
3753  * i.e. anything that starts in column 8 is one word and ends in a full stop.
3754  */
3755 void
3756 Cobol_paragraphs (inf)
3757      FILE *inf;
3758 {
3759   register char *bp, *ep;
3760
3761   LOOP_ON_INPUT_LINES (inf, lb, bp)
3762     {
3763       if (lb.len < 9)
3764         continue;
3765       bp += 8;
3766
3767       /* If eoln, compiler option or comment ignore whole line. */
3768       if (bp[-1] != ' ' || !isalnum (bp[0]))
3769         continue;
3770
3771       for (ep = bp; isalnum (*ep) || *ep == '-'; ep++)
3772         continue;
3773       if (*ep++ == '.')
3774         pfnote ((CTAGS) ? savenstr (bp, ep-bp) : NULL, TRUE,
3775                 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
3776     }
3777 }
3778 \f
3779 /* Added by Mosur Mohan, 4/22/88 */
3780 /* Pascal parsing                */
3781
3782 /*
3783  *  Locates tags for procedures & functions.  Doesn't do any type- or
3784  *  var-definitions.  It does look for the keyword "extern" or
3785  *  "forward" immediately following the procedure statement; if found,
3786  *  the tag is skipped.
3787  */
3788 void
3789 Pascal_functions (inf)
3790      FILE *inf;
3791 {
3792   linebuffer tline;             /* mostly copied from C_entries */
3793   long save_lcno;
3794   int save_lineno, save_len;
3795   char c, *cp, *namebuf;
3796
3797   bool                          /* each of these flags is TRUE iff: */
3798     incomment,                  /* point is inside a comment */
3799     inquote,                    /* point is inside '..' string */
3800     get_tagname,                /* point is after PROCEDURE/FUNCTION
3801                                    keyword, so next item = potential tag */
3802     found_tag,                  /* point is after a potential tag */
3803     inparms,                    /* point is within parameter-list */
3804     verify_tag;                 /* point has passed the parm-list, so the
3805                                    next token will determine whether this
3806                                    is a FORWARD/EXTERN to be ignored, or
3807                                    whether it is a real tag */
3808
3809   save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3810   namebuf = NULL;               /* keep compiler quiet */
3811   lineno = 0;
3812   charno = 0;
3813   dbp = lb.buffer;
3814   *dbp = '\0';
3815   initbuffer (&tline);
3816
3817   incomment = inquote = FALSE;
3818   found_tag = FALSE;            /* have a proc name; check if extern */
3819   get_tagname = FALSE;          /* have found "procedure" keyword    */
3820   inparms = FALSE;              /* found '(' after "proc"            */
3821   verify_tag = FALSE;           /* check if "extern" is ahead        */
3822
3823   
3824   while (!feof (inf))           /* long main loop to get next char */  
3825     {
3826       c = *dbp++;
3827       if (c == '\0')            /* if end of line */
3828         {
3829           lineno++;
3830           linecharno = charno;
3831           charno += readline (&lb, inf);
3832           dbp = lb.buffer;
3833           if (*dbp == '\0')
3834             continue;
3835           if (!((found_tag && verify_tag)
3836                 || get_tagname))
3837             c = *dbp++;         /* only if don't need *dbp pointing
3838                                    to the beginning of the name of
3839                                    the procedure or function */
3840         }
3841       if (incomment)
3842         {
3843           if (c == '}')         /* within { } comments */
3844             incomment = FALSE;
3845           else if (c == '*' && *dbp == ')') /* within (* *) comments */
3846             {
3847               dbp++;
3848               incomment = FALSE;
3849             }
3850           continue;
3851         }
3852       else if (inquote)
3853         {
3854           if (c == '\'')
3855             inquote = FALSE;
3856           continue;
3857         }
3858       else
3859         switch (c)
3860           {
3861           case '\'':
3862             inquote = TRUE;     /* found first quote */
3863             continue;
3864           case '{':             /* found open { comment */
3865             incomment = TRUE;
3866             continue;
3867           case '(':
3868             if (*dbp == '*')    /* found open (* comment */
3869               {
3870                 incomment = TRUE;
3871                 dbp++;
3872               }
3873             else if (found_tag) /* found '(' after tag, i.e., parm-list */
3874               inparms = TRUE;
3875             continue;
3876           case ')':             /* end of parms list */
3877             if (inparms)
3878               inparms = FALSE;
3879             continue;
3880           case ';':
3881             if (found_tag && !inparms) /* end of proc or fn stmt */
3882               {
3883                 verify_tag = TRUE;
3884                 break;
3885               }
3886             continue;
3887           }
3888       if (found_tag && verify_tag && (*dbp != ' '))
3889         {
3890           /* check if this is an "extern" declaration */
3891           if (*dbp == '\0')
3892             continue;
3893           if (lowcase (*dbp == 'e'))
3894             {
3895               if (tail ("extern"))      /* superfluous, really! */
3896                 {
3897                   found_tag = FALSE;
3898                   verify_tag = FALSE;
3899                 }
3900             }
3901           else if (lowcase (*dbp) == 'f')
3902             {
3903               if (tail ("forward"))     /*  check for forward reference */
3904                 {
3905                   found_tag = FALSE;
3906                   verify_tag = FALSE;
3907                 }
3908             }
3909           if (found_tag && verify_tag) /* not external proc, so make tag */
3910             {
3911               found_tag = FALSE;
3912               verify_tag = FALSE;
3913               pfnote (namebuf, TRUE,
3914                       tline.buffer, save_len, save_lineno, save_lcno);
3915               continue;
3916             }
3917         }
3918       if (get_tagname)          /* grab name of proc or fn */
3919         {
3920           if (*dbp == '\0')
3921             continue;
3922
3923           /* save all values for later tagging */
3924           grow_linebuffer (&tline, lb.len + 1);
3925           strcpy (tline.buffer, lb.buffer);
3926           save_lineno = lineno;
3927           save_lcno = linecharno;
3928
3929           /* grab block name */
3930           for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
3931             continue;
3932           namebuf = (CTAGS) ? savenstr (dbp, cp-dbp) : NULL;
3933           dbp = cp;             /* set dbp to e-o-token */
3934           save_len = dbp - lb.buffer + 1;
3935           get_tagname = FALSE;
3936           found_tag = TRUE;
3937           continue;
3938
3939           /* and proceed to check for "extern" */
3940         }
3941       else if (!incomment && !inquote && !found_tag)
3942         {
3943           /* check for proc/fn keywords */
3944           switch (lowcase (c))
3945             {
3946             case 'p':
3947               if (tail ("rocedure"))    /* c = 'p', dbp has advanced */
3948                 get_tagname = TRUE;
3949               continue;
3950             case 'f':
3951               if (tail ("unction"))
3952                 get_tagname = TRUE;
3953               continue;
3954             }
3955         }
3956     }                           /* while not eof */
3957
3958   free (tline.buffer);
3959 }
3960 \f
3961 /*
3962  * lisp tag functions
3963  *  look for (def or (DEF, quote or QUOTE
3964  */
3965 int L_isdef PP ((char *strp));
3966 int
3967 L_isdef (strp)
3968      register char *strp;
3969 {
3970   return ((strp[1] == 'd' || strp[1] == 'D')
3971           && (strp[2] == 'e' || strp[2] == 'E')
3972           && (strp[3] == 'f' || strp[3] == 'F'));
3973 }
3974 int L_isquote PP ((char *strp));
3975 int
3976 L_isquote (strp)
3977      register char *strp;
3978 {
3979   return ((*++strp == 'q' || *strp == 'Q')
3980           && (*++strp == 'u' || *strp == 'U')
3981           && (*++strp == 'o' || *strp == 'O')
3982           && (*++strp == 't' || *strp == 'T')
3983           && (*++strp == 'e' || *strp == 'E')
3984           && isspace (*++strp));
3985 }
3986
3987 void L_getit PP ((void));
3988 void
3989 L_getit ()
3990 {
3991   register char *cp;
3992
3993   if (*dbp == '\'')             /* Skip prefix quote */
3994     dbp++;
3995   else if (*dbp == '(')
3996   {
3997     if (L_isquote (dbp))
3998       dbp += 7;                 /* Skip "(quote " */
3999     else
4000       dbp += 1;                 /* Skip "(" before name in (defstruct (foo)) */
4001     dbp = skip_spaces (dbp);
4002   }
4003
4004   for (cp = dbp /*+1*/;
4005        *cp != '\0' && *cp != '(' && *cp != ' ' && *cp != ')';
4006        cp++)
4007     continue;
4008   if (cp == dbp)
4009     return;
4010
4011   pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
4012           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4013 }
4014
4015 void
4016 Lisp_functions (inf)
4017      FILE *inf;
4018 {
4019   LOOP_ON_INPUT_LINES (inf, lb, dbp)
4020     {
4021       if (dbp[0] == '(')
4022         {
4023           if (L_isdef (dbp))
4024             {
4025               dbp = skip_non_spaces (dbp);
4026               dbp = skip_spaces (dbp);
4027               L_getit ();
4028             }
4029           else
4030             {
4031               /* Check for (foo::defmumble name-defined ... */
4032               do
4033                 dbp++;
4034               while (*dbp != '\0' && !isspace (*dbp)
4035                      && *dbp != ':' && *dbp != '(' && *dbp != ')');
4036               if (*dbp == ':')
4037                 {
4038                   do
4039                     dbp++;
4040                   while (*dbp == ':');
4041
4042                   if (L_isdef (dbp - 1))
4043                     {
4044                       dbp = skip_non_spaces (dbp);
4045                       dbp = skip_spaces (dbp);
4046                       L_getit ();
4047                     }
4048                 }
4049             }
4050         }
4051     }
4052 }
4053 \f
4054 /*
4055  * Postscript tag functions
4056  * Just look for lines where the first character is '/'
4057  * Richard Mlynarik <mly@adoc.xerox.com>
4058  */
4059 void 
4060 Postscript_functions (inf)
4061      FILE *inf;
4062 {
4063   register char *bp, *ep;
4064
4065   LOOP_ON_INPUT_LINES (inf, lb, bp)
4066     {
4067       if (bp[0] == '/')
4068         {
4069           for (ep = bp+1;
4070                *ep != '\0' && *ep != ' ' && *ep != '{';
4071                ep++)
4072             continue;
4073           pfnote ((CTAGS) ? savenstr (bp, ep-bp) : NULL, TRUE,
4074                   lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4075         }
4076     }
4077 }
4078
4079 \f
4080 /*
4081  * Scheme tag functions
4082  * look for (def... xyzzy
4083  * look for (def... (xyzzy
4084  * look for (def ... ((...(xyzzy ....
4085  * look for (set! xyzzy
4086  */
4087
4088 void get_scheme PP ((void));
4089
4090 void
4091 Scheme_functions (inf)
4092      FILE *inf;
4093 {
4094   LOOP_ON_INPUT_LINES (inf, lb, dbp)
4095     {
4096       if (dbp[0] == '('
4097           && (dbp[1] == 'D' || dbp[1] == 'd')
4098           && (dbp[2] == 'E' || dbp[2] == 'e')
4099           && (dbp[3] == 'F' || dbp[3] == 'f'))
4100         {
4101           dbp = skip_non_spaces (dbp);
4102           /* Skip over open parens and white space */
4103           while (isspace (*dbp) || *dbp == '(')
4104             dbp++;
4105           get_scheme ();
4106         }
4107       if (dbp[0] == '('
4108           && (dbp[1] == 'S' || dbp[1] == 's')
4109           && (dbp[2] == 'E' || dbp[2] == 'e')
4110           && (dbp[3] == 'T' || dbp[3] == 't')
4111           && (dbp[4] == '!' || dbp[4] == '!')
4112           && (isspace (dbp[5])))
4113         {
4114           dbp = skip_non_spaces (dbp);
4115           dbp = skip_spaces (dbp);
4116           get_scheme ();
4117         }
4118     }
4119 }
4120
4121 void
4122 get_scheme ()
4123 {
4124   register char *cp;
4125
4126   if (*dbp == '\0')
4127     return;
4128   /* Go till you get to white space or a syntactic break */
4129   for (cp = dbp + 1;
4130        *cp != '\0' && *cp != '(' && *cp != ')' && !isspace (*cp);
4131        cp++)
4132     continue;
4133   pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
4134           lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4135 }
4136 \f
4137 /* Find tags in TeX and LaTeX input files.  */
4138
4139 /* TEX_toktab is a table of TeX control sequences that define tags.
4140    Each TEX_tabent records one such control sequence.
4141    CONVERT THIS TO USE THE Stab TYPE!! */
4142 struct TEX_tabent
4143 {
4144   char *name;
4145   int len;
4146 };
4147
4148 struct TEX_tabent *TEX_toktab = NULL;   /* Table with tag tokens */
4149
4150 /* Default set of control sequences to put into TEX_toktab.
4151    The value of environment var TEXTAGS is prepended to this.  */
4152
4153 char *TEX_defenv = "\
4154 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4155 :part:appendix:entry:index";
4156
4157 void TEX_mode PP ((FILE *inf));
4158 struct TEX_tabent *TEX_decode_env PP ((char *evarname, char *defenv));
4159 int TEX_Token PP ((char *cp));
4160
4161 char TEX_esc = '\\';
4162 char TEX_opgrp = '{';
4163 char TEX_clgrp = '}';
4164
4165 /*
4166  * TeX/LaTeX scanning loop.
4167  */
4168 void
4169 TeX_functions (inf)
4170      FILE *inf;
4171 {
4172   char *cp, *lasthit;
4173   register int i;
4174
4175   /* Select either \ or ! as escape character.  */
4176   TEX_mode (inf);
4177
4178   /* Initialize token table once from environment. */
4179   if (!TEX_toktab)
4180     TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
4181
4182   LOOP_ON_INPUT_LINES (inf, lb, cp)
4183     {
4184       lasthit = cp;
4185       /* Look at each esc in line. */
4186       while ((cp = etags_strchr (cp, TEX_esc)) != NULL)
4187         {
4188           if (*++cp == '\0')
4189             break;
4190           linecharno += cp - lasthit;
4191           lasthit = cp;
4192           i = TEX_Token (lasthit);
4193           if (i >= 0)
4194             {
4195               /* We seem to include the TeX command in the tag name.
4196               register char *p;
4197               for (p = lasthit + TEX_toktab[i].len;
4198                    *p != '\0' && *p != TEX_clgrp;
4199                    p++)
4200                 continue; */
4201               pfnote (/*savenstr (lasthit, p-lasthit)*/ (char *)NULL, TRUE,
4202                       lb.buffer, lb.len, lineno, linecharno);
4203               break;            /* We only tag a line once */
4204             }
4205         }
4206     }
4207 }
4208
4209 #define TEX_LESC '\\'
4210 #define TEX_SESC '!'
4211 #define TEX_cmt  '%'
4212
4213 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4214    chars accordingly. */
4215 void
4216 TEX_mode (inf)
4217      FILE *inf;
4218 {
4219   int c;
4220
4221   while ((c = getc (inf)) != EOF)
4222     {
4223       /* Skip to next line if we hit the TeX comment char. */
4224       if (c == TEX_cmt)
4225         while (c != '\n')
4226           c = getc (inf);
4227       else if (c == TEX_LESC || c == TEX_SESC )
4228         break;
4229     }
4230
4231   if (c == TEX_LESC)
4232     {
4233       TEX_esc = TEX_LESC;
4234       TEX_opgrp = '{';
4235       TEX_clgrp = '}';
4236     }
4237   else
4238     {
4239       TEX_esc = TEX_SESC;
4240       TEX_opgrp = '<';
4241       TEX_clgrp = '>';
4242     }
4243   rewind (inf);
4244 }
4245
4246 /* Read environment and prepend it to the default string.
4247    Build token table. */
4248 struct TEX_tabent *
4249 TEX_decode_env (evarname, defenv)
4250      char *evarname;
4251      char *defenv;
4252 {
4253   register char *env, *p;
4254
4255   struct TEX_tabent *tab;
4256   int size, i;
4257
4258   /* Append default string to environment. */
4259   env = getenv (evarname);
4260   if (!env)
4261     env = defenv;
4262   else
4263     {
4264       char *oldenv = env;
4265       env = concat (oldenv, defenv, "");
4266       free (oldenv);
4267     }
4268
4269   /* Allocate a token table */
4270   for (size = 1, p = env; p;)
4271     if ((p = etags_strchr (p, ':')) && *++p != '\0')
4272       size++;
4273   /* Add 1 to leave room for null terminator.  */
4274   tab = xnew (size + 1, struct TEX_tabent);
4275
4276   /* Unpack environment string into token table. Be careful about */
4277   /* zero-length strings (leading ':', "::" and trailing ':') */
4278   for (i = 0; *env;)
4279     {
4280       p = etags_strchr (env, ':');
4281       if (!p)                   /* End of environment string. */
4282         p = env + strlen (env);
4283       if (p - env > 0)
4284         {                       /* Only non-zero strings. */
4285           tab[i].name = savenstr (env, p - env);
4286           tab[i].len = strlen (tab[i].name);
4287           i++;
4288         }
4289       if (*p)
4290         env = p + 1;
4291       else
4292         {
4293           tab[i].name = NULL;   /* Mark end of table. */
4294           tab[i].len = 0;
4295           break;
4296         }
4297     }
4298   return tab;
4299 }
4300
4301 /* If the text at CP matches one of the tag-defining TeX command names,
4302    return the pointer to the first occurrence of that command in TEX_toktab.
4303    Otherwise return -1.
4304    Keep the capital `T' in `token' for dumb truncating compilers
4305    (this distinguishes it from `TEX_toktab' */
4306 int
4307 TEX_Token (cp)
4308      char *cp;
4309 {
4310   int i;
4311
4312   for (i = 0; TEX_toktab[i].len > 0; i++)
4313     if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
4314       return i;
4315   return -1;
4316 }
4317 \f
4318 /*
4319  * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4320  *
4321  * Assumes that the predicate starts at column 0.
4322  * Only the first clause of a predicate is added. 
4323  */
4324 int prolog_pred PP ((char *s, char *last));
4325 void prolog_skip_comment PP ((linebuffer *plb, FILE *inf));
4326 int prolog_atom PP ((char *s, int pos));
4327
4328 void
4329 Prolog_functions (inf)
4330      FILE *inf;
4331 {
4332   char *cp, *last;
4333   int len;
4334   int allocated;
4335
4336   allocated = 0;
4337   len = 0;
4338   last = NULL;
4339
4340   LOOP_ON_INPUT_LINES (inf, lb, cp)
4341     {
4342       if (cp[0] == '\0')        /* Empty line */
4343         continue;
4344       else if (isspace (cp[0])) /* Not a predicate */
4345         continue;
4346       else if (cp[0] == '/' && cp[1] == '*')    /* comment. */
4347         prolog_skip_comment (&lb, inf);
4348       else if ((len = prolog_pred (cp, last)) > 0)
4349         {
4350           /* Predicate.  Store the function name so that we only
4351              generate a tag for the first clause.  */
4352           if (last == NULL)
4353             last = xnew(len + 1, char);
4354           else if (len + 1 > allocated)
4355             last = xrnew (last, len + 1, char);
4356           allocated = len + 1;
4357           strncpy (last, cp, len);
4358           last[len] = '\0';
4359         }
4360     }
4361 }
4362
4363
4364 void
4365 prolog_skip_comment (plb, inf)
4366      linebuffer *plb;
4367      FILE *inf;
4368 {
4369   char *cp;
4370
4371   do
4372     {
4373       for (cp = plb->buffer; *cp != '\0'; cp++)
4374         if (cp[0] == '*' && cp[1] == '/')
4375           return;
4376       lineno++;
4377       linecharno += readline (plb, inf);
4378     }
4379   while (!feof(inf));
4380 }
4381
4382 /*
4383  * A predicate definition is added if it matches:
4384  *     <beginning of line><Prolog Atom><whitespace>(
4385  *
4386  * It is added to the tags database if it doesn't match the
4387  * name of the previous clause header.
4388  *
4389  * Return the size of the name of the predicate, or 0 if no header
4390  * was found.
4391  */
4392 int
4393 prolog_pred (s, last)
4394      char *s;
4395      char *last;                /* Name of last clause. */
4396 {
4397   int pos;
4398   int len;
4399
4400   pos = prolog_atom (s, 0);
4401   if (pos < 1)
4402     return 0;
4403
4404   len = pos;
4405   pos = skip_spaces (s + pos) - s;
4406
4407   if ((s[pos] == '(') || (s[pos] == '.'))
4408     {
4409       if (s[pos] == '(')
4410         pos++;
4411
4412       /* Save only the first clause. */
4413       if (last == NULL
4414           || len != (int) strlen (last)
4415           || !strneq (s, last, len))
4416         {
4417           pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
4418                   s, pos, lineno, linecharno);
4419           return len;
4420         }
4421     }
4422   return 0;
4423 }
4424
4425 /*
4426  * Consume a Prolog atom.
4427  * Return the number of bytes consumed, or -1 if there was an error.
4428  *
4429  * A prolog atom, in this context, could be one of:
4430  * - An alphanumeric sequence, starting with a lower case letter.
4431  * - A quoted arbitrary string. Single quotes can escape themselves.
4432  *   Backslash quotes everything.
4433  */
4434 int
4435 prolog_atom (s, pos)
4436      char *s;
4437      int pos;
4438 {
4439   int origpos;
4440
4441   origpos = pos;
4442
4443   if (islower(s[pos]) || (s[pos] == '_'))
4444     {
4445       /* The atom is unquoted. */
4446       pos++;
4447       while (isalnum(s[pos]) || (s[pos] == '_'))
4448         {
4449           pos++;
4450         }
4451       return pos - origpos;
4452     }
4453   else if (s[pos] == '\'')
4454     {
4455       pos++;
4456
4457       while (1) 
4458         {
4459           if (s[pos] == '\'')
4460             {
4461               pos++;
4462               if (s[pos] != '\'')
4463                 break;
4464               pos++;            /* A double quote */
4465             }
4466           else if (s[pos] == '\0')
4467             /* Multiline quoted atoms are ignored. */
4468             return -1;
4469           else if (s[pos] == '\\')
4470             {
4471               if (s[pos+1] == '\0')
4472                 return -1;
4473               pos += 2;
4474             }
4475           else
4476             pos++;
4477         }
4478       return pos - origpos;
4479     }
4480   else
4481     return -1;
4482 }
4483 \f
4484 /* 
4485  * Support for Erlang  --  Anders Lindgren, Feb 1996.
4486  *
4487  * Generates tags for functions, defines, and records.
4488  *
4489  * Assumes that Erlang functions start at column 0.
4490  */
4491 int erlang_func PP ((char *s, char *last));
4492 void erlang_attribute PP ((char *s));
4493 int erlang_atom PP ((char *s, int pos));
4494
4495 void
4496 Erlang_functions (inf)
4497      FILE *inf;
4498 {
4499   char *cp, *last;
4500   int len;
4501   int allocated;
4502
4503   allocated = 0;
4504   len = 0;
4505   last = NULL;
4506
4507   LOOP_ON_INPUT_LINES (inf, lb, cp)
4508     {
4509       if (cp[0] == '\0')        /* Empty line */
4510         continue;
4511       else if (isspace (cp[0])) /* Not function nor attribute */
4512         continue;
4513       else if (cp[0] == '%')    /* comment */
4514         continue;
4515       else if (cp[0] == '"')    /* Sometimes, strings start in column one */
4516         continue;
4517       else if (cp[0] == '-')    /* attribute, e.g. "-define" */
4518         {
4519           erlang_attribute (cp);
4520           last = NULL;
4521         }
4522       else if ((len = erlang_func (cp, last)) > 0)
4523         {
4524           /* 
4525            * Function.  Store the function name so that we only
4526            * generates a tag for the first clause.
4527            */
4528           if (last == NULL)
4529             last = xnew (len + 1, char);
4530           else if (len + 1 > allocated)
4531             last = xrnew (last, len + 1, char);
4532           allocated = len + 1;
4533           strncpy (last, cp, len);
4534           last[len] = '\0';
4535         }
4536     }
4537 }
4538
4539
4540 /*
4541  * A function definition is added if it matches:
4542  *     <beginning of line><Erlang Atom><whitespace>(
4543  *
4544  * It is added to the tags database if it doesn't match the
4545  * name of the previous clause header.
4546  *
4547  * Return the size of the name of the function, or 0 if no function
4548  * was found.
4549  */
4550 int
4551 erlang_func (s, last)
4552      char *s;
4553      char *last;                /* Name of last clause. */
4554 {
4555   int pos;
4556   int len;
4557
4558   pos = erlang_atom (s, 0);
4559   if (pos < 1)
4560     return 0;
4561
4562   len = pos;
4563   pos = skip_spaces (s + pos) - s;
4564
4565   /* Save only the first clause. */
4566   if (s[pos++] == '('
4567       && (last == NULL
4568           || len != (int) strlen (last)
4569           || !strneq (s, last, len)))
4570         {
4571           pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
4572                   s, pos, lineno, linecharno);
4573           return len;
4574         }
4575
4576   return 0;
4577 }
4578
4579
4580 /*
4581  * Handle attributes.  Currently, tags are generated for defines 
4582  * and records.
4583  *
4584  * They are on the form:
4585  * -define(foo, bar).
4586  * -define(Foo(M, N), M+N).
4587  * -record(graph, {vtab = notable, cyclic = true}).
4588  */
4589 void
4590 erlang_attribute (s)
4591      char *s;
4592 {
4593   int pos;
4594   int len;
4595
4596   if (strneq (s, "-define", 7) || strneq (s, "-record", 7))
4597     {
4598       pos = skip_spaces (s + 7) - s;
4599       if (s[pos++] == '(') 
4600         {
4601           pos = skip_spaces (s + pos) - s;
4602           len = erlang_atom (s, pos);
4603           if (len != 0)
4604             pfnote ((CTAGS) ? savenstr (& s[pos], len) : NULL, TRUE,
4605                     s, pos + len, lineno, linecharno);
4606         }
4607     }
4608   return;
4609 }
4610
4611
4612 /*
4613  * Consume an Erlang atom (or variable).
4614  * Return the number of bytes consumed, or -1 if there was an error.
4615  */
4616 int
4617 erlang_atom (s, pos)
4618      char *s;
4619      int pos;
4620 {
4621   int origpos;
4622
4623   origpos = pos;
4624
4625   if (isalpha (s[pos]) || s[pos] == '_')
4626     {
4627       /* The atom is unquoted. */
4628       pos++;
4629       while (isalnum (s[pos]) || s[pos] == '_')
4630         pos++;
4631       return pos - origpos;
4632     }
4633   else if (s[pos] == '\'')
4634     {
4635       pos++;
4636
4637       while (1) 
4638         {
4639           if (s[pos] == '\'')
4640             {
4641               pos++;
4642               break;
4643             }
4644           else if (s[pos] == '\0')
4645             /* Multiline quoted atoms are ignored. */
4646             return -1;
4647           else if (s[pos] == '\\')
4648             {
4649               if (s[pos+1] == '\0')
4650                 return -1;
4651               pos += 2;
4652             }
4653           else
4654             pos++;
4655         }
4656       return pos - origpos;
4657     }
4658   else
4659     return -1;
4660 }
4661 \f
4662 #ifdef ETAGS_REGEXPS
4663
4664 /* Take a string like "/blah/" and turn it into "blah", making sure
4665    that the first and last characters are the same, and handling
4666    quoted separator characters.  Actually, stops on the occurrence of
4667    an unquoted separator.  Also turns "\t" into a Tab character.
4668    Returns pointer to terminating separator.  Works in place.  Null
4669    terminates name string. */
4670 char * scan_separators PP ((char *name));
4671 char *
4672 scan_separators (name)
4673      char *name;
4674 {
4675   char sep = name[0];
4676   char *copyto = name;
4677   bool quoted = FALSE;
4678
4679   for (++name; *name != '\0'; ++name)
4680     {
4681       if (quoted)
4682         {
4683           if (*name == 't')
4684             *copyto++ = '\t';
4685           else if (*name == sep)
4686             *copyto++ = sep;
4687           else
4688             {
4689               /* Something else is quoted, so preserve the quote. */
4690               *copyto++ = '\\';
4691               *copyto++ = *name;
4692             }
4693           quoted = FALSE;
4694         }
4695       else if (*name == '\\')
4696         quoted = TRUE;
4697       else if (*name == sep)
4698         break;
4699       else
4700         *copyto++ = *name;
4701     }
4702
4703   /* Terminate copied string. */
4704   *copyto = '\0';
4705   return name;
4706 }
4707
4708 /* Look at the argument of --regex or --no-regex and do the right
4709    thing.  Same for each line of a regexp file. */
4710 void
4711 analyse_regex (regex_arg)
4712      char *regex_arg;
4713 {
4714   if (regex_arg == NULL)
4715     free_patterns ();           /* --no-regex: remove existing regexps */
4716
4717   /* A real --regexp option or a line in a regexp file. */
4718   switch (regex_arg[0])
4719     {
4720       /* Comments in regexp file or null arg to --regex. */
4721     case '\0':
4722     case ' ':
4723     case '\t':
4724       break;
4725
4726       /* Read a regex file.  This is recursive and may result in a
4727          loop, which will stop when the file descriptors are exhausted. */
4728     case '@':
4729       {
4730         FILE *regexfp;
4731         linebuffer regexbuf;
4732         char *regexfile = regex_arg + 1;
4733
4734         /* regexfile is a file containing regexps, one per line. */
4735         regexfp = fopen (regexfile, "r");
4736         if (regexfp == NULL)
4737           {
4738             pfatal (regexfile);
4739             return;
4740           }
4741         initbuffer (&regexbuf);
4742         while (readline_internal (&regexbuf, regexfp) > 0)
4743           analyse_regex (regexbuf.buffer);
4744         free (regexbuf.buffer);
4745         fclose (regexfp);
4746       }
4747       break;
4748
4749       /* Regexp to be used for a specific language only. */
4750     case '{':
4751       {
4752         language *lang;
4753         char *lang_name = regex_arg + 1;
4754         char *cp;
4755
4756         for (cp = lang_name; *cp != '}'; cp++)
4757           if (*cp == '\0')
4758             {
4759               error ("unterminated language name in regex: %s", regex_arg);
4760               return;
4761             }
4762         *cp = '\0';
4763         lang = get_language_from_name (lang_name);
4764         if (lang == NULL)
4765           return;
4766         add_regex (cp + 1, lang);
4767       }
4768       break;
4769
4770       /* Regexp to be used for any language. */
4771     default:
4772       add_regex (regex_arg, NULL);
4773       break;
4774     }
4775 }
4776
4777 /* Turn a name, which is an ed-style (but Emacs syntax) regular
4778    expression, into a real regular expression by compiling it. */
4779 void
4780 add_regex (regexp_pattern, lang)
4781      char *regexp_pattern;
4782      language *lang;
4783 {
4784   char *name;
4785   const char *err;
4786   struct re_pattern_buffer *patbuf;
4787   pattern *pp;
4788
4789
4790   if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
4791     {
4792       error ("%s: unterminated regexp", regexp_pattern);
4793       return;
4794     }
4795   name = scan_separators (regexp_pattern);
4796   if (regexp_pattern[0] == '\0')
4797     {
4798       error ("null regexp", (char *)NULL);
4799       return;
4800     }
4801   (void) scan_separators (name);
4802
4803   patbuf = xnew (1, struct re_pattern_buffer);
4804   patbuf->translate = NULL;
4805   patbuf->fastmap = NULL;
4806   patbuf->buffer = NULL;
4807   patbuf->allocated = 0;
4808
4809   err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
4810   if (err != NULL)
4811     {
4812       error ("%s while compiling pattern", err);
4813       return;
4814     }
4815
4816   pp = p_head;
4817   p_head = xnew (1, pattern);
4818   p_head->regex = savestr (regexp_pattern);
4819   p_head->p_next = pp;
4820   p_head->language = lang;
4821   p_head->pattern = patbuf;
4822   p_head->name_pattern = savestr (name);
4823   p_head->error_signaled = FALSE;
4824 }
4825
4826 /*
4827  * Do the substitutions indicated by the regular expression and
4828  * arguments.
4829  */
4830 char * substitute PP ((char *in, char *out, struct re_registers *regs));
4831 char *
4832 substitute (in, out, regs)
4833      char *in, *out;
4834      struct re_registers *regs;
4835 {
4836   char *result, *t;
4837   int size, dig, diglen;
4838
4839   result = NULL;
4840   size = strlen (out);
4841
4842   /* Pass 1: figure out how much to allocate by finding all \N strings. */
4843   if (out[size - 1] == '\\')
4844     fatal ("pattern error in \"%s\"", out);
4845   for (t = etags_strchr (out, '\\');
4846        t != NULL;
4847        t = etags_strchr (t + 2, '\\'))
4848     if (isdigit (t[1]))
4849       {
4850         dig = t[1] - '0';
4851         diglen = regs->end[dig] - regs->start[dig];
4852         size += diglen - 2;
4853       }
4854     else
4855       size -= 1;
4856
4857   /* Allocate space and do the substitutions. */
4858   result = xnew (size + 1, char);
4859
4860   for (t = result; *out != '\0'; out++)
4861     if (*out == '\\' && isdigit (*++out))
4862       {
4863         /* Using "dig2" satisfies my debugger.  Bleah. */
4864         dig = *out - '0';
4865         diglen = regs->end[dig] - regs->start[dig];
4866         strncpy (t, in + regs->start[dig], diglen);
4867         t += diglen;
4868       }
4869     else
4870       *t++ = *out;
4871   *t = '\0';
4872
4873   if (DEBUG && (t > result + size || t - result != strlen (result)))
4874     abort ();
4875
4876   return result;
4877 }
4878
4879 /* Deallocate all patterns. */
4880 void
4881 free_patterns ()
4882 {
4883   pattern *pp;
4884   while (p_head != NULL)
4885     {
4886       pp = p_head->p_next;
4887       free (p_head->regex);
4888       free (p_head->name_pattern);
4889       free (p_head);
4890       p_head = pp;
4891     }
4892   return;
4893 }
4894 \f
4895 #endif /* ETAGS_REGEXPS */
4896 /* Initialize a linebuffer for use */
4897 void
4898 initbuffer (lbp)
4899      linebuffer *lbp;
4900 {
4901   lbp->size = 200;
4902   lbp->buffer = xnew (200, char);
4903 }
4904
4905 /*
4906  * Read a line of text from `stream' into `lbp', excluding the
4907  * newline or CR-NL, if any.  Return the number of characters read from
4908  * `stream', which is the length of the line including the newline.
4909  *
4910  * On DOS or Windows we do not count the CR character, if any, before the
4911  * NL, in the returned length; this mirrors the behavior of emacs on those
4912  * platforms (for text files, it translates CR-NL to NL as it reads in the
4913  * file).
4914  */
4915 long
4916 readline_internal (lbp, stream)
4917      linebuffer *lbp;
4918      register FILE *stream;
4919 {
4920   char *buffer = lbp->buffer;
4921   register char *p = lbp->buffer;
4922   register char *pend;
4923   int chars_deleted;
4924
4925   pend = p + lbp->size;         /* Separate to avoid 386/IX compiler bug.  */
4926
4927   while (1)
4928     {
4929       register int c = getc (stream);
4930       if (p == pend)
4931         {
4932           /* We're at the end of linebuffer: expand it. */
4933           lbp->size *= 2;
4934           buffer = xrnew (buffer, lbp->size, char);
4935           p += buffer - lbp->buffer;
4936           pend = buffer + lbp->size;
4937           lbp->buffer = buffer;
4938         }
4939       if (c == EOF)
4940         {
4941           *p = '\0';
4942           chars_deleted = 0;
4943           break;
4944         }
4945       if (c == '\n')
4946         {
4947           if (p > buffer && p[-1] == '\r')
4948             {
4949               p -= 1;
4950 #ifdef WIN32_NATIVE
4951              /* Assume CRLF->LF translation will be performed by Emacs
4952                 when loading this file, so CRs won't appear in the buffer.
4953                 It would be cleaner to compensate within Emacs;
4954                 however, Emacs does not know how many CRs were deleted
4955                 before any given point in the file.  */
4956               chars_deleted = 1;
4957 #else
4958               chars_deleted = 2;
4959 #endif
4960             }
4961           else
4962             {
4963               chars_deleted = 1;
4964             }
4965           *p = '\0';
4966           break;
4967         }
4968       *p++ = c;
4969     }
4970   lbp->len = p - buffer;
4971
4972   return lbp->len + chars_deleted;
4973 }
4974
4975 /*
4976  * Like readline_internal, above, but in addition try to match the
4977  * input line against relevant regular expressions.
4978  */
4979 long
4980 readline (lbp, stream)
4981      linebuffer *lbp;
4982      FILE *stream;
4983 {
4984   /* Read new line. */
4985   long result = readline_internal (lbp, stream);
4986 #ifdef ETAGS_REGEXPS
4987   int match;
4988   pattern *pp;
4989
4990   /* Match against relevant patterns. */
4991   if (lbp->len > 0)
4992     for (pp = p_head; pp != NULL; pp = pp->p_next)
4993       {
4994         /* Only use generic regexps or those for the current language. */
4995         if (pp->language != NULL && pp->language != curlang)
4996           continue;
4997
4998         match = re_match (pp->pattern, lbp->buffer, lbp->len, 0, &pp->regs);
4999         switch (match)
5000           {
5001           case -2:
5002             /* Some error. */
5003             if (!pp->error_signaled)
5004               {
5005                 error ("error while matching \"%s\"", pp->regex);
5006                 pp->error_signaled = TRUE;
5007               }
5008             break;
5009           case -1:
5010             /* No match. */
5011             break;
5012           default:
5013             /* Match occurred.  Construct a tag. */
5014             if (pp->name_pattern[0] != '\0')
5015               {
5016                 /* Make a named tag. */
5017                 char *name = substitute (lbp->buffer,
5018                                          pp->name_pattern, &pp->regs);
5019                 if (name != NULL)
5020                   pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
5021               }
5022             else
5023               {
5024                 /* Make an unnamed tag. */
5025                 pfnote ((char *)NULL, TRUE,
5026                         lbp->buffer, match, lineno, linecharno);
5027               }
5028             break;
5029           }
5030       }
5031 #endif /* ETAGS_REGEXPS */
5032   
5033   return result;
5034 }
5035 \f
5036 /*
5037  * Return a pointer to a space of size strlen(cp)+1 allocated
5038  * with xnew where the string CP has been copied.
5039  */
5040 char *
5041 savestr (cp)
5042      char *cp;
5043 {
5044   return savenstr (cp, strlen (cp));
5045 }
5046
5047 /*
5048  * Return a pointer to a space of size LEN+1 allocated with xnew where
5049  * the string CP has been copied for at most the first LEN characters.
5050  */
5051 char *
5052 savenstr (cp, len)
5053      char *cp;
5054      int len;
5055 {
5056   register char *dp;
5057
5058   dp = xnew (len + 1, char);
5059   strncpy (dp, cp, len);
5060   dp[len] = '\0';
5061   return dp;
5062 }
5063
5064 /*
5065  * Return the ptr in sp at which the character c last
5066  * appears; NULL if not found
5067  *
5068  * Identical to System V strrchr, included for portability.
5069  */
5070 char *
5071 etags_strrchr (sp, c)
5072      register char *sp;
5073      register int c;
5074 {
5075   register char *r;
5076
5077   r = NULL;
5078   do
5079     {
5080       if (*sp == c)
5081         r = sp;
5082   } while (*sp++);
5083   return r;
5084 }
5085
5086
5087 /*
5088  * Return the ptr in sp at which the character c first
5089  * appears; NULL if not found
5090  *
5091  * Identical to System V strchr, included for portability.
5092  */
5093 char *
5094 etags_strchr (sp, c)
5095      register char *sp;
5096      register int c;
5097 {
5098   do
5099     {
5100       if (*sp == c)
5101         return sp;
5102     } while (*sp++);
5103   return NULL;
5104 }
5105
5106 /* Skip spaces, return new pointer. */
5107 char *
5108 skip_spaces (cp)
5109      char *cp;
5110 {
5111   while (isspace (*cp))         /* isspace('\0')==FALSE */
5112     cp++;
5113   return cp;
5114 }
5115
5116 /* Skip non spaces, return new pointer. */
5117 char *
5118 skip_non_spaces (cp)
5119      char *cp;
5120 {
5121   while (!iswhite (*cp))        /* iswhite('\0')==TRUE */
5122     cp++;
5123   return cp;
5124 }
5125
5126 /* Print error message and exit.  */
5127 void
5128 fatal (s1, s2)
5129      char *s1, *s2;
5130 {
5131   error (s1, s2);
5132   exit (BAD);
5133 }
5134
5135 void
5136 pfatal (s1)
5137      char *s1;
5138 {
5139   perror (s1);
5140   exit (BAD);
5141 }
5142
5143 void
5144 suggest_asking_for_help ()
5145 {
5146   fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
5147            progname,
5148 #ifdef LONG_OPTIONS
5149            "--help"
5150 #else
5151            "-h"
5152 #endif
5153            );
5154   exit (BAD);
5155 }
5156
5157 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
5158 void
5159 error (s1, s2)
5160      const char *s1, *s2;
5161 {
5162   fprintf (stderr, "%s: ", progname);
5163   fprintf (stderr, s1, s2);
5164   fprintf (stderr, "\n");
5165 }
5166
5167 /* Return a newly-allocated string whose contents
5168    concatenate those of s1, s2, s3.  */
5169 char *
5170 concat (s1, s2, s3)
5171      char *s1, *s2, *s3;
5172 {
5173   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
5174   char *result = xnew (len1 + len2 + len3 + 1, char);
5175
5176   strcpy (result, s1);
5177   strcpy (result + len1, s2);
5178   strcpy (result + len1 + len2, s3);
5179   result[len1 + len2 + len3] = '\0';
5180
5181   return result;
5182 }
5183 \f
5184 /* Does the same work as the system V getcwd, but does not need to
5185    guess the buffer size in advance. */
5186 char *
5187 etags_getcwd ()
5188 {
5189 #ifdef HAVE_GETCWD
5190   int bufsize = 200;
5191   char *path = xnew (bufsize, char);
5192
5193   while (getcwd (path, bufsize) == NULL)
5194     {
5195       if (errno != ERANGE)
5196         pfatal ("getcwd");
5197       bufsize *= 2;
5198       free (path);
5199       path = xnew (bufsize, char);
5200     }
5201
5202   canonicalize_filename (path);
5203   return path;
5204
5205 #else /* not HAVE_GETCWD */
5206   linebuffer path;
5207   FILE *pipe;
5208
5209   initbuffer (&path);
5210   pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
5211   if (pipe == NULL || readline_internal (&path, pipe) == 0)
5212     pfatal ("pwd");
5213   pclose (pipe);
5214
5215   return path.buffer;
5216 #endif /* not HAVE_GETCWD */
5217 }
5218
5219 /* Return a newly allocated string containing the file name of FILE
5220    relative to the absolute directory DIR (which should end with a slash). */
5221 char *
5222 relative_filename (file, dir)
5223      char *file, *dir;
5224 {
5225   char *fp, *dp, *afn, *res;
5226   int i;
5227
5228   /* Find the common root of file and dir (with a trailing slash). */
5229   afn = absolute_filename (file, cwd);
5230   fp = afn;
5231   dp = dir;
5232   while (*fp++ == *dp++)
5233     continue;
5234   fp--, dp--;                   /* back to the first differing char */
5235   do                            /* look at the equal chars until '/' */
5236     fp--, dp--;
5237   while (*fp != '/');
5238
5239   /* Build a sequence of "../" strings for the resulting relative file name. */
5240   i = 0;
5241   while ((dp = etags_strchr (dp + 1, '/')) != NULL)
5242     i += 1;
5243   res = xnew (3*i + strlen (fp + 1) + 1, char);
5244   res[0] = '\0';
5245   while (i-- > 0)
5246     strcat (res, "../");
5247
5248   /* Add the file name relative to the common root of file and dir. */
5249   strcat (res, fp + 1);
5250   free (afn);
5251
5252   return res;
5253 }
5254
5255 /* Return a newly allocated string containing the absolute file name
5256    of FILE given DIR (which should end with a slash). */
5257 char *
5258 absolute_filename (file, dir)
5259      char *file, *dir;
5260 {
5261   char *slashp, *cp, *res;
5262
5263   if (filename_is_absolute (file))
5264     res = savestr (file);
5265 #ifdef WIN32_NATIVE
5266   /* We don't support non-absolute file names with a drive
5267      letter, like `d:NAME' (it's too much hassle).  */
5268   else if (file[1] == ':')
5269     fatal ("%s: relative file names with drive letters not supported", file);
5270 #endif
5271   else
5272     res = concat (dir, file, "");
5273
5274   /* Delete the "/dirname/.." and "/." substrings. */
5275   slashp = etags_strchr (res, '/');
5276   while (slashp != NULL && slashp[0] != '\0')
5277     {
5278       if (slashp[1] == '.')
5279         {
5280           if (slashp[2] == '.'
5281               && (slashp[3] == '/' || slashp[3] == '\0'))
5282             {
5283               cp = slashp;
5284               do
5285                 cp--;
5286               while (cp >= res && !filename_is_absolute (cp));
5287               if (cp < res)
5288                 cp = slashp;    /* the absolute name begins with "/.." */
5289 #ifdef WIN32_NATIVE
5290               /* Under Windows we get `d:/NAME' as absolute
5291                  file name, so the luser could say `d:/../NAME'.
5292                  We silently treat this as `d:/NAME'.  */
5293               else if (cp[0] != '/')
5294                 cp = slashp;
5295 #endif
5296               strcpy (cp, slashp + 3);
5297               slashp = cp;
5298               continue;
5299             }
5300           else if (slashp[2] == '/' || slashp[2] == '\0')
5301             {
5302               strcpy (slashp, slashp + 2);
5303               continue;
5304             }
5305         }
5306
5307       slashp = etags_strchr (slashp + 1, '/');
5308     }
5309   
5310   if (res[0] == '\0')
5311     return savestr ("/");
5312   else
5313     return res;
5314 }
5315
5316 /* Return a newly allocated string containing the absolute
5317    file name of dir where FILE resides given DIR (which should
5318    end with a slash). */
5319 char *
5320 absolute_dirname (file, dir)
5321      char *file, *dir;
5322 {
5323   char *slashp, *res;
5324   char save;
5325
5326   canonicalize_filename (file);
5327   slashp = etags_strrchr (file, '/');
5328   if (slashp == NULL)
5329     return savestr (dir);
5330   save = slashp[1];
5331   slashp[1] = '\0';
5332   res = absolute_filename (file, dir);
5333   slashp[1] = save;
5334
5335   return res;
5336 }
5337
5338 /* Whether the argument string is an absolute file name.  The argument
5339    string must have been canonicalized with canonicalize_filename. */
5340 bool
5341 filename_is_absolute (fn)
5342      char *fn;
5343 {
5344   return (fn[0] == '/'
5345 #ifdef WIN32_NATIVE
5346           || (isalpha(fn[0]) && fn[1] == ':' && fn[2] == '/')
5347 #endif
5348           );
5349 }
5350
5351 /* Translate backslashes into slashes.  Works in place. */
5352 void
5353 canonicalize_filename (fn)
5354      register char *fn;
5355 {
5356 #ifdef WIN32_NATIVE
5357   for (; *fn != '\0'; fn++)
5358     if (*fn == '\\')
5359       *fn = '/';
5360 #else
5361   /* No action. */
5362 #endif
5363 }
5364
5365 /* Increase the size of a linebuffer. */
5366 void
5367 grow_linebuffer (lbp, toksize)
5368      linebuffer *lbp;
5369      int toksize;
5370 {
5371   while (lbp->size < toksize)
5372     lbp->size *= 2;
5373   lbp->buffer = xrnew (lbp->buffer, lbp->size, char);
5374 }
5375
5376 /* Like malloc but get fatal error if memory is exhausted.  */
5377 long *
5378 xmalloc (size)
5379      unsigned int size;
5380 {
5381   long *result = (long *) malloc (size);
5382   if (result == NULL)
5383     fatal ("virtual memory exhausted", (char *)NULL);
5384   return result;
5385 }
5386
5387 long *
5388 xrealloc (ptr, size)
5389      char *ptr;
5390      unsigned int size;
5391 {
5392   long *result =  (long *) realloc (ptr, size);
5393   if (result == NULL)
5394     fatal ("virtual memory exhausted", (char *)NULL);
5395   return result;
5396 }