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