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