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