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