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