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