configure.in (m88k-dg-dgux5.4R3): Use dgux5-4R3.
[bpt/emacs.git] / lib-src / etags.c
CommitLineData
c6d46f5f 1/* Tags file maker to go with GNU Emacs
13fde0cd 2 Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
c6d46f5f 3
ea6cd314 4This file is not considered part of GNU Emacs.
c6d46f5f 5
ea6cd314 6This program is free software; you can redistribute it and/or modify
c6d46f5f 7it under the terms of the GNU General Public License as published by
ea6cd314
RS
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
c6d46f5f 10
ea6cd314 11This program is distributed in the hope that it will be useful,
c6d46f5f
JB
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
ea6cd314
RS
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
c6d46f5f
JB
19
20/*
21 * Authors:
22 * Ctags originally by Ken Arnold.
6dd5561c 23 * Fortran added by Jim Kleckner.
c6d46f5f
JB
24 * Ed Pelegri-Llopart added C typedefs.
25 * Gnu Emacs TAGS format and modifications by RMS?
26 * Sam Kendall added C++.
31d4b314 27 *
46c145db 28 * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
c6d46f5f
JB
29 */
30
3ad2882c 31char pot_etags_version[] = "@(#) pot revision number is 10.32";
46c145db 32
c6880c90
RS
33#ifdef MSDOS
34#include <fcntl.h>
35#endif /* MSDOS */
36
72a339d7 37#ifdef HAVE_CONFIG_H
18160b98 38#include <../src/config.h>
1ddff51c
RS
39/* On some systems, Emacs defines static as nothing
40 for the sake of unexec. We don't want that here
41 since we don't use unexec. */
42#undef static
1e134a5f
RM
43#endif
44
918f9ad1
JB
45#include <stdio.h>
46#include <ctype.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49
2b878b4c
FP
50#if !defined (S_ISREG) && defined (S_IFREG)
51# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
52#endif
53
918f9ad1
JB
54#include "getopt.h"
55
c6d46f5f 56extern char *getenv ();
c6d46f5f 57
c6d46f5f 58
32daa216
FP
59/* Define CTAGS to make the program "ctags" compatible with the usual one.
60 Let it undefined to make the program "etags", which makes emacs-style
61 tag tables and tags typedefs, #defines and struct/union/enum by default. */
62#ifdef CTAGS
63# undef CTAGS
64# define CTAGS TRUE
65#else
66# define CTAGS FALSE
c6d46f5f
JB
67#endif
68
69/* Exit codes for success and failure. */
70#ifdef VMS
32daa216
FP
71#define GOOD 1
72#define BAD 0
c6d46f5f 73#else
32daa216
FP
74#define GOOD 0
75#define BAD 1
c6d46f5f
JB
76#endif
77
78/*
79 * The FILEPOS abstract type, which represents a position in a file,
80 * plus the following accessor functions:
81 *
82 * long GET_CHARNO (pos)
83 * returns absolute char number.
c6d46f5f
JB
84 * void SET_FILEPOS (pos, fp, charno)
85 * FILE *fp; long charno;
86 * sets `pos' from the current file
87 * position of `fp' and from `charno',
88 * which must be the absolute character
89 * number corresponding to the current
90 * position of `fp'.
91 *
92 * The `pos' parameter is an lvalue expression of type FILEPOS.
93 * Parameters to the accessor functions are evaluated 0 or more times,
94 * and so must have no side effects.
95 *
96 * FILEPOS objects can also be assigned and passed to and from
97 * functions in the normal C manner.
98 *
99 * Implementation notes: the `+ 0' is to enforce rvalue-ness.
100 */
c6d46f5f 101
c6d46f5f 102#ifndef DEBUG
13fde0cd 103 /* real implementation */
c6d46f5f
JB
104typedef long FILEPOS;
105#define GET_CHARNO(pos) ((pos) + 0)
c6d46f5f
JB
106#define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))
107#else
13fde0cd 108 /* debugging implementation */
c6d46f5f
JB
109typedef struct
110{
111 long charno;
112} FILEPOS;
113
114#define GET_CHARNO(pos) ((pos).charno + 0)
c6d46f5f
JB
115#define SET_FILEPOS(pos, fp, cno) \
116 ((void) ((pos).charno = (cno), \
117 (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
118 : 0))
119#endif
c6d46f5f
JB
120
121#define streq(s, t) (strcmp (s, t) == 0)
122#define strneq(s, t, n) (strncmp (s, t, n) == 0)
13fde0cd 123#define logical int
c6d46f5f
JB
124
125#define TRUE 1
126#define FALSE 0
127
128#define iswhite(arg) (_wht[arg]) /* T if char is white */
129#define begtoken(arg) (_btk[arg]) /* T if char can start token */
130#define intoken(arg) (_itk[arg]) /* T if char can be in token */
131#define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
c6d46f5f
JB
132
133#define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
134
135struct nd_st
136{ /* sorting structure */
137 char *name; /* function or type name */
138 char *file; /* file name */
139 logical is_func; /* use pattern or line no */
fe0b3356 140 logical named; /* list name separately */
c6d46f5f
JB
141 logical been_warned; /* set if noticed dup */
142 int lno; /* line number tag is on */
143 long cno; /* character number line starts on */
144 char *pat; /* search pattern */
145 struct nd_st *left, *right; /* left and right sons */
146};
147
c6d46f5f
JB
148typedef struct nd_st NODE;
149
13fde0cd
RS
150logical header_file; /* TRUE if .h file, FALSE o.w. */
151/* boolean "functions" (see init) */
152logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
c6d46f5f 153
b02c5fea 154char *cwd; /* current working directory */
6dd5561c 155char *tagfiledir; /* directory of tagfile */
c6d46f5f
JB
156
157char *concat ();
46c145db 158char *savenstr (), *savestr ();
b02c5fea
FP
159char *etags_strchr (), *etags_strrchr ();
160char *etags_getcwd ();
46c145db
FP
161char *relative_filename (), *absolute_filename (), *absolute_dirname ();
162char *xmalloc (), *xrealloc ();
c6d46f5f 163int total_size_of_entries ();
c6d46f5f 164long readline ();
6dd5561c
FP
165
166void Asm_labels ();
c6d46f5f 167void C_entries ();
6dd5561c
FP
168int Fortran_functions ();
169void Lisp_functions ();
170void Pascal_functions ();
171void Prolog_functions ();
172void Scheme_functions ();
173void TeX_functions ();
c6d46f5f
JB
174void add_node ();
175void error ();
176void fatal ();
42680d3c 177logical find_entries ();
c6d46f5f
JB
178void free_tree ();
179void getit ();
c6d46f5f
JB
180void init ();
181void initbuffer ();
182void initbuffer ();
183void pfnote ();
184void process_file ();
185void put_entries ();
186void takeprec ();
187
188/*
189 * MACRO
190 * xnew -- allocate storage
191 *
192 * SYNOPSIS
193 * Type *xnew (int n, Type);
194 */
195#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
c6d46f5f
JB
196
197/*
42680d3c 198 * Symbol table types.
c6d46f5f 199 */
c6d46f5f
JB
200enum sym_type
201{
202 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
203};
c6d46f5f
JB
204\f
205
206
207typedef int LINENO;
208
209typedef struct
210{
211 char *p;
212 int len;
c6d46f5f 213 LINENO lineno;
fe0b3356 214 logical named;
c6d46f5f 215} TOKEN;
c6d46f5f 216
13fde0cd 217/* C extensions.
c6d46f5f 218 */
13fde0cd
RS
219#define C_PLPL 0x00001 /* C++ */
220#define C_STAR 0x00003 /* C* */
221#define YACC 0x10000 /* yacc file */
c6d46f5f
JB
222
223char searchar = '/'; /* use /.../ searches */
224
225LINENO lineno; /* line number of current line */
226long charno; /* current character number */
c6d46f5f
JB
227
228long linecharno; /* charno of start of line; not used by C, but
229 * by every other language.
230 */
231
232char *curfile, /* current input file name */
6dd5561c 233 *tagfile, /* output file */
c6d46f5f 234 *white = " \f\t\n", /* white chars */
13fde0cd
RS
235 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
236 /* token starting chars */
b12756c8 237 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
46c145db 238 /* valid in-token chars */
13fde0cd 239 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
c6d46f5f 240
c6d46f5f 241int append_to_tagfile; /* -a: append to tags */
c6d46f5f
JB
242/* The following three default to 1 for etags, but to 0 for ctags. */
243int typedefs; /* -t: create tags for typedefs */
244int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
245 /* 0 struct/enum/union decls, and C++ */
32daa216 246 /* member functions. */
c6d46f5f 247int constantypedefs; /* -d: create tags for C #define and enum */
32daa216 248 /* constants. Enum consts not implemented. */
c6d46f5f
JB
249 /* -D: opposite of -d. Default under ctags. */
250int update; /* -u: update tags */
251int vgrind_style; /* -v: create vgrind style index output */
252int no_warnings; /* -w: suppress warnings */
253int cxref_style; /* -x: create cxref style output */
254int cplusplus; /* .[hc] means C++, not C */
255int noindentypedefs; /* -S: ignore indentation in C */
c6d46f5f
JB
256
257/* Name this program was invoked with. */
258char *progname;
259
4746118a
JB
260struct option longopts[] = {
261 { "append", no_argument, NULL, 'a' },
262 { "backward-search", no_argument, NULL, 'B' },
263 { "c++", no_argument, NULL, 'C' },
264 { "cxref", no_argument, NULL, 'x' },
265 { "defines", no_argument, NULL, 'd' },
4746118a
JB
266 { "help", no_argument, NULL, 'H' },
267 { "ignore-indentation", no_argument, NULL, 'S' },
268 { "include", required_argument, NULL, 'i' },
269 { "no-defines", no_argument, NULL, 'D' },
270 { "no-warn", no_argument, NULL, 'w' },
271 { "output", required_argument, NULL, 'o' },
272 { "typedefs", no_argument, NULL, 't' },
273 { "typedefs-and-c++", no_argument, NULL, 'T' },
274 { "update", no_argument, NULL, 'u' },
275 { "version", no_argument, NULL, 'V' },
276 { "vgrind", no_argument, NULL, 'v' },
277 { 0 }
278};
279
6dd5561c
FP
280FILE *tagf; /* ioptr for tags file */
281NODE *head; /* the head of the binary tree of tags */
282logical permit_duplicates = TRUE; /* allow duplicate tags */
c6d46f5f
JB
283
284/* A `struct linebuffer' is a structure which holds a line of text.
285 `readline' reads a line from a stream into a linebuffer
286 and works regardless of the length of the line. */
287
288struct linebuffer
289{
290 long size;
291 char *buffer;
292};
293
294struct linebuffer lb; /* the current line */
c6d46f5f 295struct linebuffer filename_lb; /* used to read in filenames */
13fde0cd
RS
296struct
297{
298 FILEPOS linepos;
299 struct linebuffer lb; /* used by C_entries instead of lb */
300} lbs[2];
c6d46f5f 301\f
4746118a
JB
302void
303print_version ()
304{
32daa216 305#ifdef VERSION
cc582743 306 printf ("%s for Emacs version %s.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
32daa216
FP
307#else
308 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
309#endif
4746118a 310
1a0d8c80 311 exit (GOOD);
4746118a
JB
312}
313
314void
315print_help ()
316{
317 printf ("These are the options accepted by %s. You may use unambiguous\n\
1a0d8c80
FP
318abbreviations for the long option names. A - as file name means read file\n\
319names from stdin.\n\n", progname);
4746118a 320
52cc7c59
JB
321 puts ("-a, --append\n\
322 Append tag entries to existing tags file.");
1a0d8c80 323
32daa216
FP
324 if (CTAGS)
325 puts ("-B, --backward-search\n\
1a0d8c80 326 Write the search commands for the tag entries using '?', the\n\
3ad2882c 327 backward-search command instead of '/', the forward-search command.");
1a0d8c80 328
52cc7c59 329 puts ("-C, --c++\n\
4746118a
JB
330 Treat files with `.c' and `.h' extensions as C++ code, not C\n\
331 code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
52cc7c59 332 extensions are always assumed to be C++ code.");
4746118a 333
32daa216
FP
334 if (CTAGS)
335 puts ("-d, --defines\n\
336 Create tag entries for C #defines, too.");
337 else
338 puts ("-D, --no-defines\n\
339 Don't create tag entries for C #defines. This makes the tags\n\
340 file smaller.");
4746118a 341
32daa216
FP
342 if (!CTAGS)
343 puts ("-i FILE, --include=FILE\n\
1a0d8c80
FP
344 Include a note in tag file indicating that, when searching for\n\
345 a tag, one should also consult the tags file FILE after\n\
346 checking the current file.");
4746118a 347
1a0d8c80
FP
348 puts ("-o FILE, --output=FILE\n\
349 Write the tags to FILE.");
350 puts ("-S, --ignore-indentation\n\
4746118a
JB
351 Don't rely on indentation quite as much as normal. Currently,\n\
352 this means not to assume that a closing brace in the first\n\
353 column is the final brace of a function or structure\n\
32daa216 354 definition in C and C++.");
4746118a 355
32daa216
FP
356 if (CTAGS)
357 {
358 puts ("-t, --typedefs\n\
359 Generate tag entries for C typedefs.");
360 puts ("-T, --typedefs-and-c++\n\
361 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
362 and C++ member functions.");
32daa216 363 puts ("-u, --update\n\
4746118a
JB
364 Update the tag entries for the given files, leaving tag\n\
365 entries for other files in place. Currently, this is\n\
366 implemented by deleting the existing entries for the given\n\
367 files and then rewriting the new entries at the end of the\n\
368 tags file. It is often faster to simply rebuild the entire\n\
52cc7c59 369 tag file than to use this.");
32daa216 370 puts ("-v, --vgrind\n\
4746118a
JB
371 Generates an index of items intended for human consumption,\n\
372 similar to the output of vgrind. The index is sorted, and\n\
52cc7c59 373 gives the page number of each item.");
32daa216 374 puts ("-x, --cxref\n\
4746118a
JB
375 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
376 The output uses line numbers instead of page numbers, but\n\
377 beyond that the differences are cosmetic; try both to see\n\
52cc7c59 378 which you like.");
32daa216 379 puts ("-w, --no-warn\n\
4746118a
JB
380 Suppress warning messages about entries defined in multiple\n\
381 files.");
32daa216 382 }
4746118a
JB
383
384 puts ("-V, --version\n\
385 Print the version of the program.\n\
386-H, --help\n\
387 Print this help message.");
388
1a0d8c80 389 exit (GOOD);
4746118a
JB
390}
391
392\f
c6d46f5f
JB
393void
394main (argc, argv)
395 int argc;
396 char *argv[];
397{
398 char cmd[100];
399 int i;
1e134a5f 400 unsigned int nincluded_files = 0;
72a339d7 401 char **included_files = xnew (argc, char *);
c6d46f5f
JB
402 char *this_file;
403#ifdef VMS
404 char got_err;
405
406 extern char *gfnames ();
407 extern char *massage_name ();
408#endif
46c145db 409
c6880c90 410#ifdef MSDOS
42680d3c 411 _fmode = O_BINARY; /* all of files are treated as binary files */
c6880c90
RS
412#endif /* MSDOS */
413
c6d46f5f
JB
414 progname = argv[0];
415
c6d46f5f
JB
416 /*
417 * If etags, always find typedefs and structure tags. Why not?
418 * Also default is to find macro constants.
419 */
32daa216 420 if (!CTAGS)
c6d46f5f
JB
421 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
422
4746118a 423 for (;;)
c6d46f5f 424 {
4746118a 425 int opt;
3ad2882c 426 opt = getopt_long (argc, argv, "aCdDf:o:StTi:BuvxwVH", longopts, 0);
4746118a
JB
427
428 if (opt == EOF)
429 break;
430
431 switch (opt)
c6d46f5f 432 {
b02c5fea
FP
433 case 0:
434 /* If getopt returns 0, then it has already processed a
4746118a
JB
435 long-named option. We should do nothing. */
436 break;
437
438 /* Common options. */
439 case 'a':
440 append_to_tagfile++;
441 break;
442 case 'C':
443 cplusplus = 1;
444 break;
445 case 'd':
446 constantypedefs = 1;
447 break;
448 case 'D':
449 constantypedefs = 0;
450 break;
32daa216 451 case 'f': /* for compatibility with old makefiles */
4746118a 452 case 'o':
6dd5561c 453 if (tagfile)
c6d46f5f 454 {
4746118a 455 fprintf (stderr,
3ed79319 456 "%s: -%c flag may only be given once\n", progname, opt);
c6d46f5f
JB
457 goto usage;
458 }
6dd5561c 459 tagfile = optarg;
4746118a
JB
460 break;
461 case 'S':
462 noindentypedefs++;
463 break;
4746118a
JB
464 case 'V':
465 print_version ();
466 break;
467 case 'H':
468 print_help ();
469 break;
470
b02c5fea
FP
471#if (!CTAGS)
472
4746118a
JB
473 /* Etags options */
474 case 'i':
4746118a
JB
475 included_files[nincluded_files++] = optarg;
476 break;
477
b02c5fea
FP
478#else /* CTAGS */
479
4746118a
JB
480 /* Ctags options. */
481 case 'B':
482 searchar = '?';
4746118a 483 break;
32daa216
FP
484 case 't':
485 typedefs++;
32daa216
FP
486 break;
487 case 'T':
488 typedefs++;
489 typedefs_and_cplusplus++;
4746118a
JB
490 break;
491 case 'u':
492 update++;
4746118a
JB
493 break;
494 case 'v':
495 vgrind_style++;
496 /*FALLTHRU*/
497 case 'x':
498 cxref_style++;
4746118a
JB
499 break;
500 case 'w':
501 no_warnings++;
4746118a
JB
502 break;
503
b02c5fea
FP
504#endif /* CTAGS */
505
4746118a
JB
506 default:
507 goto usage;
c6d46f5f 508 }
c6d46f5f
JB
509 }
510
0e5ad25f 511 if (optind == argc && nincluded_files == 0)
c6d46f5f 512 {
4746118a
JB
513 fprintf (stderr, "%s: No input files specified.\n", progname);
514
c6d46f5f 515 usage:
0e5ad25f 516 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
4746118a 517 progname, progname);
c6d46f5f
JB
518 exit (BAD);
519 }
520
6dd5561c 521 if (tagfile == NULL)
c6d46f5f 522 {
6dd5561c 523 tagfile = CTAGS ? "tags" : "TAGS";
c6d46f5f 524 }
b02c5fea 525 cwd = etags_getcwd (); /* the current working directory */
46c145db 526 strcat (cwd, "/");
6dd5561c 527 if (streq (tagfile, "-"))
46c145db 528 {
6dd5561c 529 tagfiledir = cwd;
46c145db
FP
530 }
531 else
532 {
6dd5561c 533 tagfiledir = absolute_dirname (tagfile, cwd);
46c145db 534 }
c6d46f5f
JB
535
536 init (); /* set up boolean "functions" */
537
538 initbuffer (&lb);
13fde0cd
RS
539 initbuffer (&lbs[0].lb);
540 initbuffer (&lbs[1].lb);
c6d46f5f
JB
541 initbuffer (&filename_lb);
542 /*
543 * loop through files finding functions
544 */
32daa216 545 if (!CTAGS)
c6d46f5f 546 {
6dd5561c
FP
547 if (streq (tagfile, "-"))
548 tagf = stdout;
c6d46f5f 549 else
6dd5561c
FP
550 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
551 if (tagf == NULL)
c6d46f5f 552 {
6dd5561c 553 perror (tagfile);
1a0d8c80 554 exit (BAD);
c6d46f5f
JB
555 }
556 }
557
c6d46f5f 558#ifdef VMS
4746118a
JB
559 argc -= optind;
560 argv += optind;
561 while (gfnames (&argc, &argv, &got_err) != NULL)
c6d46f5f
JB
562 {
563 if (got_err)
564 {
565 error ("Can't find file %s\n", this_file);
566 argc--, argv++;
567 }
568 else
569 {
570 this_file = massage_name (this_file);
571#if 0
572 }
13fde0cd 573 } /* solely to balance out the ifdef'd parens above */
c6d46f5f
JB
574#endif
575#else
4746118a 576 for (; optind < argc; optind++)
c6d46f5f 577 {
4746118a 578 this_file = argv[optind];
c6d46f5f 579#endif
42680d3c 580 /* Input file named "-" means read file names from stdin and use them. */
46c145db
FP
581 if (streq (this_file, "-"))
582 {
583 while (!feof (stdin))
c6d46f5f 584 {
46c145db
FP
585 (void) readline (&filename_lb, stdin);
586 if (strlen (filename_lb.buffer) > 0)
587 process_file (filename_lb.buffer);
c6d46f5f 588 }
c6d46f5f 589 }
46c145db
FP
590 else
591 process_file (this_file);
592 }
c6d46f5f 593
32daa216 594 if (!CTAGS)
c6d46f5f 595 {
1e134a5f 596 while (nincluded_files-- > 0)
6dd5561c 597 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1e134a5f 598
6dd5561c 599 (void) fclose (tagf);
1a0d8c80 600 exit (GOOD);
c6d46f5f
JB
601 }
602
603 if (cxref_style)
604 {
605 put_entries (head);
606 exit (GOOD);
607 }
4746118a 608 if (update)
c6d46f5f 609 {
4746118a
JB
610 /* update cannot be set under VMS, so we may assume that argc
611 and argv have not been munged. */
612 for (i = optind; i < argc; i++)
c6d46f5f
JB
613 {
614 sprintf (cmd,
615 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
6dd5561c 616 tagfile, argv[i], tagfile);
c6d46f5f
JB
617 (void) system (cmd);
618 }
619 append_to_tagfile++;
620 }
6dd5561c
FP
621 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
622 if (tagf == NULL)
c6d46f5f 623 {
6dd5561c 624 perror (tagfile);
c6d46f5f
JB
625 exit (GOOD);
626 }
627 put_entries (head);
6dd5561c 628 (void) fclose (tagf);
c6d46f5f
JB
629 if (update)
630 {
6dd5561c 631 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
c6d46f5f
JB
632 (void) system (cmd);
633 }
634 exit (GOOD);
635}
636
637
638/*
639 * This routine is called on each file argument.
640 */
641void
642process_file (file)
643 char *file;
644{
645 struct stat stat_buf;
646
42680d3c 647 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
c6d46f5f
JB
648 {
649 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
650 return;
651 }
6dd5561c 652 if (streq (file, tagfile) && !streq (tagfile, "-"))
c6d46f5f
JB
653 {
654 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
655 return;
656 }
42680d3c
FP
657 if (!find_entries (file))
658 {
659 return;
660 }
32daa216 661 if (!CTAGS)
c6d46f5f 662 {
46c145db
FP
663 char *filename;
664
665 if (file[0] == '/')
666 {
667 /* file is an absolute filename. Canonicalise it. */
668 filename = absolute_filename (file, cwd);
669 }
670 else
671 {
672 /* file is a filename relative to cwd. Make it relative
673 to the directory of the tags file. */
6dd5561c 674 filename = relative_filename (file, tagfiledir);
46c145db 675 }
6dd5561c 676 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
c6d46f5f
JB
677 put_entries (head);
678 free_tree (head);
679 head = NULL;
680 }
681}
682
683/*
eb8c3be9 684 * This routine sets up the boolean pseudo-functions which work
99e0a2e0 685 * by setting boolean flags dependent upon the corresponding character
c6d46f5f
JB
686 * Every char which is NOT in that string is not a white char. Therefore,
687 * all of the array "_wht" is set to FALSE, and then the elements
688 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
689 * of a char is TRUE if it is the string "white", else FALSE.
690 */
691void
692init ()
693{
13fde0cd
RS
694 register char *sp;
695 register int i;
c6d46f5f
JB
696
697 for (i = 0; i < 0177; i++)
13fde0cd 698 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
c6d46f5f
JB
699 for (sp = white; *sp; sp++)
700 _wht[*sp] = TRUE;
701 for (sp = endtk; *sp; sp++)
702 _etk[*sp] = TRUE;
703 for (sp = intk; *sp; sp++)
704 _itk[*sp] = TRUE;
705 for (sp = begtk; *sp; sp++)
706 _btk[*sp] = TRUE;
c6d46f5f
JB
707 _wht[0] = _wht['\n'];
708 _etk[0] = _etk['\n'];
709 _btk[0] = _btk['\n'];
710 _itk[0] = _itk['\n'];
c6d46f5f
JB
711}
712
713/*
714 * This routine opens the specified file and calls the function
715 * which finds the function and type definitions.
716 */
42680d3c 717logical
c6d46f5f
JB
718find_entries (file)
719 char *file;
720{
6dd5561c
FP
721 char *cp, *cp1;
722 FILE *inf;
c6d46f5f
JB
723
724 inf = fopen (file, "r");
725 if (inf == NULL)
726 {
727 perror (file);
42680d3c 728 return FALSE;
c6d46f5f
JB
729 }
730 curfile = savestr (file);
b02c5fea 731 cp = etags_strrchr (file, '.');
6dd5561c 732 cp1 = cp + 1;
c6d46f5f 733
6dd5561c 734 header_file = (cp && (streq (cp1, "h")));
c6d46f5f
JB
735
736 /* .tex, .aux or .bbl implies LaTeX source code */
6dd5561c
FP
737 if (cp && (streq (cp1, "tex") || streq (cp1, "aux")
738 || streq (cp1, "bbl")))
c6d46f5f 739 {
6dd5561c 740 TeX_functions (inf);
c6d46f5f
JB
741 goto close_and_return;
742 }
743 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
6dd5561c
FP
744 if (cp && (streq (cp1, "l")
745 || streq (cp1, "el")
746 || streq (cp1, "lsp")
747 || streq (cp1, "lisp")
748 || streq (cp1, "cl")
749 || streq (cp1, "clisp")))
750 {
751 Lisp_functions (inf);
c6d46f5f
JB
752 goto close_and_return;
753 }
754 /* .scm or .sm or .scheme or ... implies scheme source code */
6dd5561c
FP
755 if (cp && (streq (cp1, "sm")
756 || streq (cp1, "scm")
757 || streq (cp1, "scheme")
758 || streq (cp1, "t")
759 || streq (cp1, "sch")
760 || streq (cp1, "ss")
761 || streq (cp1, "SM")
762 || streq (cp1, "SCM")
c6d46f5f
JB
763 /* The `SCM' or `scm' prefix with a version number */
764 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's'
6dd5561c 765 && string_numeric_p (cp1))
c6d46f5f 766 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'
6dd5561c 767 && string_numeric_p (cp1))))
c6d46f5f 768 {
6dd5561c 769 Scheme_functions (inf);
42680d3c 770 goto close_and_return;
c6d46f5f 771 }
6dd5561c
FP
772 /* Assembly code */
773 if (cp && (streq (cp1, "s")
774 || streq (cp1, "a") /* Unix assembler */
775 || streq (cp1, "sa") /* Unix assembler */
776 || streq (cp1, "asm") /* Microcontroller assembly */
777 || streq (cp1, "src") /* BSO/Tasking C compiler output */
778 || streq (cp1, "def") /* BSO/Tasking definition includes */
779 || streq (cp1, "ins") /* Microcontroller include files */
780 || streq (cp1, "inc")))/* Microcontroller include files */
781 {
782 Asm_labels (inf);
42680d3c 783 goto close_and_return;
c6d46f5f
JB
784 }
785 /* .C or .H or .cxx or .hxx or .cc: a C++ file */
6dd5561c
FP
786 if (cp && (streq (cp1, "C")
787 || streq (cp1, "H")
788 || streq (cp1, "cxx")
789 || streq (cp1, "hxx")
790 || streq (cp1, "cc")))
c6d46f5f 791 {
6dd5561c 792 C_entries (C_PLPL, inf); /* C++ */
c6d46f5f
JB
793 goto close_and_return;
794 }
795 /* .cs or .hs: a C* file */
6dd5561c
FP
796 if (cp && (streq (cp1, "cs")
797 || streq (cp1, "hs")))
c6d46f5f 798 {
6dd5561c 799 C_entries (C_STAR, inf);
c6d46f5f
JB
800 goto close_and_return;
801 }
13fde0cd 802 /* .y: a yacc file */
6dd5561c 803 if (cp && (streq (cp1, "y")))
13fde0cd 804 {
6dd5561c 805 C_entries (YACC, inf);
13fde0cd
RS
806 goto close_and_return;
807 }
c6d46f5f 808 /* .pl implies prolog source code */
6dd5561c 809 if (cp && streq (cp1, "pl"))
c6d46f5f 810 {
6dd5561c 811 Prolog_functions (inf);
c6d46f5f
JB
812 goto close_and_return;
813 }
814 /* .p or .pas: a Pascal file */
6dd5561c
FP
815 if (cp && (streq (cp1, "p")
816 || streq (cp1, "pas")))
c6d46f5f 817 {
6dd5561c 818 Pascal_functions (inf);
c6d46f5f
JB
819 goto close_and_return;
820 }
1e8e1162 821 /* If .f or .for, assume it is fortran or nothing. */
6dd5561c
FP
822 if (cp && (streq (cp1, "f")
823 || streq (cp1, "for")))
1e8e1162 824 {
6dd5561c 825 (void) Fortran_functions (inf);
1e8e1162
RS
826 goto close_and_return;
827 }
c6d46f5f 828 /* if not a .c or .h or .y file, try fortran */
1e8e1162
RS
829 if (cp && ((cp[1] != 'c'
830 && cp[1] != 'h'
831 && cp[1] != 'y')
832 || (cp[1] != 0 && cp[2] != 0)))
c6d46f5f 833 {
6dd5561c 834 if (Fortran_functions (inf) != 0)
c6d46f5f
JB
835 goto close_and_return;
836 rewind (inf); /* no fortran tags found, try C */
837 }
6dd5561c 838 C_entries (cplusplus ? C_PLPL : 0, inf);
c6d46f5f
JB
839
840close_and_return:
841 (void) fclose (inf);
42680d3c 842 return TRUE;
c6d46f5f
JB
843}
844
845/* Nonzero if string STR is composed of digits. */
846
847int
848string_numeric_p (str)
849 char *str;
850{
851 while (*str)
852 {
853 if (*str < '0' || *str > '9')
854 return 0;
855 }
856 return 1;
857}
858\f
859/* Record a tag. */
860/* Should take a TOKEN* instead!! */
c6d46f5f 861void
fe0b3356 862pfnote (name, is_func, named, linestart, linelen, lno, cno)
c6d46f5f
JB
863 char *name; /* tag name */
864 logical is_func; /* function or type name? */
fe0b3356 865 logical named; /* tag different from text of definition? */
c6d46f5f
JB
866 char *linestart;
867 int linelen;
868 int lno;
869 long cno;
870{
871 register char *fp;
872 register NODE *np;
873 char tem[51];
874 char c;
875
1a0d8c80 876 np = xnew (1, NODE);
c6d46f5f
JB
877 if (np == NULL)
878 {
32daa216 879 if (CTAGS)
c6d46f5f
JB
880 {
881 /* It's okay to output early in etags -- it only disrupts the
882 * character count of the tag entries, which is no longer used
883 * by tags.el anyway.
884 */
1a0d8c80 885 error ("too many entries to sort", 0);
c6d46f5f
JB
886 }
887 put_entries (head);
888 free_tree (head);
889 head = NULL;
890 np = xnew (1, NODE);
891 }
892 /* If ctags mode, change name "main" to M<thisfilename>. */
32daa216 893 if (CTAGS && !cxref_style && streq (name, "main"))
c6d46f5f 894 {
b02c5fea 895 fp = etags_strrchr (curfile, '/');
c6d46f5f 896 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
b02c5fea 897 fp = etags_strrchr (name, '.');
c6d46f5f
JB
898 if (fp && fp[1] != '\0' && fp[2] == '\0')
899 *fp = 0;
fe0b3356 900 named = TRUE;
c6d46f5f
JB
901 }
902 np->name = savestr (name);
903 np->file = curfile;
904 np->is_func = is_func;
fe0b3356 905 np->named = named;
c6d46f5f
JB
906 np->lno = lno;
907 /* UNCOMMENT THE +1 HERE: */
908 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
909 np->left = np->right = 0;
32daa216 910 if (!CTAGS)
c6d46f5f
JB
911 {
912 c = linestart[linelen];
913 linestart[linelen] = 0;
914 }
915 else if (cxref_style == 0)
916 {
917 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
918 linestart = tem;
919 }
920 np->pat = savestr (linestart);
32daa216 921 if (!CTAGS)
c6d46f5f
JB
922 {
923 linestart[linelen] = c;
924 }
925
926 add_node (np, &head);
927}
928
929/*
930 * free_tree ()
931 * recurse on left children, iterate on right children.
932 */
933void
934free_tree (node)
935 register NODE *node;
936{
937 while (node)
938 {
939 register NODE *node_right = node->right;
940 free_tree (node->left);
941 free (node->name);
942 free (node->pat);
943 free ((char *) node);
944 node = node_right;
945 }
946}
947
948/*
949 * add_node ()
950 * Adds a node to the tree of nodes. In etags mode, we don't keep
951 * it sorted; we just keep a linear list. In ctags mode, maintain
952 * an ordered tree, with no attempt at balancing.
953 *
954 * add_node is the only function allowed to add nodes, so it can
955 * maintain state.
956 */
8f53e1ee
RS
957/* Must avoid static vars within functions since some systems
958 #define static as nothing. */
6dd5561c 959NODE *last_node = NULL;
8f53e1ee 960
c6d46f5f
JB
961void
962add_node (node, cur_node_p)
963 NODE *node, **cur_node_p;
964{
965 register int dif;
966 register NODE *cur_node = *cur_node_p;
c6d46f5f
JB
967
968 if (cur_node == NULL)
969 {
970 *cur_node_p = node;
971 last_node = node;
972 return;
973 }
974
32daa216 975 if (!CTAGS)
c6d46f5f
JB
976 {
977 /* Etags Mode */
1a0d8c80
FP
978 if (last_node == NULL)
979 fatal ("internal error in add_node", 0);
c6d46f5f
JB
980 last_node->right = node;
981 last_node = node;
982 }
983 else
984 {
985 /* Ctags Mode */
986 dif = strcmp (node->name, cur_node->name);
987
988 /*
989 * If this tag name matches an existing one, then
990 * do not add the node, but maybe print a warning.
991 */
992 if (!dif)
993 {
994 if (node->file == cur_node->file)
995 {
996 if (!no_warnings)
997 {
998 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
999 node->file, lineno, node->name);
1000 fprintf (stderr, "Second entry ignored\n");
1001 }
1002 return;
1003 }
1004 if (!cur_node->been_warned && !no_warnings)
1005 {
1006 fprintf (stderr,
1007 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1008 node->file, cur_node->file, node->name);
1009 }
1010 cur_node->been_warned = TRUE;
1011 return;
1012 }
1013
1014 /* Maybe refuse to add duplicate nodes. */
1015 if (!permit_duplicates)
1016 {
1a0d8c80
FP
1017 if (streq (node->name, cur_node->name)
1018 && streq (node->file, cur_node->file))
c6d46f5f
JB
1019 return;
1020 }
1021
1022 /* Actually add the node */
1023 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1024 }
1025}
1026\f
1027void
1028put_entries (node)
13fde0cd 1029 register NODE *node;
c6d46f5f 1030{
13fde0cd 1031 register char *sp;
c6d46f5f
JB
1032
1033 if (node == NULL)
1034 return;
1035
1036 /* Output subentries that precede this one */
1037 put_entries (node->left);
1038
1039 /* Output this entry */
1040
32daa216 1041 if (!CTAGS)
c6d46f5f 1042 {
fe0b3356 1043 if (node->named)
c6d46f5f 1044 {
6dd5561c 1045 fprintf (tagf, "%s\177%s\001%d,%d\n",
cc6d6e58
RM
1046 node->pat, node->name,
1047 node->lno, node->cno);
c6d46f5f
JB
1048 }
1049 else
1050 {
6dd5561c 1051 fprintf (tagf, "%s\177%d,%d\n",
cc6d6e58
RM
1052 node->pat,
1053 node->lno, node->cno);
c6d46f5f
JB
1054 }
1055 }
1056 else if (!cxref_style)
1057 {
6dd5561c 1058 fprintf (tagf, "%s\t%s\t",
c6d46f5f
JB
1059 node->name, node->file);
1060
1061 if (node->is_func)
1062 { /* a function */
6dd5561c
FP
1063 putc (searchar, tagf);
1064 putc ('^', tagf);
c6d46f5f
JB
1065
1066 for (sp = node->pat; *sp; sp++)
1067 {
1068 if (*sp == '\\' || *sp == searchar)
6dd5561c
FP
1069 putc ('\\', tagf);
1070 putc (*sp, tagf);
c6d46f5f 1071 }
6dd5561c 1072 putc (searchar, tagf);
c6d46f5f
JB
1073 }
1074 else
1075 { /* a typedef; text pattern inadequate */
6dd5561c 1076 fprintf (tagf, "%d", node->lno);
c6d46f5f 1077 }
6dd5561c 1078 putc ('\n', tagf);
c6d46f5f
JB
1079 }
1080 else if (vgrind_style)
1081 fprintf (stdout, "%s %s %d\n",
1082 node->name, node->file, (node->lno + 63) / 64);
1083 else
daa37602 1084 fprintf (stdout, "%-16s %3d %-16s %s\n",
c6d46f5f
JB
1085 node->name, node->lno, node->file, node->pat);
1086
1087 /* Output subentries that follow this one */
1088 put_entries (node->right);
1089}
1090
1091/* Length of a number's decimal representation. */
1092int
1093number_len (num)
1094 long num;
1095{
1096 int len = 0;
1097 if (!num)
1098 return 1;
1099 for (; num; num /= 10)
1100 ++len;
1101 return len;
1102}
1103
1104/*
1105 * Return total number of characters that put_entries will output for
32daa216
FP
1106 * the nodes in the subtree of the specified node. Works only if
1107 * we are not ctags, but called only in that case. This count
1108 * is irrelevant with the new tags.el, but is still supplied for
1109 * backward compatibility.
c6d46f5f
JB
1110 */
1111int
1112total_size_of_entries (node)
13fde0cd 1113 register NODE *node;
c6d46f5f 1114{
13fde0cd 1115 register int total;
c6d46f5f
JB
1116
1117 if (node == NULL)
1118 return 0;
1119
1120 total = 0;
1121 for (; node; node = node->right)
1122 {
1123 /* Count left subentries. */
1124 total += total_size_of_entries (node->left);
1125
1126 /* Count this entry */
1127 total += strlen (node->pat) + 1;
1128 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
fe0b3356 1129 if (node->named)
c6d46f5f
JB
1130 total += 1 + strlen (node->name); /* \001name */
1131 }
1132
1133 return total;
1134}
1135\f
1136/*
1137 * The C symbol tables.
1138 */
1139
42680d3c
FP
1140/* Feed stuff between (but not including) %[ and %] lines to:
1141 gperf -c -k1,3 -o -p -r -t
1142%[
1143struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1144%%
1145class, C_PLPL, st_C_struct
1146domain, C_STAR, st_C_struct
1147union, 0, st_C_struct
1148struct, 0, st_C_struct
1149enum, 0, st_C_enum
1150typedef, 0, st_C_typedef
1151define, 0, st_C_define
1152long, 0, st_C_typespec
1153short, 0, st_C_typespec
1154int, 0, st_C_typespec
1155char, 0, st_C_typespec
1156float, 0, st_C_typespec
1157double, 0, st_C_typespec
1158signed, 0, st_C_typespec
1159unsigned, 0, st_C_typespec
1160auto, 0, st_C_typespec
1161void, 0, st_C_typespec
1162extern, 0, st_C_typespec
1163static, 0, st_C_typespec
1164const, 0, st_C_typespec
1165volatile, 0, st_C_typespec
1166%]
1167and replace lines between %< and %> with its output. */
1168/*%<*/
1169/* C code produced by gperf version 1.8.1 (K&R C version) */
1170/* Command-line: gperf -c -k1,3 -o -p -r -t */
1171
1172
1173struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1174
1175#define MIN_WORD_LENGTH 3
1176#define MAX_WORD_LENGTH 8
1177#define MIN_HASH_VALUE 10
1178#define MAX_HASH_VALUE 62
c6d46f5f 1179/*
42680d3c
FP
1180 21 keywords
1181 53 is the maximum key range
1182*/
1183
1184static int
1185hash (str, len)
1186 register char *str;
1187 register int len;
1188{
1189 static unsigned char hash_table[] =
1190 {
1191 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1192 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1193 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1194 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1195 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1196 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1197 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1198 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1199 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1200 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1201 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1202 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1203 62, 62, 62, 62, 62, 62, 62, 62,
1204 };
1205 return len + hash_table[str[2]] + hash_table[str[0]];
1206}
c6d46f5f 1207
42680d3c
FP
1208struct C_stab_entry *
1209in_word_set (str, len)
1210 register char *str;
1211 register int len;
1212{
1213
1214 static struct C_stab_entry wordlist[] =
1215 {
1216 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1217 {"",},
1218 {"volatile", 0, st_C_typespec},
1219 {"",},
1220 {"long", 0, st_C_typespec},
1221 {"char", 0, st_C_typespec},
1222 {"class", C_PLPL, st_C_struct},
1223 {"",}, {"",}, {"",}, {"",},
1224 {"const", 0, st_C_typespec},
1225 {"",}, {"",}, {"",}, {"",},
1226 {"auto", 0, st_C_typespec},
1227 {"",}, {"",},
1228 {"define", 0, st_C_define},
1229 {"",},
1230 {"void", 0, st_C_typespec},
1231 {"",}, {"",}, {"",},
1232 {"extern", 0, st_C_typespec},
1233 {"static", 0, st_C_typespec},
1234 {"",},
1235 {"domain", C_STAR, st_C_struct},
1236 {"",},
1237 {"typedef", 0, st_C_typedef},
1238 {"double", 0, st_C_typespec},
1239 {"enum", 0, st_C_enum},
1240 {"",}, {"",}, {"",}, {"",},
1241 {"int", 0, st_C_typespec},
1242 {"",},
1243 {"float", 0, st_C_typespec},
1244 {"",}, {"",}, {"",},
1245 {"struct", 0, st_C_struct},
1246 {"",}, {"",}, {"",}, {"",},
1247 {"union", 0, st_C_struct},
1248 {"",},
1249 {"short", 0, st_C_typespec},
1250 {"",}, {"",},
1251 {"unsigned", 0, st_C_typespec},
1252 {"signed", 0, st_C_typespec},
1253 };
1254
1255 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1256 {
1257 register int key = hash (str, len);
1258
1259 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1260 {
1261 register char *s = wordlist[key].name;
1262
1a0d8c80 1263 if (*s == *str && strneq (str + 1, s + 1, len - 1))
42680d3c
FP
1264 return &wordlist[key];
1265 }
1266 }
1267 return 0;
c6d46f5f 1268}
42680d3c 1269/*%>*/
c6d46f5f 1270
42680d3c
FP
1271enum sym_type
1272C_symtype(str, len, c_ext)
1273 char *str;
1274 int len;
c6d46f5f
JB
1275 int c_ext;
1276{
42680d3c 1277 register struct C_stab_entry *se = in_word_set(str, len);
c6d46f5f 1278
42680d3c
FP
1279 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1280 return st_none;
1281 return se->type;
c6d46f5f
JB
1282}
1283\f
13fde0cd 1284 /*
13fde0cd
RS
1285 * C functions are recognized using a simple finite automaton.
1286 * funcdef is its state variable.
1287 */
1288typedef enum
1289{
31d4b314
FP
1290 fnone, /* nothing seen */
1291 ftagseen, /* function-like tag seen */
b12756c8 1292 fstartlist, /* just after open parenthesis */
31d4b314
FP
1293 finlist, /* in parameter list */
1294 flistseen, /* after parameter list */
46e4cb76 1295 fignore /* before open brace */
13fde0cd
RS
1296} FUNCST;
1297FUNCST funcdef;
1298
1299
46c145db
FP
1300 /*
1301 * typedefs are recognized using a simple finite automaton.
13fde0cd
RS
1302 * typeddef is its state variable.
1303 */
1304typedef enum
1305{
31d4b314
FP
1306 tnone, /* nothing seen */
1307 ttypedseen, /* typedef keyword seen */
1308 tinbody, /* inside typedef body */
46c145db
FP
1309 tend, /* just before typedef tag */
1310 tignore /* junk after typedef tag */
13fde0cd
RS
1311} TYPEDST;
1312TYPEDST typdef;
1313
1314
46c145db
FP
1315 /*
1316 * struct-like structures (enum, struct and union) are recognized
1317 * using another simple finite automaton. `structdef' is its state
1318 * variable.
13fde0cd
RS
1319 */
1320typedef enum
1321{
1322 snone, /* nothing seen yet */
1323 skeyseen, /* struct-like keyword seen */
1324 stagseen, /* struct-like tag seen */
1325 scolonseen, /* colon seen after struct-like tag */
46e4cb76 1326 sinbody /* in struct body: recognize member func defs*/
13fde0cd
RS
1327} STRUCTST;
1328STRUCTST structdef;
46c145db 1329
13fde0cd
RS
1330/*
1331 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
42680d3c
FP
1332 * struct tag, and structtype is the type of the preceding struct-like
1333 * keyword.
13fde0cd
RS
1334 */
1335char structtag[BUFSIZ];
42680d3c 1336enum sym_type structtype;
13fde0cd
RS
1337
1338/*
1339 * Yet another little state machine to deal with preprocessor lines.
1340 */
1341typedef enum
1342{
1343 dnone, /* nothing seen */
1344 dsharpseen, /* '#' seen as first char on line */
1345 ddefineseen, /* '#' and 'define' seen */
46e4cb76 1346 dignorerest /* ignore rest of line */
13fde0cd
RS
1347} DEFINEST;
1348DEFINEST definedef;
1349
1350/*
1351 * Set this to TRUE, and the next token considered is called a function.
1352 * Used only for GNUmacs's function-defining macros.
1353 */
1354logical next_token_is_func;
1355
1356/*
1357 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1358 */
1359logical yacc_rules;
1360
6dd5561c
FP
1361/*
1362 * consider_token ()
1363 * checks to see if the current token is at the start of a
1364 * function, or corresponds to a typedef, or is a struct/union/enum
1365 * tag.
1366 *
1367 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1368 * C_EXT is which language we are looking at.
1369 *
1370 * In the future we will need some way to adjust where the end of
1371 * the token is; for instance, implementing the C++ keyword
1372 * `operator' properly will adjust the end of the token to be after
1373 * whatever follows `operator'.
1374 *
1375 * Globals
1376 * funcdef IN OUT
1377 * structdef IN OUT
1378 * definedef IN OUT
1379 * typdef IN OUT
1380 * next_token_is_func IN OUT
1381 */
1382
1383logical
1384consider_token (c, tokp, c_ext, cblev, is_func)
1385 register char c; /* IN: first char after the token */
1386 register TOKEN *tokp; /* IN: token pointer */
1387 int c_ext; /* IN: C extensions mask */
1388 int cblev; /* IN: curly brace level */
1389 logical *is_func; /* OUT */
1390{
1391 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1392
1393 /*
1394 * Advance the definedef state machine.
1395 */
1396 switch (definedef)
1397 {
1398 case dnone:
1399 /* We're not on a preprocessor line. */
1400 break;
1401 case dsharpseen:
1402 if (toktype == st_C_define)
1403 {
1404 definedef = ddefineseen;
1405 }
1406 else
1407 {
1408 definedef = dignorerest;
1409 }
1410 return (FALSE);
1411 case ddefineseen:
1412 /*
1413 * Make a tag for any macro.
1414 */
1415 definedef = dignorerest;
1416 *is_func = (c == '(');
1417 if (!*is_func && !constantypedefs)
1418 return (FALSE);
1419 else
1420 return (TRUE);
1421 case dignorerest:
1422 return (FALSE);
1423 default:
1424 error ("internal error: definedef value.", 0);
1425 }
1426
1427 /*
1428 * Now typedefs
1429 */
1430 switch (typdef)
1431 {
1432 case tnone:
1433 if (toktype == st_C_typedef)
1434 {
1435 if (typedefs)
1436 typdef = ttypedseen;
1437 funcdef = fnone;
1438 return (FALSE);
1439 }
1440 break;
1441 case ttypedseen:
1442 switch (toktype)
1443 {
1444 case st_none:
1445 case st_C_typespec:
1446 typdef = tend;
1447 break;
1448 case st_C_struct:
1449 case st_C_enum:
1450 break;
1451 }
1452 /* Do not return here, so the structdef stuff has a chance. */
1453 break;
1454 case tend:
1455 switch (toktype)
1456 {
1457 case st_C_typespec:
1458 case st_C_struct:
1459 case st_C_enum:
1460 return (FALSE);
1461 }
1462 return (TRUE);
1463 }
1464
1465 /*
1466 * This structdef business is currently only invoked when cblev==0.
1467 * It should be recursively invoked whatever the curly brace level,
1468 * and a stack of states kept, to allow for definitions of structs
1469 * within structs.
1470 *
1471 * This structdef business is NOT invoked when we are ctags and the
1472 * file is plain C. This is because a struct tag may have the same
1473 * name as another tag, and this loses with ctags.
1474 *
1475 * This if statement deals with the typdef state machine as
1476 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1477 * return (FALSE). All the other code here is for the structdef
1478 * state machine.
1479 */
1480 switch (toktype)
1481 {
1482 case st_C_struct:
1483 case st_C_enum:
1484 if (typdef == ttypedseen
1485 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1486 {
1487 structdef = skeyseen;
1488 structtype = toktype;
1489 }
1490 return (FALSE);
1491 }
1492 if (structdef == skeyseen)
1493 {
1494 if (structtype == st_C_struct)
1495 {
1496 strncpy (structtag, tokp->p, tokp->len);
1497 structtag[tokp->len] = '\0'; /* for struct/union/class */
1498 }
1499 else
1500 {
1501 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1502 }
1503 structdef = stagseen;
1504 return (TRUE);
1505 }
1506
1507 /* Avoid entering funcdef stuff if typdef is going on. */
1508 if (typdef != tnone)
1509 {
1510 definedef = dnone;
1511 return (FALSE);
1512 }
1513
1514 /* Detect GNUmacs's function-defining macros. */
1515 if (definedef == dnone)
1516 {
1517 if (strneq (tokp->p, "DEF", 3)
1518 || strneq (tokp->p, "ENTRY", 5)
1519 || strneq (tokp->p, "SYSCALL", 7)
1520 || strneq (tokp->p, "PSEUDO", 6))
1521 {
1522 next_token_is_func = TRUE;
1523 return (FALSE);
1524 }
1525 if (strneq (tokp->p, "EXFUN", 5))
1526 {
1527 next_token_is_func = FALSE;
1528 return (FALSE);
1529 }
1530 }
1531 if (next_token_is_func)
1532 {
1533 next_token_is_func = FALSE;
1534 funcdef = fnone;
1535 *is_func = TRUE; /* to force search string in ctags */
1536 return (TRUE);
1537 }
1538
1539 /* A function? */
1540 switch (toktype)
1541 {
1542 case st_C_typespec:
1543 if (funcdef != finlist && funcdef != fignore)
1544 funcdef = fnone; /* should be useless */
1545 return (FALSE);
1546 default:
1547 if (funcdef == fnone)
1548 {
1549 funcdef = ftagseen;
1550 *is_func = TRUE;
1551 return (TRUE);
1552 }
1553 }
1554
1555 return (FALSE);
1556}
1557
c6d46f5f
JB
1558/*
1559 * C_entries ()
13fde0cd
RS
1560 * This routine finds functions, typedefs, #define's and
1561 * struct/union/enum definitions in C syntax and adds them
c6d46f5f
JB
1562 * to the list.
1563 */
1564
13fde0cd
RS
1565#define curlb (lbs[curndx].lb)
1566#define othlb (lbs[1-curndx].lb)
1567#define newlb (lbs[newndx].lb)
1568#define curlinepos (lbs[curndx].linepos)
1569#define othlinepos (lbs[1-curndx].linepos)
1570#define newlinepos (lbs[newndx].linepos)
1571
b12756c8
FP
1572/* Save and restore token state. This is used when preprocessor defines
1573 are handled, to avoid disturbing active function/typedef/struct states. */
1574#define TOKEN_SAVED_P (savetok.lineno > 0)
1575#define SAVE_TOKEN (savetok = tok, savetok.p = (char *) tokoff, \
1576 savetok.len = toklen, strcpy(savenameb, nameb))
1577#define RESTORE_TOKEN (tok = savetok, tokoff = (int) tok.p, \
1578 toklen = tok.len, strcpy(nameb, savenameb), \
1579 savetok.lineno = 0)
1580
c6d46f5f 1581#define CNL_SAVE_DEFINEDEF \
13fde0cd
RS
1582do { \
1583 SET_FILEPOS (curlinepos, inf, charno); \
c6d46f5f 1584 lineno++; \
13fde0cd
RS
1585 charno += readline (&curlb, inf); \
1586 lp = curlb.buffer; \
1587 quotednl = FALSE; \
1588 newndx = curndx; \
1589} while (FALSE)
c6d46f5f
JB
1590
1591#define CNL \
13fde0cd 1592do { \
c6d46f5f 1593 CNL_SAVE_DEFINEDEF; \
b12756c8
FP
1594 if (TOKEN_SAVED_P) \
1595 RESTORE_TOKEN; \
c6d46f5f 1596 definedef = dnone; \
13fde0cd
RS
1597} while (FALSE)
1598
fe0b3356 1599#define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
13fde0cd 1600 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
fe0b3356 1601#define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
13fde0cd 1602 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
c6d46f5f
JB
1603
1604void
6dd5561c 1605C_entries (c_ext, inf)
c6d46f5f 1606 int c_ext; /* extension of C? */
6dd5561c 1607 FILE *inf;
c6d46f5f 1608{
13fde0cd 1609 register char c; /* latest char read; '\0' for end of line */
c6d46f5f 1610 register char *lp; /* pointer one beyond the character `c' */
13fde0cd
RS
1611 int curndx, newndx; /* indices for current and new lb */
1612 TOKEN tok; /* latest token read for funcdef & structdef */
fe0b3356 1613 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
13fde0cd
RS
1614 register int tokoff; /* offset in line of start of latest token */
1615 register int toklen; /* length of latest token */
591fa824 1616 int cblev; /* current curly brace level */
b12756c8 1617 int parlev; /* current parenthesis level */
13fde0cd
RS
1618 logical incomm, inquote, inchar, quotednl, midtoken;
1619 logical cplpl;
b12756c8 1620 TOKEN savetok; /* saved token during preprocessor handling */
b12756c8 1621 char savenameb[BUFSIZ]; /* ouch! */
c6d46f5f 1622
b12756c8 1623 savetok.lineno = 0;
13fde0cd 1624 curndx = newndx = 0;
c6d46f5f
JB
1625 lineno = 0;
1626 charno = 0;
13fde0cd 1627 lp = curlb.buffer;
c6d46f5f
JB
1628 *lp = 0;
1629
46c145db 1630 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
13fde0cd
RS
1631 next_token_is_func = yacc_rules = FALSE;
1632 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1633 cblev = 0;
b12756c8 1634 parlev = 0;
13fde0cd 1635 cplpl = c_ext & C_PLPL;
c6d46f5f 1636
c6d46f5f
JB
1637 while (!feof (inf))
1638 {
1639 c = *lp++;
c6d46f5f
JB
1640 if (c == '\\')
1641 {
4746118a
JB
1642 /* If we're at the end of the line, the next character is a
1643 '\0'; don't skip it, because it's the thing that tells us
1644 to read the next line. */
13fde0cd 1645 if (*lp == '\0')
99e0a2e0 1646 {
13fde0cd 1647 quotednl = TRUE;
99e0a2e0
RS
1648 continue;
1649 }
1e134a5f 1650 lp++;
c6d46f5f
JB
1651 c = ' ';
1652 }
1653 else if (incomm)
1654 {
13fde0cd 1655 switch (c)
c6d46f5f 1656 {
13fde0cd
RS
1657 case '*':
1658 if (*lp == '/')
1659 {
1660 c = *lp++;
1661 incomm = FALSE;
1662 }
1663 break;
1664 case '\0':
1665 /* Newlines inside comments do not end macro definitions in
1666 traditional cpp. */
1667 CNL_SAVE_DEFINEDEF;
1668 break;
c6d46f5f 1669 }
13fde0cd 1670 continue;
c6d46f5f
JB
1671 }
1672 else if (inquote)
1673 {
13fde0cd
RS
1674 switch (c)
1675 {
1676 case '"':
1677 inquote = FALSE;
1678 break;
1679 case '\0':
42680d3c 1680 /* Newlines inside strings do not end macro definitions
13fde0cd
RS
1681 in traditional cpp, even though compilers don't
1682 usually accept them. */
1683 CNL_SAVE_DEFINEDEF;
1684 break;
1685 }
1686 continue;
c6d46f5f
JB
1687 }
1688 else if (inchar)
1689 {
42680d3c
FP
1690 switch (c)
1691 {
1692 case '\0':
1693 /* Hmmm, something went wrong. */
1694 CNL;
1695 /* FALLTHRU */
1696 case '\'':
46c145db 1697 inchar = FALSE;
42680d3c
FP
1698 break;
1699 }
c6d46f5f
JB
1700 continue;
1701 }
13fde0cd 1702 else
c6d46f5f
JB
1703 switch (c)
1704 {
1705 case '"':
1706 inquote = TRUE;
b12756c8
FP
1707 if (funcdef != finlist && funcdef != fignore)
1708 funcdef = fnone;
c6d46f5f
JB
1709 continue;
1710 case '\'':
1711 inchar = TRUE;
b12756c8
FP
1712 if (funcdef != finlist && funcdef != fignore)
1713 funcdef = fnone;
c6d46f5f
JB
1714 continue;
1715 case '/':
1716 if (*lp == '*')
1717 {
1718 lp++;
1719 incomm = TRUE;
13fde0cd 1720 continue;
c6d46f5f 1721 }
13fde0cd 1722 else if (cplpl && *lp == '/')
c6d46f5f 1723 {
daa37602
JB
1724 c = 0;
1725 break;
c6d46f5f 1726 }
b12756c8
FP
1727 else
1728 break;
13fde0cd
RS
1729 case '%':
1730 if ((c_ext & YACC) && *lp == '%')
1731 {
1732 /* entering or exiting rules section in yacc file */
1733 lp++;
1734 definedef = dnone; funcdef = fnone;
46c145db 1735 typdef = tnone; structdef = snone;
13fde0cd
RS
1736 next_token_is_func = FALSE;
1737 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1738 cblev = 0;
13fde0cd
RS
1739 yacc_rules = !yacc_rules;
1740 continue;
591fa824 1741 }
b12756c8
FP
1742 else
1743 break;
c6d46f5f 1744 case '#':
13fde0cd 1745 if (lp == newlb.buffer + 1 && definedef == dnone)
c6d46f5f
JB
1746 definedef = dsharpseen;
1747 continue;
13fde0cd 1748 } /* switch (c) */
c6d46f5f 1749
c6d46f5f 1750
591fa824
RS
1751 /* Consider token only if some complicated conditions are satisfied. */
1752 if (((cblev == 0 && structdef != scolonseen)
1753 || (cblev == 1 && cplpl && structdef == sinbody))
46c145db 1754 && typdef != tignore
13fde0cd 1755 && definedef != dignorerest
b12756c8 1756 && (funcdef != finlist
46c145db 1757 || definedef != dnone))
c6d46f5f
JB
1758 {
1759 if (midtoken)
1760 {
1761 if (endtoken (c))
1762 {
b12756c8 1763 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
c6d46f5f
JB
1764 {
1765 /*
1766 * This handles :: in the middle, but not at beginning
1767 * of an identifier.
1768 */
1769 lp += 2;
1770 toklen += 3;
1771 }
1772 else
1773 {
fe0b3356 1774 logical is_func = FALSE;
c6d46f5f 1775
13fde0cd
RS
1776 tok.lineno = lineno;
1777 tok.p = newlb.buffer + tokoff;
c6d46f5f 1778 tok.len = toklen;
fe0b3356 1779 tok.named = FALSE;
13fde0cd 1780 if (yacc_rules
42680d3c 1781 || consider_token (c, &tok, c_ext, cblev, &is_func))
c6d46f5f 1782 {
99e0a2e0 1783 if (structdef == sinbody
fe0b3356
FP
1784 && definedef == dnone
1785 && is_func)
1786 /* function defined in C++ class body */
1787 {
1788 tok.named = TRUE;
1789 sprintf (nameb, "%s::%.*s",
13fde0cd
RS
1790 ((structtag[0] == '\0')
1791 ? "_anonymous_" : structtag),
c6d46f5f 1792 tok.len, tok.p);
c6d46f5f
JB
1793 }
1794 else
1795 {
fe0b3356 1796 sprintf (nameb, "%.*s", tok.len, tok.p);
c6d46f5f 1797 }
13fde0cd 1798
fe0b3356
FP
1799 if (structdef == stagseen
1800 || typdef == tend)
1801 tok.named = TRUE;
1802
b12756c8
FP
1803 if (definedef == dnone
1804 && (funcdef == ftagseen
1805 || structdef == stagseen
1806 || typdef == tend))
13fde0cd
RS
1807 {
1808 if (newndx == curndx)
1809 curndx = 1 - curndx; /* switch line buffers */
1810 }
1811 else
1812 MAKE_TAG_FROM_NEW_LB (is_func);
c6d46f5f
JB
1813 }
1814 midtoken = FALSE;
1815 }
13fde0cd 1816 } /* if (endtoken (c)) */
c6d46f5f 1817 else if (intoken (c))
13fde0cd
RS
1818 {
1819 toklen++;
1820 continue;
1821 }
1822 } /* if (midtoken) */
c6d46f5f
JB
1823 else if (begtoken (c))
1824 {
b12756c8 1825 switch (definedef)
13fde0cd 1826 {
b12756c8
FP
1827 case dnone:
1828 switch (funcdef)
1829 {
1830 case fstartlist:
1831 funcdef = finlist;
1832 continue;
1833 case flistseen:
1834 MAKE_TAG_FROM_OTH_LB (TRUE);
1835 funcdef = fignore;
1836 break;
1837 case ftagseen:
1838 funcdef = fnone;
1839 break;
1840 }
1841 if (structdef == stagseen)
1842 structdef = snone;
13fde0cd 1843 break;
b12756c8
FP
1844 case dsharpseen:
1845 /* Take a quick peek ahead for define directive,
1846 so we can avoid saving the token when not absolutely
1847 necessary. [This is a speed hack.] */
1848 if (c == 'd' && strneq(lp, "efine", 5)
1849 && iswhite(*(lp + 5)))
1850 {
1851 SAVE_TOKEN;
1852 definedef = ddefineseen;
1853 lp += 6;
1854 }
1855 else
1856 definedef = dignorerest;
1857 continue;
13fde0cd 1858 }
13fde0cd
RS
1859 if (!yacc_rules || lp == newlb.buffer + 1)
1860 {
1861 tokoff = lp - 1 - newlb.buffer;
1862 toklen = 1;
1863 midtoken = TRUE;
1864 }
1865 continue;
c6d46f5f 1866 }
13fde0cd
RS
1867 } /* if must look at token */
1868
1869
1870 /* Detect end of line, colon, comma, semicolon and various braces
b12756c8 1871 after having handled a token.*/
13fde0cd 1872 switch (c)
1e134a5f 1873 {
13fde0cd 1874 case ':':
b12756c8
FP
1875 if (definedef != dnone)
1876 break;
13fde0cd
RS
1877 if (structdef == stagseen)
1878 structdef = scolonseen;
b12756c8
FP
1879 else
1880 switch (funcdef)
1881 {
1882 case ftagseen:
1883 if (yacc_rules)
1884 {
1885 MAKE_TAG_FROM_OTH_LB (FALSE);
1886 funcdef = fignore;
1887 }
1888 break;
1889 case fstartlist:
1890 funcdef = fnone;
1891 break;
1892 }
13fde0cd
RS
1893 break;
1894 case ';':
b12756c8
FP
1895 if (definedef != dnone)
1896 break;
46c145db
FP
1897 if (cblev == 0)
1898 switch (typdef)
1899 {
1900 case tend:
1901 MAKE_TAG_FROM_OTH_LB (FALSE);
1902 /* FALLTHRU */
1903 default:
1904 typdef = tnone;
1905 }
31d4b314
FP
1906 if (funcdef != fignore)
1907 funcdef = fnone;
46c145db
FP
1908 if (structdef == stagseen)
1909 structdef = snone;
1910 break;
13fde0cd 1911 case ',':
46c145db
FP
1912 if (definedef != dnone)
1913 break;
1914 if (funcdef != finlist && funcdef != fignore)
1915 funcdef = fnone;
1916 if (structdef == stagseen)
1917 structdef = snone;
1918 break;
13fde0cd 1919 case '[':
b12756c8
FP
1920 if (definedef != dnone)
1921 break;
46c145db
FP
1922 if (cblev == 0 && typdef == tend)
1923 {
1924 typdef = tignore;
1925 MAKE_TAG_FROM_OTH_LB (FALSE);
1926 break;
1927 }
31d4b314 1928 if (funcdef != finlist && funcdef != fignore)
13fde0cd
RS
1929 funcdef = fnone;
1930 if (structdef == stagseen)
1931 structdef = snone;
1932 break;
1933 case '(':
b12756c8
FP
1934 if (definedef != dnone)
1935 break;
13fde0cd 1936 switch (funcdef)
57e83cfe 1937 {
13fde0cd 1938 case ftagseen:
b12756c8 1939 funcdef = fstartlist;
13fde0cd 1940 break;
13fde0cd 1941 case flistseen:
b12756c8 1942 funcdef = finlist;
13fde0cd 1943 break;
57e83cfe 1944 }
b12756c8 1945 parlev++;
13fde0cd
RS
1946 break;
1947 case ')':
b12756c8
FP
1948 if (definedef != dnone)
1949 break;
1950 if (--parlev == 0)
1951 {
1952 switch (funcdef)
1953 {
1954 case fstartlist:
1955 case finlist:
1956 funcdef = flistseen;
1957 break;
1958 }
46c145db
FP
1959 if (cblev == 0 && typdef == tend)
1960 {
1961 typdef = tignore;
1962 MAKE_TAG_FROM_OTH_LB (FALSE);
1963 }
b12756c8
FP
1964 }
1965 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
1966 parlev = 0;
13fde0cd
RS
1967 break;
1968 case '{':
b12756c8
FP
1969 if (definedef != dnone)
1970 break;
13fde0cd
RS
1971 if (typdef == ttypedseen)
1972 typdef = tinbody;
1973 switch (structdef)
1974 {
1975 case skeyseen: /* unnamed struct */
1976 structtag[0] = '\0';
1977 structdef = sinbody;
1978 break;
1979 case stagseen:
1980 case scolonseen: /* named struct */
1981 structdef = sinbody;
1982 MAKE_TAG_FROM_OTH_LB (FALSE);
1983 break;
1984 }
31d4b314
FP
1985 switch (funcdef)
1986 {
1987 case flistseen:
1988 MAKE_TAG_FROM_OTH_LB (TRUE);
1989 /* FALLTHRU */
1990 case fignore:
1991 funcdef = fnone;
46c145db
FP
1992 break;
1993 case fnone:
1994 /* Neutralize `extern "C" {' grot.
1995 if (cblev == 0 && structdef == snone && typdef == tnone)
1996 cblev--; */;
31d4b314 1997 }
591fa824 1998 cblev++;
31d4b314 1999 break;
13fde0cd 2000 case '*':
b12756c8
FP
2001 if (definedef != dnone)
2002 break;
2003 if (funcdef == fstartlist)
2004 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
13fde0cd
RS
2005 break;
2006 case '}':
b12756c8
FP
2007 if (definedef != dnone)
2008 break;
13fde0cd 2009 if (!noindentypedefs && lp == newlb.buffer + 1)
b12756c8
FP
2010 {
2011 cblev = 0; /* reset curly brace level if first column */
2012 parlev = 0; /* also reset paren level, just in case... */
2013 }
591fa824
RS
2014 else if (cblev > 0)
2015 cblev--;
2016 if (cblev == 0)
13fde0cd
RS
2017 {
2018 if (typdef == tinbody)
2019 typdef = tend;
2020 structdef = snone;
1a0d8c80 2021 strcpy (structtag, "<error 2>");
13fde0cd
RS
2022 }
2023 break;
b12756c8 2024 case '=':
42680d3c
FP
2025 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2026 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
b12756c8
FP
2027 if (definedef != dnone)
2028 break;
2029 /* These surely cannot follow a function tag. */
2030 if (funcdef != finlist && funcdef != fignore)
2031 funcdef = fnone;
2032 break;
13fde0cd
RS
2033 case '\0':
2034 /* If a macro spans multiple lines don't reset its state. */
2035 if (quotednl)
2036 CNL_SAVE_DEFINEDEF;
2037 else
2038 CNL;
2039 break;
2040 } /* switch (c) */
2041
2042 } /* while not eof */
c6d46f5f 2043}
6dd5561c
FP
2044\f
2045/* Fortran parsing */
c6d46f5f 2046
6dd5561c
FP
2047char *dbp;
2048int pfcnt;
c6d46f5f
JB
2049
2050logical
6dd5561c
FP
2051tail (cp)
2052 char *cp;
c6d46f5f 2053{
6dd5561c 2054 register int len = 0;
c6d46f5f 2055
6dd5561c
FP
2056 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2057 cp++, len++;
2058 if (*cp == 0)
c6d46f5f 2059 {
6dd5561c 2060 dbp += len;
13fde0cd 2061 return (TRUE);
c6d46f5f 2062 }
6dd5561c
FP
2063 return (FALSE);
2064}
13fde0cd 2065
6dd5561c
FP
2066void
2067takeprec ()
2068{
2069 while (isspace (*dbp))
2070 dbp++;
2071 if (*dbp != '*')
2072 return;
2073 dbp++;
2074 while (isspace (*dbp))
2075 dbp++;
2076 if (!isdigit (*dbp))
c6d46f5f 2077 {
6dd5561c
FP
2078 --dbp; /* force failure */
2079 return;
c6d46f5f 2080 }
6dd5561c
FP
2081 do
2082 dbp++;
2083 while (isdigit (*dbp));
2084}
13fde0cd 2085
6dd5561c
FP
2086void
2087getit (inf)
2088 FILE *inf;
2089{
2090 register char *cp;
2091 char c;
2092 char nambuf[BUFSIZ];
13fde0cd 2093
6dd5561c
FP
2094 while (isspace (*dbp))
2095 dbp++;
2096 if (*dbp == '\0')
c6d46f5f 2097 {
6dd5561c
FP
2098 lineno++;
2099 linecharno = charno;
2100 charno += readline (&lb, inf);
2101 dbp = lb.buffer;
2102 if (dbp[5] != '&')
2103 return;
2104 dbp += 6;
2105 while (isspace (*dbp))
2106 dbp++;
c6d46f5f 2107 }
6dd5561c
FP
2108 if (!isalpha (*dbp)
2109 && *dbp != '_'
2110 && *dbp != '$')
2111 return;
2112 for (cp = dbp + 1;
2113 (*cp
2114 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2115 cp++)
2116 continue;
2117 c = *cp;
2118 *cp = '\0';
2119 strcpy (nambuf, dbp);
2120 *cp = c;
2121 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2122 cp - lb.buffer + 1, lineno, linecharno);
2123 pfcnt++;
c6d46f5f 2124}
c6d46f5f
JB
2125
2126int
6dd5561c
FP
2127Fortran_functions (inf)
2128 FILE *inf;
c6d46f5f
JB
2129{
2130 lineno = 0;
2131 charno = 0;
2132 pfcnt = 0;
2133
6dd5561c 2134 while (!feof (inf))
c6d46f5f
JB
2135 {
2136 lineno++;
2137 linecharno = charno;
6dd5561c 2138 charno += readline (&lb, inf);
c6d46f5f
JB
2139 dbp = lb.buffer;
2140 if (*dbp == '%')
2141 dbp++; /* Ratfor escape to fortran */
2142 while (isspace (*dbp))
2143 dbp++;
2144 if (*dbp == 0)
2145 continue;
2146 switch (*dbp | ' ')
2147 {
2148 case 'i':
2149 if (tail ("integer"))
2150 takeprec ();
2151 break;
2152 case 'r':
2153 if (tail ("real"))
2154 takeprec ();
2155 break;
2156 case 'l':
2157 if (tail ("logical"))
2158 takeprec ();
2159 break;
2160 case 'c':
2161 if (tail ("complex") || tail ("character"))
2162 takeprec ();
2163 break;
2164 case 'd':
2165 if (tail ("double"))
2166 {
2167 while (isspace (*dbp))
2168 dbp++;
2169 if (*dbp == 0)
2170 continue;
2171 if (tail ("precision"))
2172 break;
2173 continue;
2174 }
2175 break;
2176 }
2177 while (isspace (*dbp))
2178 dbp++;
2179 if (*dbp == 0)
2180 continue;
2181 switch (*dbp | ' ')
2182 {
2183 case 'f':
2184 if (tail ("function"))
6dd5561c 2185 getit (inf);
c6d46f5f
JB
2186 continue;
2187 case 's':
2188 if (tail ("subroutine"))
6dd5561c 2189 getit (inf);
c6d46f5f 2190 continue;
8a6c8bcf
RS
2191 case 'e':
2192 if (tail ("entry"))
6dd5561c 2193 getit (inf);
8a6c8bcf 2194 continue;
c6d46f5f
JB
2195 case 'p':
2196 if (tail ("program"))
2197 {
6dd5561c 2198 getit (inf);
c6d46f5f
JB
2199 continue;
2200 }
2201 if (tail ("procedure"))
6dd5561c 2202 getit (inf);
c6d46f5f
JB
2203 continue;
2204 }
2205 }
2206 return (pfcnt);
2207}
6dd5561c
FP
2208\f
2209/*
2210 * Bob Weiner, Motorola Inc., 4/3/94
2211 * Unix and microcontroller assembly tag handling
2212 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2213 */
c6d46f5f 2214void
6dd5561c
FP
2215Asm_labels (inf)
2216 FILE *inf;
c6d46f5f 2217{
6dd5561c 2218 char nambuf[BUFSIZ];
c6d46f5f
JB
2219 register char *cp;
2220 char c;
c6d46f5f
JB
2221
2222 lineno = 0;
2223 charno = 0;
2224 pfcnt = 0;
2225
6dd5561c 2226 while (!feof (inf))
c6d46f5f
JB
2227 {
2228 lineno++;
2229 linecharno = charno;
6dd5561c
FP
2230 charno += readline (&lb, inf);
2231 cp = lb.buffer;
2232
2233 /* If first char is alphabetic or one of [_.$], test for colon
2234 following identifier. */
2235 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2236 {
2237 /* Read past label. */
2238 cp++;
2239 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2240 cp++;
2241 if (*cp == ':' || isspace (*cp))
2242 {
2243 /* Found end of label, so copy it and add it to the table. */
2244 c = *cp;
2245 *cp = '\0';
2246 strcpy (nambuf, lb.buffer);
2247 *cp = c;
2248 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2249 cp - lb.buffer + 1, lineno, linecharno);
2250 pfcnt++;
2251 }
2252 }
c6d46f5f
JB
2253 }
2254}
2255\f
2256/* Added by Mosur Mohan, 4/22/88 */
2257/* Pascal parsing */
2258
2259#define GET_NEW_LINE \
2260{ \
2261 linecharno = charno; lineno++; \
2262 charno += 1 + readline (&lb, inf); \
2263 dbp = lb.buffer; \
2264}
2265
2266/* Locates tags for procedures & functions.
2267 * Doesn't do any type- or var-definitions.
2268 * It does look for the keyword "extern" or "forward"
2269 * immediately following the procedure statement;
2270 * if found, the tag is skipped.
2271 */
2272
2273void
6dd5561c
FP
2274Pascal_functions (inf)
2275 FILE *inf;
c6d46f5f
JB
2276{
2277 struct linebuffer tline; /* mostly copied from C_entries */
2278 long save_lcno;
2279 int save_lineno;
2280 char c, *cp;
2281 char nambuf[BUFSIZ];
2282
2283 logical /* each of these flags is TRUE iff: */
2284 incomm1, /* point is inside {..} comment */
2285 incomm2, /* point is inside (*..*) comment */
2286 inquote, /* point is inside '..' string */
2287 get_tagname, /* point is after PROCEDURE/FUNCTION */
2288 /* keyword, so next item = potential tag */
2289 found_tag, /* point is after a potential tag */
2290 inparms, /* point is within parameter-list */
2291 verify_tag; /* point has passed the parm-list, so the */
2292 /* next token will determine whether */
2293 /* this is a FORWARD/EXTERN to be */
2294 /* ignored, or whether it is a real tag */
2295
2296 lineno = 0;
2297 charno = 0;
2298 dbp = lb.buffer;
2299 *dbp = 0;
2300 initbuffer (&tline);
2301
2302 incomm1 = incomm2 = inquote = FALSE;
2303 found_tag = FALSE; /* have a proc name; check if extern */
2304 get_tagname = FALSE; /* have found "procedure" keyword */
2305 inparms = FALSE; /* found '(' after "proc" */
2306 verify_tag = FALSE; /* check if "extern" is ahead */
2307
2308 /* long main loop to get next char */
6dd5561c 2309 while (!feof (inf))
c6d46f5f
JB
2310 {
2311 c = *dbp++;
2312 if (c == 0) /* if end of line */
2313 {
2314 GET_NEW_LINE;
2315 if (*dbp == 0)
2316 continue;
2317 if (!((found_tag && verify_tag) ||
2318 get_tagname))
2319 c = *dbp++; /* only if don't need *dbp pointing */
2320 /* to the beginning of the name of */
2321 /* the procedure or function */
2322 }
2323 if (incomm1) /* within { - } comments */
2324 {
2325 if (c == '}')
2326 incomm1 = FALSE;
2327 continue;
2328 }
2329 else if (incomm2) /* within (* - *) comments */
2330 {
2331 if (c == '*')
2332 {
2333 while ((c = *dbp++) == '*')
2334 continue;
2335 if (c == 0)
2336 GET_NEW_LINE;
2337 if (c == ')')
2338 incomm2 = FALSE;
2339 }
2340 continue;
2341 }
2342 else if (inquote)
2343 {
2344 if (c == '\'')
2345 inquote = FALSE;
2346 continue;
2347 }
2348 else
2349 switch (c)
2350 {
2351 case '\'':
2352 inquote = TRUE; /* found first quote */
2353 continue;
2354 case '{': /* found open-{-comment */
2355 incomm1 = TRUE;
2356 continue;
2357 case '(':
2358 if (*dbp == '*') /* found open-(*-comment */
2359 {
2360 incomm2 = TRUE;
2361 dbp++;
2362 }
2363 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2364 inparms = TRUE;
2365 continue;
2366 case ')': /* end of parms list */
2367 if (inparms)
2368 inparms = FALSE;
2369 continue;
2370 case ';':
2371 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2372 {
2373 verify_tag = TRUE;
2374 break;
2375 }
2376 continue;
2377 }
2378 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2379 {
2380 /* check if this is an "extern" declaration */
2381 if (*dbp == 0)
2382 continue;
2383 if ((*dbp == 'e') || (*dbp == 'E'))
2384 {
2385 if (tail ("extern")) /* superfluous, really! */
2386 {
2387 found_tag = FALSE;
2388 verify_tag = FALSE;
2389 }
2390 }
2391 else if ((*dbp == 'f') || (*dbp == 'F'))
2392 {
2393 if (tail ("forward")) /* check for forward reference */
2394 {
2395 found_tag = FALSE;
2396 verify_tag = FALSE;
2397 }
2398 }
46c145db 2399 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
c6d46f5f
JB
2400 {
2401 found_tag = FALSE;
2402 verify_tag = FALSE;
2403 pfnote (nambuf, TRUE, FALSE,
2404 tline.buffer, cp - tline.buffer + 1,
2405 save_lineno, save_lcno);
2406 continue;
2407 }
2408 }
2409 if (get_tagname) /* grab name of proc or fn */
2410 {
2411 if (*dbp == 0)
2412 continue;
2413
2414 /* save all values for later tagging */
2415 tline.size = lb.size;
2416 strcpy (tline.buffer, lb.buffer);
2417 save_lineno = lineno;
2418 save_lcno = linecharno;
2419
2420 /* grab block name */
2421 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2422 continue;
2423 c = cp[0];
2424 cp[0] = 0;
2425 strcpy (nambuf, dbp);
2426 cp[0] = c;
2427 dbp = cp; /* restore dbp to e-o-token */
2428 get_tagname = FALSE;
2429 found_tag = TRUE;
2430 continue;
2431
2432 /* and proceed to check for "extern" */
2433 }
2434 if ((!incomm1) && (!incomm2) && (!inquote) &&
2435 (!found_tag) && (!get_tagname))
2436 {
2437 /* check for proc/fn keywords */
2438 switch (c | ' ')
2439 {
2440 case 'p':
2441 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2442 get_tagname = TRUE;
2443 continue;
2444 case 'f':
2445 if (tail ("unction"))
2446 get_tagname = TRUE;
2447 continue;
2448 }
2449 }
6dd5561c 2450 } /* while not eof */
c6d46f5f
JB
2451}
2452\f
2453/*
2454 * lisp tag functions
2455 * just look for (def or (DEF
2456 */
2457
c6d46f5f
JB
2458int
2459L_isdef (dbp)
31d4b314 2460 register char *dbp;
c6d46f5f 2461{
31d4b314
FP
2462 return ((dbp[1] == 'd' || dbp[1] == 'D')
2463 && (dbp[2] == 'e' || dbp[2] == 'E')
2464 && (dbp[3] == 'f' || dbp[3] == 'F'));
2465}
2466
2467int
2468L_isquote (dbp)
2469 register char *dbp;
2470{
2471 return ((*(++dbp) == 'q' || *dbp == 'Q')
2472 && (*(++dbp) == 'u' || *dbp == 'U')
2473 && (*(++dbp) == 'o' || *dbp == 'O')
2474 && (*(++dbp) == 't' || *dbp == 'T')
2475 && (*(++dbp) == 'e' || *dbp == 'E')
2476 && isspace(*(++dbp)));
c6d46f5f
JB
2477}
2478
2479void
2480L_getit ()
2481{
2482 register char *cp;
2483 char c;
2484 char nambuf[BUFSIZ];
2485
31d4b314
FP
2486 if (*dbp == '\'') /* Skip prefix quote */
2487 dbp++;
2488 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2489 {
2490 dbp += 7;
2491 while (isspace(*dbp))
2492 dbp++;
2493 }
2494 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
c6d46f5f 2495 continue;
31d4b314
FP
2496 if (cp == dbp)
2497 return;
2498
c6d46f5f
JB
2499 c = cp[0];
2500 cp[0] = 0;
1a0d8c80 2501 strcpy (nambuf, dbp);
c6d46f5f 2502 cp[0] = c;
591fa824
RS
2503 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2504 cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f
JB
2505 pfcnt++;
2506}
6dd5561c
FP
2507
2508void
2509Lisp_functions (inf)
2510 FILE *inf;
2511{
2512 lineno = 0;
2513 charno = 0;
2514 pfcnt = 0;
2515
2516 while (!feof (inf))
2517 {
2518 lineno++;
2519 linecharno = charno;
2520 charno += readline (&lb, inf);
2521 dbp = lb.buffer;
2522 if (dbp[0] == '(')
2523 {
2524 if (L_isdef (dbp))
2525 {
2526 while (!isspace (*dbp))
2527 dbp++;
2528 while (isspace (*dbp))
2529 dbp++;
2530 L_getit ();
2531 }
2532 else
2533 {
2534 /* Check for (foo::defmumble name-defined ... */
2535 do
2536 dbp++;
2537 while (*dbp && !isspace (*dbp)
2538 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2539 if (*dbp == ':')
2540 {
2541 do
2542 dbp++;
2543 while (*dbp == ':');
2544
2545 if (L_isdef (dbp - 1))
2546 {
2547 while (!isspace (*dbp))
2548 dbp++;
2549 while (isspace (*dbp))
2550 dbp++;
2551 L_getit ();
2552 }
2553 }
2554 }
2555 }
2556 }
2557}
c6d46f5f
JB
2558\f
2559/*
2560 * Scheme tag functions
2561 * look for (def... xyzzy
2562 * look for (def... (xyzzy
2563 * look for (def ... ((...(xyzzy ....
2564 * look for (set! xyzzy
2565 */
2566
6dd5561c 2567void get_scheme ();
c6d46f5f
JB
2568
2569void
6dd5561c
FP
2570Scheme_functions (inf)
2571 FILE *inf;
c6d46f5f
JB
2572{
2573 lineno = 0;
2574 charno = 0;
2575 pfcnt = 0;
2576
6dd5561c 2577 while (!feof (inf))
c6d46f5f
JB
2578 {
2579 lineno++;
2580 linecharno = charno;
6dd5561c 2581 charno += readline (&lb, inf);
c6d46f5f
JB
2582 dbp = lb.buffer;
2583 if (dbp[0] == '(' &&
2584 (dbp[1] == 'D' || dbp[1] == 'd') &&
2585 (dbp[2] == 'E' || dbp[2] == 'e') &&
2586 (dbp[3] == 'F' || dbp[3] == 'f'))
2587 {
2588 while (!isspace (*dbp))
2589 dbp++;
2590 /* Skip over open parens and white space */
2591 while (*dbp && (isspace (*dbp) || *dbp == '('))
2592 dbp++;
2593 get_scheme ();
2594 }
2595 if (dbp[0] == '(' &&
2596 (dbp[1] == 'S' || dbp[1] == 's') &&
2597 (dbp[2] == 'E' || dbp[2] == 'e') &&
2598 (dbp[3] == 'T' || dbp[3] == 't') &&
2599 (dbp[4] == '!' || dbp[4] == '!') &&
2600 (isspace (dbp[5])))
2601 {
2602 while (!isspace (*dbp))
2603 dbp++;
2604 /* Skip over white space */
2605 while (isspace (*dbp))
2606 dbp++;
2607 get_scheme ();
2608 }
2609 }
2610}
2611
6dd5561c 2612void
c6d46f5f
JB
2613get_scheme ()
2614{
2615 register char *cp;
2616 char c;
2617 char nambuf[BUFSIZ];
2618
2619 if (*dbp == 0)
2620 return;
2621 /* Go till you get to white space or a syntactic break */
2622 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2623 continue;
2624 /* Null terminate the string there. */
2625 c = cp[0];
2626 cp[0] = 0;
2627 /* Copy the string */
2628 strcpy (nambuf, dbp);
2629 /* Unterminate the string */
2630 cp[0] = c;
2631 /* Announce the change */
2632 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2633 pfcnt++;
2634}
2635\f
2636/* Find tags in TeX and LaTeX input files. */
2637
2638/* TEX_toktab is a table of TeX control sequences that define tags.
2639 Each TEX_tabent records one such control sequence.
2640 CONVERT THIS TO USE THE Stab TYPE!! */
2641
2642struct TEX_tabent
2643{
2644 char *name;
2645 int len;
2646};
2647
2648struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2649
2650/* Default set of control sequences to put into TEX_toktab.
2651 The value of environment var TEXTAGS is prepended to this. */
2652
6dd5561c
FP
2653char *TEX_defenv = "\
2654:chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
c6d46f5f
JB
2655
2656void TEX_mode ();
2657struct TEX_tabent *TEX_decode_env ();
2658void TEX_getit ();
2659int TEX_Token ();
2660
6dd5561c
FP
2661char TEX_esc = '\\';
2662char TEX_opgrp = '{';
2663char TEX_clgrp = '}';
c6d46f5f
JB
2664
2665/*
2666 * TeX/LaTeX scanning loop.
2667 */
2668
2669void
6dd5561c
FP
2670TeX_functions (inf)
2671 FILE *inf;
c6d46f5f
JB
2672{
2673 char *lasthit;
2674
2675 lineno = 0;
2676 charno = 0;
2677 pfcnt = 0;
2678
2679 /* Select either \ or ! as escape character. */
6dd5561c 2680 TEX_mode (inf);
c6d46f5f
JB
2681
2682 /* Initialize token table once from environment. */
2683 if (!TEX_toktab)
2684 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2685
6dd5561c 2686 while (!feof (inf))
d2729198 2687 { /* Scan each line in file */
c6d46f5f
JB
2688 lineno++;
2689 linecharno = charno;
6dd5561c 2690 charno += readline (&lb, inf);
c6d46f5f
JB
2691 dbp = lb.buffer;
2692 lasthit = dbp;
b02c5fea 2693 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
8a6c8bcf
RS
2694 {
2695 register int i;
c6d46f5f 2696
8a6c8bcf
RS
2697 if (!*(++dbp))
2698 break;
2699 linecharno += dbp - lasthit;
c6d46f5f 2700 lasthit = dbp;
8a6c8bcf
RS
2701 i = TEX_Token (lasthit);
2702 if (0 <= i)
c6d46f5f 2703 {
8a6c8bcf 2704 TEX_getit (lasthit, TEX_toktab[i].len);
d2729198 2705 break; /* We only save a line once */
c6d46f5f
JB
2706 }
2707 }
2708 }
2709}
2710
2711#define TEX_LESC '\\'
2712#define TEX_SESC '!'
2713#define TEX_cmt '%'
2714
2715/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2716/* chars accordingly. */
2717
2718void
6dd5561c
FP
2719TEX_mode (inf)
2720 FILE *inf;
c6d46f5f
JB
2721{
2722 int c;
2723
6dd5561c 2724 while ((c = getc (inf)) != EOF)
c6d46f5f
JB
2725 {
2726 /* Skip to next line if we hit the TeX comment char. */
2727 if (c == TEX_cmt)
2728 while (c != '\n')
6dd5561c 2729 c = getc (inf);
c6d46f5f
JB
2730 else if (c == TEX_LESC || c == TEX_SESC )
2731 break;
2732 }
2733
2734 if (c == TEX_LESC)
2735 {
2736 TEX_esc = TEX_LESC;
2737 TEX_opgrp = '{';
2738 TEX_clgrp = '}';
2739 }
2740 else
2741 {
2742 TEX_esc = TEX_SESC;
2743 TEX_opgrp = '<';
2744 TEX_clgrp = '>';
2745 }
6dd5561c 2746 rewind (inf);
c6d46f5f
JB
2747}
2748
2749/* Read environment and prepend it to the default string. */
2750/* Build token table. */
2751
2752struct TEX_tabent *
2753TEX_decode_env (evarname, defenv)
2754 char *evarname;
2755 char *defenv;
2756{
2757 register char *env, *p;
c6d46f5f
JB
2758
2759 struct TEX_tabent *tab;
2760 int size, i;
2761
2762 /* Append default string to environment. */
2763 env = getenv (evarname);
2764 if (!env)
2765 env = defenv;
2766 else
2767 env = concat (env, defenv, "");
2768
2769 /* Allocate a token table */
2770 for (size = 1, p = env; p;)
b02c5fea 2771 if ((p = etags_strchr (p, ':')) && *(++p))
c6d46f5f 2772 size++;
8a6c8bcf
RS
2773 /* Add 1 to leave room for null terminator. */
2774 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
2775
2776 /* Unpack environment string into token table. Be careful about */
2777 /* zero-length strings (leading ':', "::" and trailing ':') */
2778 for (i = 0; *env;)
2779 {
b02c5fea 2780 p = etags_strchr (env, ':');
c6d46f5f
JB
2781 if (!p) /* End of environment string. */
2782 p = env + strlen (env);
2783 if (p - env > 0)
2784 { /* Only non-zero strings. */
2785 tab[i].name = savenstr (env, p - env);
2786 tab[i].len = strlen (tab[i].name);
2787 i++;
2788 }
2789 if (*p)
2790 env = p + 1;
2791 else
2792 {
2793 tab[i].name = NULL; /* Mark end of table. */
2794 tab[i].len = 0;
2795 break;
2796 }
2797 }
2798 return tab;
2799}
2800
2801/* Record a tag defined by a TeX command of length LEN and starting at NAME.
2802 The name being defined actually starts at (NAME + LEN + 1).
2803 But we seem to include the TeX command in the tag name. */
2804
2805void
2806TEX_getit (name, len)
2807 char *name;
2808 int len;
2809{
2810 char *p = name + len;
2811 char nambuf[BUFSIZ];
2812
2813 if (*name == 0)
2814 return;
2815
2816 /* Let tag name extend to next group close (or end of line) */
2817 while (*p && *p != TEX_clgrp)
2818 p++;
1a0d8c80 2819 strncpy (nambuf, name, p - name);
c6d46f5f
JB
2820 nambuf[p - name] = 0;
2821
2822 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2823 pfcnt++;
2824}
2825
2826/* If the text at CP matches one of the tag-defining TeX command names,
b02c5fea 2827 return the pointer to the first occurrence of that command in TEX_toktab.
c6d46f5f
JB
2828 Otherwise return -1. */
2829
2830/* Keep the capital `T' in `Token' for dumb truncating compilers
2831 (this distinguishes it from `TEX_toktab' */
2832int
2833TEX_Token (cp)
2834 char *cp;
2835{
2836 int i;
2837
2838 for (i = 0; TEX_toktab[i].len > 0; i++)
1a0d8c80 2839 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
c6d46f5f
JB
2840 return i;
2841 return -1;
2842}
2843\f
2844/* Support for Prolog. */
2845
2846/* whole head (not only functor, but also arguments)
2847 is gotten in compound term. */
2848
2849void
2850prolog_getit (s, lineno, linecharno)
2851 char *s;
2852 int lineno;
2853 long linecharno;
2854{
2855 char nambuf[BUFSIZ], *save_s, tmpc;
2856 int insquote, npar;
2857
2858 save_s = s;
2859 insquote = FALSE;
2860 npar = 0;
2861 while (1)
2862 {
2863 if (*s == '\0') /* syntax error. */
2864 return;
2865 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2866 s += 2;
2867 else if (*s == '\'')
2868 {
2869 insquote = !insquote;
2870 s++;
2871 }
2872 else if (!insquote && *s == '(')
2873 {
2874 npar++;
2875 s++;
2876 }
2877 else if (!insquote && *s == ')')
2878 {
2879 npar--;
2880 s++;
2881 if (npar == 0)
2882 break;
2883 else if (npar < 0) /* syntax error. */
2884 return;
2885 }
2886 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2887 { /* fullstop. */
2888 if (npar != 0) /* syntax error. */
2889 return;
2890 s++;
2891 break;
2892 }
2893 else
2894 s++;
2895 }
2896 tmpc = *s;
2897 *s = '\0';
2898 strcpy (nambuf, save_s);
2899 *s = tmpc;
bff8edcc 2900 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
c6d46f5f
JB
2901}
2902
2903/* It is assumed that prolog predicate starts from column 0. */
2904
2905void
6dd5561c
FP
2906Prolog_functions (inf)
2907 FILE *inf;
c6d46f5f
JB
2908{
2909 void skip_comment (), prolog_getit ();
2910
2911 lineno = linecharno = charno = 0;
6dd5561c 2912 while (!feof (inf))
c6d46f5f
JB
2913 {
2914 lineno++;
2915 linecharno += charno;
6dd5561c 2916 charno = readline (&lb, inf) + 1; /* 1 for newline. */
c6d46f5f
JB
2917 dbp = lb.buffer;
2918 if (isspace (dbp[0])) /* not predicate header. */
2919 continue;
2920 else if (dbp[0] == '%') /* comment. */
2921 continue;
2922 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
6dd5561c 2923 skip_comment (&lb, inf, &lineno, &linecharno);
c6d46f5f
JB
2924 else /* found. */
2925 prolog_getit (dbp, lineno, linecharno);
2926 }
2927}
2928
2929void
6dd5561c 2930skip_comment (plb, inf, plineno, plinecharno)
c6d46f5f 2931 struct linebuffer *plb;
6dd5561c 2932 FILE *inf;
c6d46f5f
JB
2933 int *plineno; /* result */
2934 long *plinecharno; /* result */
2935{
2936 while (!substr ("*/", plb->buffer))
2937 {
2938 (*plineno)++;
6dd5561c 2939 *plinecharno += readline (plb, inf) + 1;
c6d46f5f
JB
2940 } /* 1 for newline. */
2941}
2942
2943/* Return TRUE if 'sub' exists somewhere in 's'. */
2944
2945int
2946substr (sub, s)
2947 char *sub;
2948 char *s;
2949{
b02c5fea 2950 while (*s && (s = etags_strchr (s, *sub)))
c6d46f5f
JB
2951 if (prestr (sub, s))
2952 return (TRUE);
2953 else
2954 s++;
2955 return (FALSE);
2956}
2957
2958/* Return TRUE if 'pre' is prefix of string 's'. */
2959
2960int
2961prestr (pre, s)
2962 char *pre;
2963 char *s;
2964{
2965 if (*pre == '\0')
2966 return (TRUE);
2967 else if (*pre == *s)
2968 return (prestr (pre + 1, s + 1));
2969 else
2970 return (FALSE);
2971}
2972\f
2973/* Initialize a linebuffer for use */
2974
2975void
2976initbuffer (linebuffer)
2977 struct linebuffer *linebuffer;
2978{
2979 linebuffer->size = 200;
2980 linebuffer->buffer = xnew (200, char);
2981}
2982
2983/*
2984 * Read a line of text from `stream' into `linebuffer'.
2985 * Return the number of characters read from `stream',
2986 * which is the length of the line including the newline, if any.
2987 */
2988long
2989readline (linebuffer, stream)
2990 struct linebuffer *linebuffer;
2991 register FILE *stream;
2992{
2993 char *buffer = linebuffer->buffer;
2994 register char *p = linebuffer->buffer;
2995 register char *pend;
2996 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2997
eb8c3be9 2998 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
c6d46f5f
JB
2999
3000 while (1)
3001 {
3002 register int c = getc (stream);
3003 if (p == pend)
3004 {
3005 linebuffer->size *= 2;
3006 buffer = (char *) xrealloc (buffer, linebuffer->size);
3007 p += buffer - linebuffer->buffer;
3008 pend = buffer + linebuffer->size;
3009 linebuffer->buffer = buffer;
3010 }
42680d3c 3011 if (c == EOF || c == '\n')
c6d46f5f
JB
3012 {
3013 *p = 0;
42680d3c 3014 newline = (c == '\n') ? 1 : 0;
c6d46f5f
JB
3015 break;
3016 }
3017 *p++ = c;
3018 }
3019
3020 return p - buffer + newline;
3021}
3022\f
3023char *
3024savestr (cp)
3025 char *cp;
3026{
3027 return savenstr (cp, strlen (cp));
3028}
3029
3030char *
3031savenstr (cp, len)
3032 char *cp;
3033 int len;
3034{
3035 register char *dp;
3036
3037 dp = xnew (len + 1, char);
1a0d8c80 3038 strncpy (dp, cp, len);
c6d46f5f
JB
3039 dp[len] = '\0';
3040 return dp;
3041}
3042
c6d46f5f
JB
3043/*
3044 * Return the ptr in sp at which the character c last
3045 * appears; NULL if not found
3046 *
b02c5fea 3047 * Identical to System V strrchr, included for portability.
c6d46f5f
JB
3048 */
3049
3050char *
b02c5fea 3051etags_strrchr (sp, c)
c6d46f5f
JB
3052 register char *sp, c;
3053{
3054 register char *r;
3055
3056 r = NULL;
3057 do
3058 {
3059 if (*sp == c)
3060 r = sp;
3061 } while (*sp++);
3062 return (r);
3063}
3064
9d7ad1b3 3065
c6d46f5f
JB
3066/*
3067 * Return the ptr in sp at which the character c first
3068 * appears; NULL if not found
3069 *
b02c5fea 3070 * Identical to System V strchr, included for portability.
c6d46f5f
JB
3071 */
3072
3073char *
b02c5fea 3074etags_strchr (sp, c)
c6d46f5f
JB
3075 register char *sp, c;
3076{
3077 do
3078 {
3079 if (*sp == c)
3080 return (sp);
3081 } while (*sp++);
3082 return (NULL);
3083}
3084
c6d46f5f
JB
3085/* Print error message and exit. */
3086
3087/* VARARGS1 */
3088void
3089fatal (s1, s2)
3090 char *s1, *s2;
3091{
3092 error (s1, s2);
1a0d8c80 3093 exit (BAD);
c6d46f5f
JB
3094}
3095
3096/* Print error message. `s1' is printf control string, `s2' is arg for it. */
3097
3098/* VARARGS1 */
3099void
3100error (s1, s2)
3101 char *s1, *s2;
3102{
3103 fprintf (stderr, "%s: ", progname);
3104 fprintf (stderr, s1, s2);
3105 fprintf (stderr, "\n");
3106}
3107
46c145db
FP
3108/* Return a newly-allocated string whose contents
3109 concatenate those of s1, s2, s3. */
c6d46f5f
JB
3110
3111char *
3112concat (s1, s2, s3)
3113 char *s1, *s2, *s3;
3114{
3115 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3116 char *result = xnew (len1 + len2 + len3 + 1, char);
3117
1a0d8c80
FP
3118 strcpy (result, s1);
3119 strcpy (result + len1, s2);
3120 strcpy (result + len1 + len2, s3);
46c145db 3121 result[len1 + len2 + len3] = '\0';
c6d46f5f
JB
3122
3123 return result;
3124}
b02c5fea 3125\f
6dd5561c
FP
3126/* Does the same work as the system V getcwd, but does not need to
3127 guess buffer size in advance. Included mostly for compatibility. */
b02c5fea
FP
3128char *
3129etags_getcwd ()
3130{
3131 FILE *pipe;
3132 char *buf;
1ddff51c 3133 int bufsize = 256;
c6d46f5f 3134
b02c5fea
FP
3135 do
3136 {
3137 buf = xnew (bufsize, char);
3138
3139 pipe = popen ("pwd 2>/dev/null", "r");
3140 if (pipe == NULL)
3141 {
3142 perror ("pwd");
3143 exit (BAD);
3144 }
3145 if (fgets (buf, bufsize, pipe) == NULL)
3146 {
3147 perror ("pwd");
3148 exit (BAD);
3149 }
3150 pclose (pipe);
3151
3152 bufsize *= 2;
3153
3154 } while (buf[strlen (buf) - 1] != '\n');
3155
3156 return buf;
3157}
3158
3159/* Return a newly allocated string containing the filename
3160 of FILE relative to the absolute directory DIR (which
3161 should end with a slash). */
46c145db
FP
3162
3163char *
3164relative_filename (file, dir)
3165 char *file, *dir;
3166{
3167 char *fp, *dp, *res;
3168
3169 /* Find the common root of file and dir. */
3170 fp = absolute_filename (file, cwd);
3171 dp = dir;
3172 while (*fp++ == *dp++)
3173 continue;
3174 do
3175 {
3176 fp--;
3177 dp--;
3178 }
3179 while (*fp != '/');
3180
3181 /* Build a sequence of "../" strings for the resulting relative filename. */
b02c5fea 3182 for (dp = etags_strchr (dp + 1, '/'), res = "";
46c145db 3183 dp != NULL;
b02c5fea 3184 dp = etags_strchr (dp + 1, '/'))
46c145db
FP
3185 {
3186 res = concat (res, "../", "");
3187 }
3188
3189 /* Add the filename relative to the common root of file and dir. */
3190 res = concat (res, fp + 1, "");
3191
3192 return res; /* temporary stub */
3193}
3194
3195/* Return a newly allocated string containing the
b02c5fea
FP
3196 absolute filename of FILE given CWD (which should
3197 end with a slash). */
3198
46c145db
FP
3199char *
3200absolute_filename (file, cwd)
3201 char *file, *cwd;
3202{
3203 char *slashp, *cp, *res;
3204
3205 if (file[0] == '/')
3206 res = concat (file, "", "");
3207 else
3208 res = concat (cwd, file, "");
3209
3210 /* Delete the "/dirname/.." and "/." substrings. */
b02c5fea 3211 slashp = etags_strchr (res, '/');
46c145db
FP
3212 while (slashp != NULL && slashp[0] != '\0')
3213 {
3214 if (slashp[1] == '.')
3215 {
3216 if (slashp[2] == '.'
3217 && (slashp[3] == '/' || slashp[3] == '\0'))
3218 {
3219 cp = slashp;
3220 do
3221 cp--;
3222 while (cp >= res && *cp != '/');
3223 if (*cp == '/')
3224 {
3225 strcpy (cp, slashp + 3);
3226 }
3227 else /* else (cp == res) */
3228 {
1875d994 3229 if (slashp[3] != '\0')
46c145db
FP
3230 strcpy (cp, slashp + 4);
3231 else
3232 return ".";
3233 }
3234 slashp = cp;
3235 }
3236 else if (slashp[2] == '/' || slashp[2] == '\0')
3237 {
3238 strcpy (slashp, slashp + 2);
3239 }
3240 }
3241 else
3242 {
b02c5fea 3243 slashp = etags_strchr (slashp + 1, '/');
46c145db
FP
3244 }
3245 }
3246
3247 return res;
3248}
3249
b02c5fea
FP
3250/* Return a newly allocated string containing the absolute
3251 filename of dir where FILE resides given CWD (which should
3252 end with a slash). */
3253
46c145db
FP
3254char *
3255absolute_dirname (file, cwd)
3256 char *file, *cwd;
3257{
3258 char *slashp, *res;
3259 char save;
3260
b02c5fea 3261 slashp = etags_strrchr (file, '/');
46c145db
FP
3262 if (slashp == NULL)
3263 return cwd;
3264 save = slashp[1];
3265 slashp[1] = '\0';
3266 res = absolute_filename (file, cwd);
3267 slashp[1] = save;
3268
3269 return res;
3270}
3271
c6d46f5f
JB
3272/* Like malloc but get fatal error if memory is exhausted. */
3273
3274char *
3275xmalloc (size)
42680d3c 3276 unsigned int size;
c6d46f5f 3277{
1a0d8c80
FP
3278 char *result = (char *) malloc (size);
3279 if (result == NULL)
c6d46f5f
JB
3280 fatal ("virtual memory exhausted", 0);
3281 return result;
3282}
3283
3284char *
3285xrealloc (ptr, size)
3286 char *ptr;
42680d3c 3287 unsigned int size;
c6d46f5f 3288{
1a0d8c80
FP
3289 char *result = (char *) realloc (ptr, size);
3290 if (result == NULL)
c6d46f5f
JB
3291 fatal ("virtual memory exhausted");
3292 return result;
3293}