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