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