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