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