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