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