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