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