* etags.c (stab_entry, stab_create, stab_find, stab_search,
[bpt/emacs.git] / lib-src / etags.c
1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
3
4 This file is not considered part of GNU Emacs.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
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++.
27 *
28 * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. 10.6
29 */
30
31 #ifdef MSDOS
32 #include <fcntl.h>
33 #endif /* MSDOS */
34
35 #ifdef HAVE_CONFIG_H
36 #include <../src/config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43
44 #if !defined (S_ISREG) && defined (S_IFREG)
45 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
46 #endif
47
48 #include "getopt.h"
49
50 extern char *malloc (), *realloc ();
51 extern char *getenv ();
52 extern char *strcpy (), *strncpy ();
53 extern int strcmp ();
54
55 char *etags_index (), *etags_rindex ();
56 char *savenstr ();
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.
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 */
110
111 #ifndef DEBUG
112 /* real implementation */
113 typedef long FILEPOS;
114 #define GET_CHARNO(pos) ((pos) + 0)
115 #define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))
116 #else
117 /* debugging implementation */
118 typedef struct
119 {
120 long charno;
121 } FILEPOS;
122
123 #define GET_CHARNO(pos) ((pos).charno + 0)
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
129
130 #define streq(s, t) (strcmp (s, t) == 0)
131 #define strneq(s, t, n) (strncmp (s, t, n) == 0)
132 #define logical int
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 */
141
142 #define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
143
144 struct 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 */
149 logical named; /* list name separately */
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
157 long ftell ();
158 typedef struct nd_st NODE;
159
160 logical header_file; /* TRUE if .h file, FALSE o.w. */
161 /* boolean "functions" (see init) */
162 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
163
164
165 char *concat ();
166 char *savenstr ();
167 char *savestr ();
168 char *xmalloc ();
169 char *xrealloc ();
170 int L_isdef (), L_isquote ();
171 int PF_funcs ();
172 int total_size_of_entries ();
173 logical consider_token ();
174 logical tail ();
175 long readline ();
176 void Asm_funcs ();
177 void C_entries ();
178 void L_funcs ();
179 void L_getit ();
180 void PAS_funcs ();
181 void Scheme_funcs ();
182 void TEX_funcs ();
183 void add_node ();
184 void error ();
185 void fatal ();
186 logical find_entries ();
187 void free_tree ();
188 void getit ();
189 void init ();
190 void initbuffer ();
191 void initbuffer ();
192 void pfnote ();
193 void process_file ();
194 void put_entries ();
195 void 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)))
205
206 /*
207 * Symbol table types.
208 */
209 enum sym_type
210 {
211 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
212 };
213 \f
214
215
216 typedef int LINENO;
217
218 typedef struct
219 {
220 char *p;
221 int len;
222 LINENO lineno;
223 logical named;
224 } TOKEN;
225
226 /* C extensions.
227 */
228 #define C_PLPL 0x00001 /* C++ */
229 #define C_STAR 0x00003 /* C* */
230 #define YACC 0x10000 /* yacc file */
231
232 char searchar = '/'; /* use /.../ searches */
233
234 LINENO lineno; /* line number of current line */
235 long charno; /* current character number */
236
237 long linecharno; /* charno of start of line; not used by C, but
238 * by every other language.
239 */
240
241 char *curfile, /* current input file name */
242 *outfile, /* output file */
243 *white = " \f\t\n", /* white chars */
244 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
245 /* token starting chars */
246 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
247 /* valid in-token chars */
248 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
249
250 int append_to_tagfile; /* -a: append to tags */
251 int 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. */
253 int typedefs; /* -t: create tags for typedefs */
254 int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
255 /* 0 struct/enum/union decls, and C++ */
256 /* member functions */
257 int 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. */
261 int update; /* -u: update tags */
262 int vgrind_style; /* -v: create vgrind style index output */
263 int no_warnings; /* -w: suppress warnings */
264 int cxref_style; /* -x: create cxref style output */
265 int cplusplus; /* .[hc] means C++, not C */
266 int noindentypedefs; /* -S: ignore indentation in C */
267
268 /* Name this program was invoked with. */
269 char *progname;
270
271 struct 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
292 FILE *inf, /* ioptr for current input file */
293 *outf; /* ioptr for tags file */
294
295 NODE *head; /* the head of the binary tree of tags */
296
297 int 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
303 struct linebuffer
304 {
305 long size;
306 char *buffer;
307 };
308
309 struct linebuffer lb; /* the current line */
310 struct linebuffer filename_lb; /* used to read in filenames */
311 struct
312 {
313 FILEPOS linepos;
314 struct linebuffer lb; /* used by C_entries instead of lb */
315 } lbs[2];
316 \f
317 void
318 print_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
329 printf ("for Emacs version 19.\n");
330
331 exit (0);
332 }
333
334 void
335 print_help ()
336 {
337 printf ("These are the options accepted by %s. You may use unambiguous\n\
338 abbreviations for the long option names.\n\n", progname);
339
340 puts ("-a, --append\n\
341 Append tag entries to existing tags file.");
342 puts ("-C, --c++\n\
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\
345 extensions are always assumed to be C++ code.");
346 fputs ("-d, --defines\n\
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\
370 definition.");
371 puts ("-t, --typedefs\n\
372 Generate tag entries for typedefs. This is the default\n\
373 behavior.");
374 puts ("-T, --typedefs-and-c++\n\
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\
388 backward-search command.");
389 puts ("-F, --forward-search\n\
390 Write the search commands for the tag entries using '/', the\n\
391 forward-search command.");
392 puts ("-u, --update\n\
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\
398 tag file than to use this.");
399 puts ("-v, --vgrind\n\
400 Generates an index of items intended for human consumption,\n\
401 similar to the output of vgrind. The index is sorted, and\n\
402 gives the page number of each item.");
403 puts ("-x, --cxref\n\
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\
407 which you like.");
408 puts ("-w, --no-warn\n\
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
422 void
423 main (argc, argv)
424 int argc;
425 char *argv[];
426 {
427 char cmd[100];
428 int i;
429 unsigned int nincluded_files = 0;
430 char **included_files = xnew (argc, char *);
431 char *this_file;
432 #ifdef VMS
433 char got_err;
434
435 extern char *gfnames ();
436 extern char *massage_name ();
437 #endif
438
439 #ifdef MSDOS
440 _fmode = O_BINARY; /* all of files are treated as binary files */
441 #endif /* MSDOS */
442
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
458 for (;;)
459 {
460 int opt;
461 opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0);
462
463 if (opt == EOF)
464 break;
465
466 switch (opt)
467 {
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;
486 case 'f':
487 case 'o':
488 if (outfile)
489 {
490 fprintf (stderr,
491 "%s: -%c flag may only be given once\n", progname, opt);
492 goto usage;
493 }
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;
552 }
553 }
554
555 if (optind == argc && nincluded_files == 0)
556 {
557 fprintf (stderr, "%s: No input files specified.\n", progname);
558
559 usage:
560 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
561 progname, progname);
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);
573 initbuffer (&lbs[0].lb);
574 initbuffer (&lbs[1].lb);
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
592 #ifdef VMS
593 argc -= optind;
594 argv += optind;
595 while (gfnames (&argc, &argv, &got_err) != NULL)
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 }
607 } /* solely to balance out the ifdef'd parens above */
608 #endif
609 #else
610 for (; optind < argc; optind++)
611 {
612 this_file = argv[optind];
613 #endif
614 /* Input file named "-" means read file names from stdin and use them. */
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 }
627
628 if (emacs_tags_format)
629 {
630 while (nincluded_files-- > 0)
631 fprintf (outf, "\f\n%s,include\n", *included_files++);
632
633 (void) fclose (outf);
634 exit (0);
635 }
636
637 if (cxref_style)
638 {
639 put_entries (head);
640 exit (GOOD);
641 }
642 if (update)
643 {
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++)
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 */
675 void
676 process_file (file)
677 char *file;
678 {
679 struct stat stat_buf;
680
681 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
682 {
683 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
684 return;
685 }
686 if (streq (file, outfile) && !streq (outfile, "-"))
687 {
688 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
689 return;
690 }
691 if (!find_entries (file))
692 {
693 return;
694 }
695 if (emacs_tags_format)
696 {
697 fprintf (outf, "\f\n%s,%d\n", file, total_size_of_entries (head));
698 put_entries (head);
699 free_tree (head);
700 head = NULL;
701 }
702 }
703
704 /*
705 * This routine sets up the boolean pseudo-functions which work
706 * by setting boolean flags dependent upon the corresponding character
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 */
712 void
713 init ()
714 {
715 register char *sp;
716 register int i;
717
718 for (i = 0; i < 0177; i++)
719 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
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;
728 _wht[0] = _wht['\n'];
729 _etk[0] = _etk['\n'];
730 _btk[0] = _btk['\n'];
731 _itk[0] = _itk['\n'];
732 }
733
734 /*
735 * This routine opens the specified file and calls the function
736 * which finds the function and type definitions.
737 */
738 logical
739 find_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);
749 return FALSE;
750 }
751 curfile = savestr (file);
752 cp = etags_rindex (file, '.');
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);
789 goto close_and_return;
790 }
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")))
796 {
797 Asm_funcs (inf);
798 goto close_and_return;
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 */
811 if (cp && (streq (cp + 1, "cs")
812 || streq (cp + 1, "hs")))
813 {
814 C_entries (C_STAR);
815 goto close_and_return;
816 }
817 /* .y: a yacc file */
818 if (cp && (streq (cp + 1, "y")))
819 {
820 C_entries (YACC);
821 goto close_and_return;
822 }
823 /* .pl implies prolog source code */
824 if (cp && streq (cp + 1, "pl"))
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 }
836 /* If .f or .for, assume it is fortran or nothing. */
837 if (cp && (streq (cp + 1, "f")
838 || streq (cp + 1, "for")))
839 {
840 (void) PF_funcs (inf);
841 goto close_and_return;
842 }
843 /* if not a .c or .h or .y file, try fortran */
844 if (cp && ((cp[1] != 'c'
845 && cp[1] != 'h'
846 && cp[1] != 'y')
847 || (cp[1] != 0 && cp[2] != 0)))
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
855 close_and_return:
856 (void) fclose (inf);
857 return TRUE;
858 }
859
860 /* Nonzero if string STR is composed of digits. */
861
862 int
863 string_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!! */
876 void
877 pfnote (name, is_func, named, linestart, linelen, lno, cno)
878 char *name; /* tag name */
879 logical is_func; /* function or type name? */
880 logical named; /* tag different from text of definition? */
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 {
910 fp = etags_rindex (curfile, '/');
911 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
912 fp = etags_rindex (name, '.');
913 if (fp && fp[1] != '\0' && fp[2] == '\0')
914 *fp = 0;
915 named = TRUE;
916 }
917 np->name = savestr (name);
918 np->file = curfile;
919 np->is_func = is_func;
920 np->named = named;
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 */
948 void
949 free_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 */
972 /* Must avoid static vars within functions since some systems
973 #define static as nothing. */
974 static NODE *last_node = NULL;
975
976 void
977 add_node (node, cur_node_p)
978 NODE *node, **cur_node_p;
979 {
980 register int dif;
981 register NODE *cur_node = *cur_node_p;
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
1042 void
1043 put_entries (node)
1044 register NODE *node;
1045 {
1046 register char *sp;
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 {
1058 if (node->named)
1059 {
1060 fprintf (outf, "%s\177%s\001%d,%d\n",
1061 node->pat, node->name,
1062 node->lno, node->cno);
1063 }
1064 else
1065 {
1066 fprintf (outf, "%s\177%d,%d\n",
1067 node->pat,
1068 node->lno, node->cno);
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
1099 fprintf (stdout, "%-16s %3d %-16s %s\n",
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. */
1107 int
1108 number_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 */
1125 int
1126 total_size_of_entries (node)
1127 register NODE *node;
1128 {
1129 register int total;
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;
1143 if (node->named)
1144 total += 1 + strlen (node->name); /* \001name */
1145 }
1146
1147 return total;
1148 }
1149 \f
1150 /*
1151 * The C symbol tables.
1152 */
1153
1154 /* Feed stuff between (but not including) %[ and %] lines to:
1155 gperf -c -k1,3 -o -p -r -t
1156 %[
1157 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1158 %%
1159 class, C_PLPL, st_C_struct
1160 domain, C_STAR, st_C_struct
1161 union, 0, st_C_struct
1162 struct, 0, st_C_struct
1163 enum, 0, st_C_enum
1164 typedef, 0, st_C_typedef
1165 define, 0, st_C_define
1166 long, 0, st_C_typespec
1167 short, 0, st_C_typespec
1168 int, 0, st_C_typespec
1169 char, 0, st_C_typespec
1170 float, 0, st_C_typespec
1171 double, 0, st_C_typespec
1172 signed, 0, st_C_typespec
1173 unsigned, 0, st_C_typespec
1174 auto, 0, st_C_typespec
1175 void, 0, st_C_typespec
1176 extern, 0, st_C_typespec
1177 static, 0, st_C_typespec
1178 const, 0, st_C_typespec
1179 volatile, 0, st_C_typespec
1180 %]
1181 and 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
1187 struct 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
1193 /*
1194 21 keywords
1195 53 is the maximum key range
1196 */
1197
1198 static int
1199 hash (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 }
1221
1222 struct C_stab_entry *
1223 in_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;
1282 }
1283 /*%>*/
1284
1285 enum sym_type
1286 C_symtype(str, len, c_ext)
1287 char *str;
1288 int len;
1289 int c_ext;
1290 {
1291 register struct C_stab_entry *se = in_word_set(str, len);
1292
1293 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1294 return st_none;
1295 return se->type;
1296 }
1297 \f
1298 /*
1299 * C functions are recognized using a simple finite automaton.
1300 * funcdef is its state variable.
1301 */
1302 typedef enum
1303 {
1304 fnone, /* nothing seen */
1305 ftagseen, /* function-like tag seen */
1306 fstartlist, /* just after open parenthesis */
1307 finlist, /* in parameter list */
1308 flistseen, /* after parameter list */
1309 fignore /* before open brace */
1310 } FUNCST;
1311 FUNCST funcdef;
1312
1313
1314 /* typedefs are recognized using a simple finite automaton.
1315 * typeddef is its state variable.
1316 */
1317 typedef enum
1318 {
1319 tnone, /* nothing seen */
1320 ttypedseen, /* typedef keyword seen */
1321 tinbody, /* inside typedef body */
1322 tend /* just before typedef tag */
1323 } TYPEDST;
1324 TYPEDST 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 */
1333 typedef 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 */
1339 sinbody /* in struct body: recognize member func defs*/
1340 } STRUCTST;
1341 STRUCTST structdef;
1342 /*
1343 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1344 * struct tag, and structtype is the type of the preceding struct-like
1345 * keyword.
1346 */
1347 char structtag[BUFSIZ];
1348 enum sym_type structtype;
1349
1350 /*
1351 * Yet another little state machine to deal with preprocessor lines.
1352 */
1353 typedef enum
1354 {
1355 dnone, /* nothing seen */
1356 dsharpseen, /* '#' seen as first char on line */
1357 ddefineseen, /* '#' and 'define' seen */
1358 dignorerest /* ignore rest of line */
1359 } DEFINEST;
1360 DEFINEST 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 */
1366 logical next_token_is_func;
1367
1368 /*
1369 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1370 */
1371 logical yacc_rules;
1372
1373 /*
1374 * C_entries ()
1375 * This routine finds functions, typedefs, #define's and
1376 * struct/union/enum definitions in C syntax and adds them
1377 * to the list.
1378 */
1379
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
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
1396 #define CNL_SAVE_DEFINEDEF \
1397 do { \
1398 SET_FILEPOS (curlinepos, inf, charno); \
1399 lineno++; \
1400 charno += readline (&curlb, inf); \
1401 lp = curlb.buffer; \
1402 quotednl = FALSE; \
1403 newndx = curndx; \
1404 } while (FALSE)
1405
1406 #define CNL \
1407 do { \
1408 CNL_SAVE_DEFINEDEF; \
1409 if (TOKEN_SAVED_P) \
1410 RESTORE_TOKEN; \
1411 definedef = dnone; \
1412 } while (FALSE)
1413
1414 #define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
1415 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
1416 #define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
1417 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
1418
1419 void
1420 C_entries (c_ext)
1421 int c_ext; /* extension of C? */
1422 {
1423 register char c; /* latest char read; '\0' for end of line */
1424 register char *lp; /* pointer one beyond the character `c' */
1425 int curndx, newndx; /* indices for current and new lb */
1426 TOKEN tok; /* latest token read for funcdef & structdef */
1427 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
1428 register int tokoff; /* offset in line of start of latest token */
1429 register int toklen; /* length of latest token */
1430 int cblev; /* current curly brace level */
1431 int parlev; /* current parenthesis level */
1432 logical incomm, inquote, inchar, quotednl, midtoken;
1433 logical cplpl;
1434 TOKEN savetok; /* saved token during preprocessor handling */
1435 char savenameb[BUFSIZ]; /* ouch! */
1436
1437 savetok.lineno = 0;
1438 curndx = newndx = 0;
1439 lineno = 0;
1440 charno = 0;
1441 lp = curlb.buffer;
1442 *lp = 0;
1443
1444 definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
1445 next_token_is_func = yacc_rules = FALSE;
1446 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1447 cblev = 0;
1448 parlev = 0;
1449 cplpl = c_ext & C_PLPL;
1450
1451 while (!feof (inf))
1452 {
1453 c = *lp++;
1454 if (c == '\\')
1455 {
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. */
1459 if (*lp == '\0')
1460 {
1461 quotednl = TRUE;
1462 continue;
1463 }
1464 lp++;
1465 c = ' ';
1466 }
1467 else if (incomm)
1468 {
1469 switch (c)
1470 {
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;
1483 }
1484 continue;
1485 }
1486 else if (inquote)
1487 {
1488 switch (c)
1489 {
1490 case '"':
1491 inquote = FALSE;
1492 break;
1493 case '\0':
1494 /* Newlines inside strings do not end macro definitions
1495 in traditional cpp, even though compilers don't
1496 usually accept them. */
1497 CNL_SAVE_DEFINEDEF;
1498 break;
1499 }
1500 continue;
1501 }
1502 else if (inchar)
1503 {
1504 switch (c)
1505 {
1506 case '\0':
1507 /* Hmmm, something went wrong. */
1508 CNL;
1509 /* FALLTHRU */
1510 case '\'':
1511 inchar = FALSE;
1512 break;
1513 }
1514 continue;
1515 }
1516 else
1517 switch (c)
1518 {
1519 case '"':
1520 inquote = TRUE;
1521 if (funcdef != finlist && funcdef != fignore)
1522 funcdef = fnone;
1523 continue;
1524 case '\'':
1525 inchar = TRUE;
1526 if (funcdef != finlist && funcdef != fignore)
1527 funcdef = fnone;
1528 continue;
1529 case '/':
1530 if (*lp == '*')
1531 {
1532 lp++;
1533 incomm = TRUE;
1534 continue;
1535 }
1536 else if (cplpl && *lp == '/')
1537 {
1538 c = 0;
1539 break;
1540 }
1541 else
1542 break;
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;
1552 cblev = 0;
1553 yacc_rules = !yacc_rules;
1554 continue;
1555 }
1556 else
1557 break;
1558 case '#':
1559 if (lp == newlb.buffer + 1 && definedef == dnone)
1560 definedef = dsharpseen;
1561 continue;
1562 } /* switch (c) */
1563
1564
1565 /* Consider token only if some complicated conditions are satisfied. */
1566 if (((cblev == 0 && structdef != scolonseen)
1567 || (cblev == 1 && cplpl && structdef == sinbody))
1568 && definedef != dignorerest
1569 && (funcdef != finlist
1570 || (definedef != dnone && definedef != dignorerest)))
1571 {
1572 if (midtoken)
1573 {
1574 if (endtoken (c))
1575 {
1576 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
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 {
1587 logical is_func = FALSE;
1588
1589 tok.lineno = lineno;
1590 tok.p = newlb.buffer + tokoff;
1591 tok.len = toklen;
1592 tok.named = FALSE;
1593 if (yacc_rules
1594 || consider_token (c, &tok, c_ext, cblev, &is_func))
1595 {
1596 if (structdef == sinbody
1597 && definedef == dnone
1598 && is_func)
1599 /* function defined in C++ class body */
1600 {
1601 tok.named = TRUE;
1602 sprintf (nameb, "%s::%.*s",
1603 ((structtag[0] == '\0')
1604 ? "_anonymous_" : structtag),
1605 tok.len, tok.p);
1606 }
1607 else
1608 {
1609 sprintf (nameb, "%.*s", tok.len, tok.p);
1610 }
1611
1612 if (structdef == stagseen
1613 || typdef == tend)
1614 tok.named = TRUE;
1615
1616 if (definedef == dnone
1617 && (funcdef == ftagseen
1618 || structdef == stagseen
1619 || typdef == tend))
1620 {
1621 if (newndx == curndx)
1622 curndx = 1 - curndx; /* switch line buffers */
1623 }
1624 else
1625 MAKE_TAG_FROM_NEW_LB (is_func);
1626 }
1627 midtoken = FALSE;
1628 }
1629 } /* if (endtoken (c)) */
1630 else if (intoken (c))
1631 {
1632 toklen++;
1633 continue;
1634 }
1635 } /* if (midtoken) */
1636 else if (begtoken (c))
1637 {
1638 switch (definedef)
1639 {
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;
1656 break;
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;
1671 }
1672 if (!yacc_rules || lp == newlb.buffer + 1)
1673 {
1674 tokoff = lp - 1 - newlb.buffer;
1675 toklen = 1;
1676 midtoken = TRUE;
1677 }
1678 continue;
1679 }
1680 } /* if must look at token */
1681
1682
1683 /* Detect end of line, colon, comma, semicolon and various braces
1684 after having handled a token.*/
1685 switch (c)
1686 {
1687 case ':':
1688 if (definedef != dnone)
1689 break;
1690 if (structdef == stagseen)
1691 structdef = scolonseen;
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 }
1706 break;
1707 case ';':
1708 if (definedef != dnone)
1709 break;
1710 if (cblev == 0 && typdef == tend)
1711 {
1712 typdef = tnone;
1713 MAKE_TAG_FROM_OTH_LB (FALSE);
1714 }
1715 if (funcdef != fignore)
1716 funcdef = fnone;
1717 /* FALLTHRU */
1718 case ',':
1719 /* FALLTHRU */
1720 case '[':
1721 if (definedef != dnone)
1722 break;
1723 if (funcdef != finlist && funcdef != fignore)
1724 funcdef = fnone;
1725 if (structdef == stagseen)
1726 structdef = snone;
1727 break;
1728 case '(':
1729 if (definedef != dnone)
1730 break;
1731 switch (funcdef)
1732 {
1733 case ftagseen:
1734 funcdef = fstartlist;
1735 break;
1736 case flistseen:
1737 funcdef = finlist;
1738 break;
1739 }
1740 parlev++;
1741 break;
1742 case ')':
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;
1757 break;
1758 case '{':
1759 if (definedef != dnone)
1760 break;
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 }
1775 switch (funcdef)
1776 {
1777 case flistseen:
1778 MAKE_TAG_FROM_OTH_LB (TRUE);
1779 /* FALLTHRU */
1780 case fignore:
1781 funcdef = fnone;
1782 }
1783 cblev++;
1784 break;
1785 case '*':
1786 if (definedef != dnone)
1787 break;
1788 if (funcdef == fstartlist)
1789 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
1790 break;
1791 case '}':
1792 if (definedef != dnone)
1793 break;
1794 if (!noindentypedefs && lp == newlb.buffer + 1)
1795 {
1796 cblev = 0; /* reset curly brace level if first column */
1797 parlev = 0; /* also reset paren level, just in case... */
1798 }
1799 else if (cblev > 0)
1800 cblev--;
1801 if (cblev == 0)
1802 {
1803 if (typdef == tinbody)
1804 typdef = tend;
1805 structdef = snone;
1806 (void) strcpy (structtag, "<error 2>");
1807 }
1808 break;
1809 case '=':
1810 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
1811 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
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;
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 */
1828 }
1829
1830 /*
1831 * consider_token ()
1832 * checks to see if the current token is at the start of a
1833 * function, or corresponds to a typedef, or is a struct/union/enum
1834 * tag.
1835 *
1836 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
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
1845 * funcdef IN OUT
1846 * structdef IN OUT
1847 * definedef IN OUT
1848 * typdef IN OUT
1849 * next_token_is_func IN OUT
1850 */
1851
1852 logical
1853 consider_token (c, tokp, c_ext, cblev, is_func)
1854 register char c; /* IN: first char after the token */
1855 register TOKEN *tokp; /* IN: token pointer */
1856 int c_ext; /* IN: C extensions mask */
1857 int cblev; /* IN: curly brace level */
1858 logical *is_func; /* OUT */
1859 {
1860 enum sym_type toktype = C_symtype(tokp->p, tokp->len, c_ext);
1861
1862 /*
1863 * Advance the definedef state machine.
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;
1874 }
1875 else
1876 {
1877 definedef = dignorerest;
1878 }
1879 return (FALSE);
1880 case ddefineseen:
1881 /*
1882 * Make a tag for any macro.
1883 */
1884 definedef = dignorerest;
1885 *is_func = (c == '(');
1886 if (!*is_func && !constantypedefs)
1887 return (FALSE);
1888 else
1889 return (TRUE);
1890 case dignorerest:
1891 return (FALSE);
1892 default:
1893 error ("internal error: definedef value");
1894 }
1895
1896 /*
1897 * Now typedefs
1898 */
1899 switch (typdef)
1900 {
1901 case tnone:
1902 if (toktype == st_C_typedef)
1903 {
1904 if (typedefs)
1905 typdef = ttypedseen;
1906 return (FALSE);
1907 }
1908 break;
1909 case ttypedseen:
1910 switch (toktype)
1911 {
1912 case st_none:
1913 case st_C_typespec:
1914 typdef = tend;
1915 break;
1916 case st_C_struct:
1917 case st_C_enum:
1918 break;
1919 }
1920 /* Do not return here, so the structdef stuff has a chance. */
1921 break;
1922 case tend:
1923 switch (toktype)
1924 {
1925 case st_C_typespec:
1926 case st_C_struct:
1927 case st_C_enum:
1928 return (FALSE);
1929 }
1930 return (TRUE);
1931 }
1932
1933 /*
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.
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 *
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.
1947 */
1948 switch (toktype)
1949 {
1950 case st_C_struct:
1951 case st_C_enum:
1952 if (typdef == ttypedseen
1953 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1954 {
1955 structdef = skeyseen;
1956 structtype = toktype;
1957 }
1958 return (FALSE);
1959 }
1960 if (structdef == skeyseen)
1961 {
1962 if (structtype == st_C_struct)
1963 {
1964 (void) strncpy (structtag, tokp->p, tokp->len);
1965 structtag[tokp->len] = '\0'; /* for struct/union/class */
1966 }
1967 else
1968 {
1969 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
1970 }
1971 structdef = stagseen;
1972 return (TRUE);
1973 }
1974
1975 /* Avoid entering funcdef stuff if typdef is going on. */
1976 if (typdef != tnone)
1977 {
1978 definedef = dnone;
1979 return (FALSE);
1980 }
1981
1982 /* Detect GNUmacs's function-defining macros. */
1983 if (definedef == dnone)
1984 {
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))
1989 {
1990 next_token_is_func = TRUE;
1991 return (FALSE);
1992 }
1993 if (strneq (tokp->p, "EXFUN", 5))
1994 {
1995 next_token_is_func = FALSE;
1996 return (FALSE);
1997 }
1998 }
1999 if (next_token_is_func)
2000 {
2001 next_token_is_func = FALSE;
2002 funcdef = fnone;
2003 *is_func = TRUE; /* to force search string in ctags */
2004 return (TRUE);
2005 }
2006
2007 /* A function? */
2008 switch (toktype)
2009 {
2010 case st_C_typespec:
2011 funcdef = fnone; /* should be useless */
2012 return (FALSE);
2013 default:
2014 if (funcdef == fnone)
2015 {
2016 funcdef = ftagseen;
2017 *is_func = TRUE;
2018 return (TRUE);
2019 }
2020 }
2021
2022 return (FALSE);
2023 }
2024 \f
2025 /* Fortran parsing */
2026
2027 char *dbp;
2028 int pfcnt;
2029
2030 int
2031 PF_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"))
2089 getit (fi);
2090 continue;
2091 case 's':
2092 if (tail ("subroutine"))
2093 getit (fi);
2094 continue;
2095 case 'e':
2096 if (tail ("entry"))
2097 getit (fi);
2098 continue;
2099 case 'p':
2100 if (tail ("program"))
2101 {
2102 getit (fi);
2103 continue;
2104 }
2105 if (tail ("procedure"))
2106 getit (fi);
2107 continue;
2108 }
2109 }
2110 return (pfcnt);
2111 }
2112
2113 logical
2114 tail (cp)
2115 char *cp;
2116 {
2117 register int len = 0;
2118
2119 while (*cp && (*cp | ' ') == (dbp[len] | ' '))
2120 cp++, len++;
2121 if (*cp == 0)
2122 {
2123 dbp += len;
2124 return (TRUE);
2125 }
2126 return (FALSE);
2127 }
2128
2129 void
2130 takeprec ()
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
2149 void
2150 getit (fi)
2151 FILE *fi;
2152 {
2153 register char *cp;
2154 char c;
2155 char nambuf[BUFSIZ];
2156
2157 while (isspace (*dbp))
2158 dbp++;
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)
2172 && *dbp != '_'
2173 && *dbp != '$')
2174 return;
2175 for (cp = dbp + 1;
2176 (*cp
2177 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2178 cp++)
2179 continue;
2180 c = *cp;
2181 *cp = '\0';
2182 (void) strcpy (nambuf, dbp);
2183 *cp = c;
2184 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2185 cp - lb.buffer + 1, lineno, linecharno);
2186 pfcnt++;
2187 }
2188
2189 /* Handle a file of assembler code. */
2190
2191 void
2192 Asm_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 == ':'))
2213 getit (fi);
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
2234 void
2235 PAS_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
2419 void
2420 L_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 ... */
2446 do
2447 dbp++;
2448 while (*dbp && !isspace (*dbp)
2449 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2450 if (*dbp == ':')
2451 {
2452 do
2453 dbp++;
2454 while (*dbp == ':');
2455
2456 if (L_isdef (dbp - 1))
2457 {
2458 while (!isspace (*dbp))
2459 dbp++;
2460 while (isspace (*dbp))
2461 dbp++;
2462 L_getit ();
2463 }
2464 }
2465 }
2466 }
2467 }
2468 }
2469
2470 int
2471 L_isdef (dbp)
2472 register char *dbp;
2473 {
2474 return ((dbp[1] == 'd' || dbp[1] == 'D')
2475 && (dbp[2] == 'e' || dbp[2] == 'E')
2476 && (dbp[3] == 'f' || dbp[3] == 'F'));
2477 }
2478
2479 int
2480 L_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)));
2489 }
2490
2491 void
2492 L_getit ()
2493 {
2494 register char *cp;
2495 char c;
2496 char nambuf[BUFSIZ];
2497
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++)
2507 continue;
2508 if (cp == dbp)
2509 return;
2510
2511 c = cp[0];
2512 cp[0] = 0;
2513 (void) strcpy (nambuf, dbp);
2514 cp[0] = c;
2515 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2516 cp - lb.buffer + 1, lineno, linecharno);
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
2528 static void get_scheme ();
2529
2530 void
2531 Scheme_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
2573 static void
2574 get_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
2603 struct TEX_tabent
2604 {
2605 char *name;
2606 int len;
2607 };
2608
2609 struct 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
2614 static char *TEX_defenv =
2615 ":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2616
2617 void TEX_mode ();
2618 struct TEX_tabent *TEX_decode_env ();
2619 void TEX_getit ();
2620 int TEX_Token ();
2621
2622 static char TEX_esc = '\\';
2623 static char TEX_opgrp = '{';
2624 static char TEX_clgrp = '}';
2625
2626 /*
2627 * TeX/LaTeX scanning loop.
2628 */
2629
2630 void
2631 TEX_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))
2648 { /* Scan each line in file */
2649 lineno++;
2650 linecharno = charno;
2651 charno += readline (&lb, fi);
2652 dbp = lb.buffer;
2653 lasthit = dbp;
2654 while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
2655 {
2656 register int i;
2657
2658 if (!*(++dbp))
2659 break;
2660 linecharno += dbp - lasthit;
2661 lasthit = dbp;
2662 i = TEX_Token (lasthit);
2663 if (0 <= i)
2664 {
2665 TEX_getit (lasthit, TEX_toktab[i].len);
2666 break; /* We only save a line once */
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
2679 void
2680 TEX_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
2713 struct TEX_tabent *
2714 TEX_decode_env (evarname, defenv)
2715 char *evarname;
2716 char *defenv;
2717 {
2718 register char *env, *p;
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;)
2732 if ((p = etags_index (p, ':')) && *(++p))
2733 size++;
2734 /* Add 1 to leave room for null terminator. */
2735 tab = xnew (size + 1, struct TEX_tabent);
2736
2737 /* Unpack environment string into token table. Be careful about */
2738 /* zero-length strings (leading ':', "::" and trailing ':') */
2739 for (i = 0; *env;)
2740 {
2741 p = etags_index (env, ':');
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
2766 void
2767 TEX_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,
2788 return the etags_index of that command in TEX_toktab.
2789 Otherwise return -1. */
2790
2791 /* Keep the capital `T' in `Token' for dumb truncating compilers
2792 (this distinguishes it from `TEX_toktab' */
2793 int
2794 TEX_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
2810 void
2811 prolog_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;
2861 pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
2862 }
2863
2864 /* It is assumed that prolog predicate starts from column 0. */
2865
2866 void
2867 prolog_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
2890 void
2891 skip_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
2906 int
2907 substr (sub, s)
2908 char *sub;
2909 char *s;
2910 {
2911 while (*s && (s = etags_index (s, *sub)))
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
2921 int
2922 prestr (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
2936 void
2937 initbuffer (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 */
2949 long
2950 readline (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
2959 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
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 }
2972 if (c == EOF || c == '\n')
2973 {
2974 *p = 0;
2975 newline = (c == '\n') ? 1 : 0;
2976 break;
2977 }
2978 *p++ = c;
2979 }
2980
2981 return p - buffer + newline;
2982 }
2983 \f
2984 char *
2985 savestr (cp)
2986 char *cp;
2987 {
2988 return savenstr (cp, strlen (cp));
2989 }
2990
2991 char *
2992 savenstr (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
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
3011 char *
3012 etags_rindex (sp, c)
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
3026
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
3034 char *
3035 etags_index (sp, c)
3036 register char *sp, c;
3037 {
3038 do
3039 {
3040 if (*sp == c)
3041 return (sp);
3042 } while (*sp++);
3043 return (NULL);
3044 }
3045
3046 /* Print error message and exit. */
3047
3048 /* VARARGS1 */
3049 void
3050 fatal (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 */
3060 void
3061 error (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
3071 char *
3072 concat (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
3088 char *
3089 xmalloc (size)
3090 unsigned int size;
3091 {
3092 char *result = malloc (size);
3093 if (!result)
3094 fatal ("virtual memory exhausted", 0);
3095 return result;
3096 }
3097
3098 char *
3099 xrealloc (ptr, size)
3100 char *ptr;
3101 unsigned int size;
3102 {
3103 char *result = realloc (ptr, size);
3104 if (!result)
3105 fatal ("virtual memory exhausted");
3106 return result;
3107 }