Added ${lispsource}ediff-hook.elc after vc-hooks.
[emacs.git] / lib-src / etags.c
blob1e4875305a73e6fd2671bcfa1eeab3ae8472d11f
1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984, 87, 88, 89, 93, 94, 95
3 Free Software Foundation, Inc. and Ken Arnold
4 This file is not considered part of GNU Emacs.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21 * Authors:
22 * Ctags originally by Ken Arnold.
23 * Fortran added by Jim Kleckner.
24 * Ed Pelegri-Llopart added C typedefs.
25 * Gnu Emacs TAGS format and modifications by RMS?
26 * Sam Kendall added C++.
27 * Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
28 #ifdef ETAGS_REGEXPS
29 * Regexp tags by Tom Tromey.
30 #endif
32 * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
35 char pot_etags_version[] = "@(#) pot revision number is 11.30";
37 #define TRUE 1
38 #define FALSE 0
39 #ifndef DEBUG
40 # define DEBUG FALSE
41 #endif
43 #ifdef MSDOS
44 #include <fcntl.h>
45 #include <sys/param.h>
46 #endif /* MSDOS */
48 #ifdef WINDOWSNT
49 #include <stdlib.h>
50 #include <fcntl.h>
51 #include <string.h>
52 #define MAXPATHLEN _MAX_PATH
53 #endif
55 #ifdef HAVE_CONFIG_H
56 #include <config.h>
57 /* On some systems, Emacs defines static as nothing for the sake
58 of unexec. We don't want that here since we don't use unexec. */
59 #undef static
60 #endif
62 #include <stdio.h>
63 #include <ctype.h>
64 #include <errno.h>
65 #ifndef errno
66 extern int errno;
67 #endif
68 #include <sys/types.h>
69 #include <sys/stat.h>
71 #if !defined (S_ISREG) && defined (S_IFREG)
72 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
73 #endif
75 #include <getopt.h>
77 #ifdef ETAGS_REGEXPS
78 #include <regex.h>
79 #endif /* ETAGS_REGEXPS */
81 /* Define CTAGS to make the program "ctags" compatible with the usual one.
82 Let it undefined to make the program "etags", which makes emacs-style
83 tag tables and tags typedefs, #defines and struct/union/enum by default. */
84 #ifdef CTAGS
85 # undef CTAGS
86 # define CTAGS TRUE
87 #else
88 # define CTAGS FALSE
89 #endif
91 /* Exit codes for success and failure. */
92 #ifdef VMS
93 #define GOOD 1
94 #define BAD 0
95 #else
96 #define GOOD 0
97 #define BAD 1
98 #endif
100 /* C extensions. */
101 #define C_PLPL 0x00001 /* C++ */
102 #define C_STAR 0x00003 /* C* */
103 #define YACC 0x10000 /* yacc file */
105 #define streq(s,t) (strcmp (s, t) == 0)
106 #define strneq(s,t,n) (strncmp (s, t, n) == 0)
108 #define lowcase(c) ((c) | ' ')
110 #define iswhite(arg) (_wht[arg]) /* T if char is white */
111 #define begtoken(arg) (_btk[arg]) /* T if char can start token */
112 #define intoken(arg) (_itk[arg]) /* T if char can be in token */
113 #define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
115 #ifdef DOS_NT
116 # define absolutefn(fn) (fn[0] == '/' || (isalpha (fn[0]) && fn[1] == ':'))
117 #else
118 # define absolutefn(fn) (fn[0] == '/')
119 #endif
123 * xnew -- allocate storage
125 * SYNOPSIS: Type *xnew (int n, Type);
127 #define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
129 typedef int logical;
131 typedef struct nd_st
132 { /* sorting structure */
133 char *name; /* function or type name */
134 char *file; /* file name */
135 logical is_func; /* use pattern or line no */
136 logical been_warned; /* set if noticed dup */
137 int lno; /* line number tag is on */
138 long cno; /* character number line starts on */
139 char *pat; /* search pattern */
140 struct nd_st *left, *right; /* left and right sons */
141 } NODE;
143 extern char *getenv ();
145 char *concat ();
146 char *savenstr (), *savestr ();
147 char *etags_strchr (), *etags_strrchr ();
148 char *etags_getcwd ();
149 char *relative_filename (), *absolute_filename (), *absolute_dirname ();
150 long *xmalloc (), *xrealloc ();
152 typedef void Lang_function ();
153 #if FALSE /* many compilers barf on this */
154 Lang_function Asm_labels;
155 Lang_function default_C_entries;
156 Lang_function C_entries;
157 Lang_function Cplusplus_entries;
158 Lang_function Cstar_entries;
159 Lang_function Fortran_functions;
160 Lang_function Yacc_entries;
161 Lang_function Lisp_functions;
162 Lang_function Pascal_functions;
163 Lang_function Prolog_functions;
164 Lang_function Scheme_functions;
165 Lang_function TeX_functions;
166 Lang_function just_read_file;
167 #else /* so let's write it this way */
168 void Asm_labels ();
169 void C_entries ();
170 void default_C_entries ();
171 void plain_C_entries ();
172 void Cplusplus_entries ();
173 void Cstar_entries ();
174 void Fortran_functions ();
175 void Yacc_entries ();
176 void Lisp_functions ();
177 void Pascal_functions ();
178 void Prolog_functions ();
179 void Scheme_functions ();
180 void TeX_functions ();
181 void just_read_file ();
182 #endif
184 logical get_language ();
185 int total_size_of_entries ();
186 long readline ();
187 long readline_internal ();
188 #ifdef ETAGS_REGEXPS
189 void add_regex ();
190 #endif
191 void add_node ();
192 void error ();
193 void fatal (), pfatal ();
194 void find_entries ();
195 void free_tree ();
196 void getit ();
197 void init ();
198 void initbuffer ();
199 void pfnote ();
200 void process_file ();
201 void put_entries ();
202 void takeprec ();
205 char searchar = '/'; /* use /.../ searches */
207 int lineno; /* line number of current line */
208 long charno; /* current character number */
210 long linecharno; /* charno of start of line; not used by C,
211 but by every other language. */
213 char *curfile; /* current input file name */
214 char *tagfile; /* output file */
215 char *progname; /* name this program was invoked with */
216 char *cwd; /* current working directory */
217 char *tagfiledir; /* directory of tagfile */
219 FILE *tagf; /* ioptr for tags file */
220 NODE *head; /* the head of the binary tree of tags */
223 * A `struct linebuffer' is a structure which holds a line of text.
224 * `readline' reads a line from a stream into a linebuffer and works
225 * regardless of the length of the line.
227 struct linebuffer
229 long size;
230 char *buffer;
233 struct linebuffer lb; /* the current line */
234 struct linebuffer token_name; /* used by C_entries as temporary area */
235 struct
237 long linepos;
238 struct linebuffer lb; /* used by C_entries instead of lb */
239 } lbs[2];
241 /* boolean "functions" (see init) */
242 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
243 char
244 *white = " \f\t\n\013", /* white chars */
245 *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
246 /* token starting chars */
247 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
248 /* valid in-token chars */
249 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
251 logical append_to_tagfile; /* -a: append to tags */
252 /* The following three default to TRUE for etags, but to FALSE for ctags. */
253 logical typedefs; /* -t: create tags for typedefs */
254 logical typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
255 /* 0 struct/enum/union decls, and C++ */
256 /* member functions. */
257 logical constantypedefs; /* -d: create tags for C #define and enum */
258 /* constants. Enum consts not implemented. */
259 /* -D: opposite of -d. Default under ctags. */
260 logical update; /* -u: update tags */
261 logical vgrind_style; /* -v: create vgrind style index output */
262 logical no_warnings; /* -w: suppress warnings */
263 logical cxref_style; /* -x: create cxref style output */
264 logical cplusplus; /* .[hc] means C++, not C */
265 logical noindentypedefs; /* -I: ignore indentation in C */
266 #define permit_duplicates TRUE /* allow duplicate tags */
268 struct option longopts[] =
270 { "append", no_argument, NULL, 'a' },
271 { "backward-search", no_argument, NULL, 'B' },
272 { "c++", no_argument, NULL, 'C' },
273 { "cxref", no_argument, NULL, 'x' },
274 { "defines", no_argument, NULL, 'd' },
275 { "help", no_argument, NULL, 'h' },
276 { "help", no_argument, NULL, 'H' },
277 { "ignore-indentation", no_argument, NULL, 'I' },
278 { "include", required_argument, NULL, 'i' },
279 { "language", required_argument, NULL, 'l' },
280 { "no-defines", no_argument, NULL, 'D' },
281 { "no-regex", no_argument, NULL, 'R' },
282 { "no-warn", no_argument, NULL, 'w' },
283 { "output", required_argument, NULL, 'o' },
284 { "regex", required_argument, NULL, 'r' },
285 { "typedefs", no_argument, NULL, 't' },
286 { "typedefs-and-c++", no_argument, NULL, 'T' },
287 { "update", no_argument, NULL, 'u' },
288 { "version", no_argument, NULL, 'V' },
289 { "vgrind", no_argument, NULL, 'v' },
290 { 0 }
293 #ifdef ETAGS_REGEXPS
294 /* Structure defining a regular expression. Elements are
295 the compiled pattern, and the name string. */
296 struct pattern
298 struct re_pattern_buffer *pattern;
299 struct re_registers regs;
300 char *name_pattern;
301 logical error_signaled;
304 /* Number of regexps found. */
305 int num_patterns = 0;
307 /* Array of all regexps. */
308 struct pattern *patterns = NULL;
309 #endif /* ETAGS_REGEXPS */
311 /* Language stuff. */
312 struct lang_entry
314 char *suffix;
315 Lang_function *function;
318 /* Table of language names and corresponding functions. */
319 /* It is ok for a given function to be listed under more than one
320 name. I just didn't. */
321 /* "auto" language reverts to default behavior. */
322 struct lang_entry lang_names[] =
324 { "asm", Asm_labels },
325 { "c", default_C_entries },
326 { "c++", Cplusplus_entries },
327 { "c*", Cstar_entries },
328 { "fortran", Fortran_functions },
329 { "lisp", Lisp_functions },
330 { "none", just_read_file },
331 { "pascal", Pascal_functions },
332 { "scheme" , Scheme_functions },
333 { "tex", TeX_functions },
334 { "auto", NULL },
335 { NULL, NULL }
338 /* Table of file name suffixes and corresponding language functions. */
339 struct lang_entry lang_suffixes[] =
341 /* Assume that ".s" or ".a" is assembly code. -wolfgang.
342 Or even ".sa". */
343 { "a", Asm_labels }, /* Unix assembler */
344 { "asm", Asm_labels }, /* Microcontroller assembly */
345 { "def", Asm_labels }, /* BSO/Tasking definition includes */
346 { "inc", Asm_labels }, /* Microcontroller include files */
347 { "ins", Asm_labels }, /* Microcontroller include files */
348 { "s", Asm_labels },
349 { "sa", Asm_labels }, /* Unix assembler */
350 { "src", Asm_labels }, /* BSO/Tasking C compiler output */
352 /* .aux, .bbl, .clo, .cls, .dtx or .tex implies LaTeX source code. */
353 { "aux", TeX_functions },
354 { "bbl", TeX_functions },
355 { "clo", TeX_functions },
356 { "cls", TeX_functions },
357 { "dtx", TeX_functions },
358 { "sty", TeX_functions },
359 { "tex", TeX_functions },
361 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
362 { "cl", Lisp_functions },
363 { "clisp", Lisp_functions },
364 { "el", Lisp_functions },
365 { "l", Lisp_functions },
366 { "lisp", Lisp_functions },
367 { "lsp", Lisp_functions },
369 /* .scm or .sm or .scheme implies scheme source code */
370 { "SCM", Scheme_functions },
371 { "SM", Scheme_functions },
372 { "oak", Scheme_functions },
373 { "sch", Scheme_functions },
374 { "scheme", Scheme_functions },
375 { "scm", Scheme_functions },
376 { "sm", Scheme_functions },
377 { "t", Scheme_functions },
378 /* FIXME Can't do the `SCM' or `scm' prefix with a version number */
380 /* Note that .c and .h can be considered C++, if the --c++ flag was
381 given. That is why default_C_entries is called here. */
382 { "c", default_C_entries },
383 { "h", default_C_entries },
385 /* .pc is a Pro*C file. */
386 { "pc", plain_C_entries },
388 /* .C or .H or .c++ or .cc or .cpp or .cxx or .h++ or .hh or .hxx:
389 a C++ file */
390 { "C", Cplusplus_entries },
391 { "H", Cplusplus_entries },
392 { "c++", Cplusplus_entries },
393 { "cc", Cplusplus_entries },
394 { "cpp", Cplusplus_entries },
395 { "cxx", Cplusplus_entries },
396 { "h++", Cplusplus_entries },
397 { "hh", Cplusplus_entries },
398 { "hxx", Cplusplus_entries },
400 /* .y: a yacc file */
401 { "y", Yacc_entries },
403 /* .cs or .hs: a C* file */
404 { "cs", Cstar_entries },
405 { "hs", Cstar_entries },
407 /* .F, .f and .for are FORTRAN. */
408 { "F", Fortran_functions },
409 { "f", Fortran_functions },
410 { "for", Fortran_functions },
412 /* .pl implies prolog source code */
413 { "pl", Prolog_functions },
415 /* .p or .pas: a Pascal file */
416 { "p", Pascal_functions },
417 { "pas", Pascal_functions },
419 { NULL, NULL }
422 /* Non-NULL if language fixed. */
423 Lang_function *lang_func = NULL;
426 void
427 print_language_names ()
429 struct lang_entry *name, *ext;
431 puts ("\nThese are the currently supported languages, along with the\n\
432 default file name suffixes:");
433 for (name = lang_names; name->suffix; ++name)
435 printf ("\t%s\t", name->suffix);
436 for (ext = lang_suffixes; ext->suffix; ++ext)
437 if (name->function == ext->function)
438 printf (" .%s", ext->suffix);
439 puts ("");
441 puts ("Where `auto' means use default language for files based on file\n\
442 name suffix, and `none' means only do regexp processing on files.\n\
443 If no language is specified and no matching suffix is found,\n\
444 Fortran is tried first; if no tags are found, C is tried next.");
447 void
448 print_version ()
450 #ifdef VERSION
451 printf ("%s for Emacs version %s.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
452 #else
453 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
454 #endif
456 exit (GOOD);
459 void
460 print_help ()
462 printf ("These are the options accepted by %s. You may use unambiguous\n\
463 abbreviations for the long option names. A - as file name means read\n\
464 names from stdin.\n\n", progname);
466 puts ("-a, --append\n\
467 Append tag entries to existing tags file.");
469 if (CTAGS)
470 puts ("-B, --backward-search\n\
471 Write the search commands for the tag entries using '?', the\n\
472 backward-search command instead of '/', the forward-search command.");
474 puts ("-C, --c++\n\
475 Treat files whose name suffix defaults to C language as C++ files.");
477 if (CTAGS)
478 puts ("-d, --defines\n\
479 Create tag entries for constant C #defines, too.");
480 else
481 puts ("-D, --no-defines\n\
482 Don't create tag entries for constant C #defines. This makes\n\
483 the tags file smaller.");
485 if (!CTAGS)
487 puts ("-i FILE, --include=FILE\n\
488 Include a note in tag file indicating that, when searching for\n\
489 a tag, one should also consult the tags file FILE after\n\
490 checking the current file.");
491 puts ("-l LANG, --language=LANG\n\
492 Force the following files to be considered as written in the\n\
493 named language up to the next --language=LANG option.");
496 #ifdef ETAGS_REGEXPS
497 puts ("-r /REGEXP/, --regex=/REGEXP/\n\
498 Make a tag for each line matching pattern REGEXP in the\n\
499 following files. REGEXP is anchored (as if preceded by ^).\n\
500 The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
501 named tags can be created with:\n\
502 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
503 puts ("-R, --no-regex\n\
504 Don't create tags from regexps for the following files.");
505 #endif /* ETAGS_REGEXPS */
506 puts ("-o FILE, --output=FILE\n\
507 Write the tags to FILE.");
508 puts ("-I, --ignore-indentation\n\
509 Don't rely on indentation quite as much as normal. Currently,\n\
510 this means not to assume that a closing brace in the first\n\
511 column is the final brace of a function or structure\n\
512 definition in C and C++.");
514 if (CTAGS)
516 puts ("-t, --typedefs\n\
517 Generate tag entries for C typedefs.");
518 puts ("-T, --typedefs-and-c++\n\
519 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
520 and C++ member functions.");
521 puts ("-u, --update\n\
522 Update the tag entries for the given files, leaving tag\n\
523 entries for other files in place. Currently, this is\n\
524 implemented by deleting the existing entries for the given\n\
525 files and then rewriting the new entries at the end of the\n\
526 tags file. It is often faster to simply rebuild the entire\n\
527 tag file than to use this.");
528 puts ("-v, --vgrind\n\
529 Generates an index of items intended for human consumption,\n\
530 similar to the output of vgrind. The index is sorted, and\n\
531 gives the page number of each item.");
532 puts ("-w, --no-warn\n\
533 Suppress warning messages about entries defined in multiple\n\
534 files.");
535 puts ("-x, --cxref\n\
536 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
537 The output uses line numbers instead of page numbers, but\n\
538 beyond that the differences are cosmetic; try both to see\n\
539 which you like.");
542 puts ("-V, --version\n\
543 Print the version of the program.\n\
544 -h, --help\n\
545 Print this help message.");
547 print_language_names ();
549 exit (GOOD);
553 enum argument_type
555 at_language,
556 at_regexp,
557 at_filename
560 /* This structure helps us allow mixing of --lang and filenames. */
561 typedef struct
563 enum argument_type arg_type;
564 char *what;
565 Lang_function *function;
566 } ARGUMENT;
568 #ifdef VMS /* VMS specific functions */
570 #define EOS '\0'
572 /* This is a BUG! ANY arbitrary limit is a BUG!
573 Won't someone please fix this? */
574 #define MAX_FILE_SPEC_LEN 255
575 typedef struct {
576 short curlen;
577 char body[MAX_FILE_SPEC_LEN + 1];
578 } vspec;
581 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
582 returning in each successive call the next filename matching the input
583 spec. The function expects that each in_spec passed
584 to it will be processed to completion; in particular, up to and
585 including the call following that in which the last matching name
586 is returned, the function ignores the value of in_spec, and will
587 only start processing a new spec with the following call.
588 If an error occurs, on return out_spec contains the value
589 of in_spec when the error occurred.
591 With each successive filename returned in out_spec, the
592 function's return value is one. When there are no more matching
593 names the function returns zero. If on the first call no file
594 matches in_spec, or there is any other error, -1 is returned.
597 #include <rmsdef.h>
598 #include <descrip.h>
599 #define OUTSIZE MAX_FILE_SPEC_LEN
600 short
601 fn_exp (out, in)
602 vspec *out;
603 char *in;
605 static long context = 0;
606 static struct dsc$descriptor_s o;
607 static struct dsc$descriptor_s i;
608 static logical pass1 = TRUE;
609 long status;
610 short retval;
612 if (pass1)
614 pass1 = FALSE;
615 o.dsc$a_pointer = (char *) out;
616 o.dsc$w_length = (short)OUTSIZE;
617 i.dsc$a_pointer = in;
618 i.dsc$w_length = (short)strlen(in);
619 i.dsc$b_dtype = DSC$K_DTYPE_T;
620 i.dsc$b_class = DSC$K_CLASS_S;
621 o.dsc$b_dtype = DSC$K_DTYPE_VT;
622 o.dsc$b_class = DSC$K_CLASS_VS;
624 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
626 out->body[out->curlen] = EOS;
627 return 1;
629 else if (status == RMS$_NMF)
630 retval = 0;
631 else
633 strcpy(out->body, in);
634 retval = -1;
636 lib$find_file_end(&context);
637 pass1 = TRUE;
638 return retval;
642 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
643 name of each file specified by the provided arg expanding wildcards.
645 char *
646 gfnames (arg, p_error)
647 char *arg;
648 logical *p_error;
650 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
652 switch (fn_exp (&filename, arg))
654 case 1:
655 *p_error = FALSE;
656 return filename.body;
657 case 0:
658 *p_error = FALSE;
659 return NULL;
660 default:
661 *p_error = TRUE;
662 return filename.body;
666 #ifndef OLD /* Newer versions of VMS do provide `system'. */
667 system (cmd)
668 char *cmd;
670 fprintf (stderr, "system() function not implemented under VMS\n");
672 #endif
674 #define VERSION_DELIM ';'
675 char *massage_name (s)
676 char *s;
678 char *start = s;
680 for ( ; *s; s++)
681 if (*s == VERSION_DELIM)
683 *s = EOS;
684 break;
686 else
687 *s = tolower(*s);
688 return start;
690 #endif /* VMS */
693 void
694 main (argc, argv)
695 int argc;
696 char *argv[];
698 int i;
699 unsigned int nincluded_files = 0;
700 char **included_files = xnew (argc, char *);
701 char *this_file;
702 ARGUMENT *argbuffer;
703 int current_arg = 0, file_count = 0;
704 struct linebuffer filename_lb;
705 #ifdef VMS
706 logical got_err;
707 #endif
709 #ifdef DOS_NT
710 _fmode = O_BINARY; /* all of files are treated as binary files */
711 #endif /* DOS_NT */
713 progname = argv[0];
715 /* Allocate enough no matter what happens. Overkill, but each one
716 is small. */
717 argbuffer = xnew (argc, ARGUMENT);
719 #ifdef ETAGS_REGEXPS
720 /* Set syntax for regular expression routines. */
721 re_set_syntax (RE_SYNTAX_EMACS);
722 #endif /* ETAGS_REGEXPS */
725 * If etags, always find typedefs and structure tags. Why not?
726 * Also default is to find macro constants.
728 if (!CTAGS)
729 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
731 while (1)
733 int opt = getopt_long (argc, argv,
734 "-aCdDf:Il:o:r:RStTi:BuvxwVhH", longopts, 0);
736 if (opt == EOF)
737 break;
739 switch (opt)
741 case 0:
742 /* If getopt returns 0, then it has already processed a
743 long-named option. We should do nothing. */
744 break;
746 case 1:
747 /* This means that a filename has been seen. Record it. */
748 argbuffer[current_arg].arg_type = at_filename;
749 argbuffer[current_arg].what = optarg;
750 ++current_arg;
751 ++file_count;
752 break;
754 /* Common options. */
755 case 'a':
756 append_to_tagfile = TRUE;
757 break;
758 case 'C':
759 cplusplus = TRUE;
760 break;
761 case 'd':
762 constantypedefs = TRUE;
763 break;
764 case 'D':
765 constantypedefs = FALSE;
766 break;
767 case 'f': /* for compatibility with old makefiles */
768 case 'o':
769 if (tagfile)
771 fprintf (stderr, "%s: -%c option may only be given once.\n",
772 progname, opt);
773 goto usage;
775 tagfile = optarg;
776 break;
777 case 'I':
778 case 'S': /* for backward compatibility */
779 noindentypedefs = TRUE;
780 break;
781 case 'l':
782 if (!get_language (optarg, &argbuffer[current_arg].function))
784 fprintf (stderr, "%s: language \"%s\" not recognized.\n",
785 progname, optarg);
786 goto usage;
788 argbuffer[current_arg].arg_type = at_language;
789 ++current_arg;
790 break;
791 #ifdef ETAGS_REGEXPS
792 case 'r':
793 argbuffer[current_arg].arg_type = at_regexp;
794 argbuffer[current_arg].what = optarg;
795 ++current_arg;
796 break;
797 case 'R':
798 argbuffer[current_arg].arg_type = at_regexp;
799 argbuffer[current_arg].what = NULL;
800 ++current_arg;
801 break;
802 #endif /* ETAGS_REGEXPS */
803 case 'V':
804 print_version ();
805 break;
806 case 'h':
807 case 'H':
808 print_help ();
809 break;
810 case 't':
811 typedefs = TRUE;
812 break;
813 case 'T':
814 typedefs = typedefs_and_cplusplus = TRUE;
815 break;
816 #if (!CTAGS)
817 /* Etags options */
818 case 'i':
819 included_files[nincluded_files++] = optarg;
820 break;
821 #else /* CTAGS */
822 /* Ctags options. */
823 case 'B':
824 searchar = '?';
825 break;
826 case 'u':
827 update = TRUE;
828 break;
829 case 'v':
830 vgrind_style = TRUE;
831 /*FALLTHRU*/
832 case 'x':
833 cxref_style = TRUE;
834 break;
835 case 'w':
836 no_warnings = TRUE;
837 break;
838 #endif /* CTAGS */
839 default:
840 goto usage;
844 for (; optind < argc; ++optind)
846 argbuffer[current_arg].arg_type = at_filename;
847 argbuffer[current_arg].what = argv[optind];
848 ++current_arg;
849 ++file_count;
852 if (nincluded_files == 0 && file_count == 0)
854 fprintf (stderr, "%s: No input files specified.\n", progname);
856 usage:
857 fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
858 progname);
859 exit (BAD);
862 if (tagfile == NULL)
864 tagfile = CTAGS ? "tags" : "TAGS";
866 cwd = etags_getcwd (); /* the current working directory */
867 strcat (cwd, "/");
868 if (streq (tagfile, "-"))
870 tagfiledir = cwd;
872 else
874 tagfiledir = absolute_dirname (tagfile, cwd);
877 init (); /* set up boolean "functions" */
879 initbuffer (&lb);
880 initbuffer (&token_name);
881 initbuffer (&lbs[0].lb);
882 initbuffer (&lbs[1].lb);
883 initbuffer (&filename_lb);
885 if (!CTAGS)
887 if (streq (tagfile, "-"))
888 tagf = stdout;
889 else
890 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
891 if (tagf == NULL)
892 pfatal (tagfile);
896 * Loop through files finding functions.
898 for (i = 0; i < current_arg; ++i)
900 switch (argbuffer[i].arg_type)
902 case at_language:
903 lang_func = argbuffer[i].function;
904 break;
905 #ifdef ETAGS_REGEXPS
906 case at_regexp:
907 add_regex (argbuffer[i].what);
908 break;
909 #endif
910 case at_filename:
911 #ifdef VMS
912 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
914 if (got_err)
916 error ("Can't find file %s\n", this_file);
917 argc--, argv++;
919 else
921 this_file = massage_name (this_file);
923 #else
924 this_file = argbuffer[i].what;
925 #endif
926 /* Input file named "-" means read file names from stdin
927 and use them. */
928 if (streq (this_file, "-"))
929 while (readline_internal (&filename_lb, stdin) > 0)
930 process_file (filename_lb.buffer);
931 else
932 process_file (this_file);
933 #ifdef VMS
935 #endif
936 break;
940 if (!CTAGS)
942 while (nincluded_files-- > 0)
943 fprintf (tagf, "\f\n%s,include\n", *included_files++);
945 fclose (tagf);
946 exit (GOOD);
949 /* If CTAGS, we are here. process_file did not write the tags yet,
950 because we want them ordered. Let's do it now. */
951 if (cxref_style)
953 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
954 if (tagf == NULL)
955 pfatal (tagfile);
956 put_entries (head);
957 exit (GOOD);
960 if (update)
962 char cmd[BUFSIZ];
963 for (i = 0; i < current_arg; ++i)
965 if (argbuffer[i].arg_type != at_filename)
966 continue;
967 sprintf (cmd,
968 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
969 tagfile, argbuffer[i].what, tagfile);
970 if (system (cmd) != GOOD)
971 fatal ("failed to execute shell command");
973 append_to_tagfile = TRUE;
976 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
977 if (tagf == NULL)
978 pfatal (tagfile);
979 put_entries (head);
980 fclose (tagf);
982 if (update)
984 char cmd[BUFSIZ];
985 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
986 exit (system (cmd));
988 exit (GOOD);
993 * Set the language, given the name.
995 logical
996 get_language (language, func)
997 char *language;
998 Lang_function **func;
1000 struct lang_entry *lang;
1002 for (lang = lang_names; lang->suffix; ++lang)
1004 if (streq (language, lang->suffix))
1006 *func = lang->function;
1007 return TRUE;
1011 return FALSE;
1016 * This routine is called on each file argument.
1018 void
1019 process_file (file)
1020 char *file;
1022 struct stat stat_buf;
1023 FILE *inf;
1025 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
1027 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
1028 return;
1030 if (streq (file, tagfile) && !streq (tagfile, "-"))
1032 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
1033 return;
1035 inf = fopen (file, "r");
1036 if (inf == NULL)
1038 perror (file);
1039 return;
1042 find_entries (file, inf);
1044 if (!CTAGS)
1046 char *filename;
1048 if (absolutefn (file))
1050 /* file is an absolute filename. Canonicalise it. */
1051 filename = absolute_filename (file, cwd);
1053 else
1055 /* file is a filename relative to cwd. Make it relative
1056 to the directory of the tags file. */
1057 filename = relative_filename (file, tagfiledir);
1059 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1060 free (filename);
1061 put_entries (head);
1062 free_tree (head);
1063 head = NULL;
1068 * This routine sets up the boolean pseudo-functions which work
1069 * by setting boolean flags dependent upon the corresponding character
1070 * Every char which is NOT in that string is not a white char. Therefore,
1071 * all of the array "_wht" is set to FALSE, and then the elements
1072 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1073 * of a char is TRUE if it is the string "white", else FALSE.
1075 void
1076 init ()
1078 register char *sp;
1079 register int i;
1081 for (i = 0; i < 0177; i++)
1082 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
1083 for (sp = white; *sp; sp++)
1084 _wht[*sp] = TRUE;
1085 for (sp = endtk; *sp; sp++)
1086 _etk[*sp] = TRUE;
1087 for (sp = intk; *sp; sp++)
1088 _itk[*sp] = TRUE;
1089 for (sp = begtk; *sp; sp++)
1090 _btk[*sp] = TRUE;
1091 _wht[0] = _wht['\n'];
1092 _etk[0] = _etk['\n'];
1093 _btk[0] = _btk['\n'];
1094 _itk[0] = _itk['\n'];
1098 * This routine opens the specified file and calls the function
1099 * which finds the function and type definitions.
1101 void
1102 find_entries (file, inf)
1103 char *file;
1104 FILE *inf;
1106 char *cp;
1107 struct lang_entry *lang;
1108 NODE *old_last_node;
1109 extern NODE *last_node;
1111 /* The memory block pointed by curfile is never released for simplicity. */
1112 curfile = savestr (file);
1113 cp = etags_strrchr (file, '.');
1115 /* If user specified a language, use it. */
1116 if (lang_func != NULL)
1118 lang_func (inf);
1119 fclose (inf);
1120 return;
1123 if (cp)
1125 ++cp;
1126 for (lang = lang_suffixes; lang->suffix; ++lang)
1128 if (streq (cp, lang->suffix))
1130 lang->function (inf);
1131 fclose (inf);
1132 return;
1137 /* Try Fortran. */
1138 old_last_node = last_node;
1139 Fortran_functions (inf);
1141 /* No Fortran entries found. Try C. */
1142 if (old_last_node == last_node)
1144 rewind (inf);
1145 default_C_entries (inf);
1147 fclose (inf);
1150 /* Record a tag. */
1151 void
1152 pfnote (name, is_func, linestart, linelen, lno, cno)
1153 char *name; /* tag name, if different from definition */
1154 logical is_func; /* tag is a function */
1155 char *linestart; /* start of the line where tag is */
1156 int linelen; /* length of the line where tag is */
1157 int lno; /* line number */
1158 long cno; /* character number */
1160 register NODE *np = xnew (1, NODE);
1162 /* If ctags mode, change name "main" to M<thisfilename>. */
1163 if (CTAGS && !cxref_style && streq (name, "main"))
1165 register char *fp = etags_strrchr (curfile, '/');
1166 np->name = concat ("M", fp == 0 ? curfile : fp + 1, "");
1167 fp = etags_strrchr (np->name, '.');
1168 if (fp && fp[1] != '\0' && fp[2] == '\0')
1169 fp[0] = 0;
1171 else
1172 np->name = name;
1173 np->been_warned = FALSE;
1174 np->file = curfile;
1175 np->is_func = is_func;
1176 np->lno = lno;
1177 /* Our char numbers are 0-base, because of C language tradition?
1178 ctags compatibility? old versions compatibility? I don't know.
1179 Anyway, since emacs's are 1-base we espect etags.el to take care
1180 of the difference. If we wanted to have 1-based numbers, we would
1181 uncomment the +1 below. */
1182 np->cno = cno /* + 1 */ ;
1183 np->left = np->right = NULL;
1184 np->pat = savenstr (linestart, ((CTAGS && !cxref_style) ? 50 : linelen));
1186 add_node (np, &head);
1190 * free_tree ()
1191 * recurse on left children, iterate on right children.
1193 void
1194 free_tree (node)
1195 register NODE *node;
1197 while (node)
1199 register NODE *node_right = node->right;
1200 free_tree (node->left);
1201 if (node->name != NULL)
1202 free (node->name);
1203 free (node->pat);
1204 free ((char *) node);
1205 node = node_right;
1210 * add_node ()
1211 * Adds a node to the tree of nodes. In etags mode, we don't keep
1212 * it sorted; we just keep a linear list. In ctags mode, maintain
1213 * an ordered tree, with no attempt at balancing.
1215 * add_node is the only function allowed to add nodes, so it can
1216 * maintain state.
1218 NODE *last_node = NULL;
1219 void
1220 add_node (node, cur_node_p)
1221 NODE *node, **cur_node_p;
1223 register int dif;
1224 register NODE *cur_node = *cur_node_p;
1226 if (cur_node == NULL)
1228 *cur_node_p = node;
1229 last_node = node;
1230 return;
1233 if (!CTAGS)
1235 /* Etags Mode */
1236 if (last_node == NULL)
1237 fatal ("internal error in add_node", 0);
1238 last_node->right = node;
1239 last_node = node;
1241 else
1243 /* Ctags Mode */
1244 dif = strcmp (node->name, cur_node->name);
1247 * If this tag name matches an existing one, then
1248 * do not add the node, but maybe print a warning.
1250 if (!dif)
1252 if (streq (node->file, cur_node->file))
1254 if (!no_warnings)
1256 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1257 node->file, lineno, node->name);
1258 fprintf (stderr, "Second entry ignored\n");
1260 return;
1262 if (!cur_node->been_warned && !no_warnings)
1264 fprintf (stderr,
1265 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1266 node->file, cur_node->file, node->name);
1268 cur_node->been_warned = TRUE;
1269 return;
1272 /* Maybe refuse to add duplicate nodes. */
1273 if (!permit_duplicates)
1275 if (streq (node->name, cur_node->name)
1276 && streq (node->file, cur_node->file))
1277 return;
1280 /* Actually add the node */
1281 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1285 void
1286 put_entries (node)
1287 register NODE *node;
1289 register char *sp;
1291 if (node == NULL)
1292 return;
1294 /* Output subentries that precede this one */
1295 put_entries (node->left);
1297 /* Output this entry */
1299 if (!CTAGS)
1301 if (node->name != NULL)
1302 fprintf (tagf, "%s\177%s\001%d,%d\n",
1303 node->pat, node->name, node->lno, node->cno);
1304 else
1305 fprintf (tagf, "%s\177%d,%d\n",
1306 node->pat, node->lno, node->cno);
1308 else if (!cxref_style)
1310 fprintf (tagf, "%s\t%s\t",
1311 node->name, node->file);
1313 if (node->is_func)
1314 { /* a function */
1315 putc (searchar, tagf);
1316 putc ('^', tagf);
1318 for (sp = node->pat; *sp; sp++)
1320 if (*sp == '\\' || *sp == searchar)
1321 putc ('\\', tagf);
1322 putc (*sp, tagf);
1324 putc (searchar, tagf);
1326 else
1327 { /* a typedef; text pattern inadequate */
1328 fprintf (tagf, "%d", node->lno);
1330 putc ('\n', tagf);
1332 else if (vgrind_style)
1333 fprintf (stdout, "%s %s %d\n",
1334 node->name, node->file, (node->lno + 63) / 64);
1335 else
1336 fprintf (stdout, "%-16s %3d %-16s %s\n",
1337 node->name, node->lno, node->file, node->pat);
1339 /* Output subentries that follow this one */
1340 put_entries (node->right);
1343 /* Length of a number's decimal representation. */
1345 number_len (num)
1346 long num;
1348 int len = 0;
1349 if (!num)
1350 return 1;
1351 for (; num; num /= 10)
1352 ++len;
1353 return len;
1357 * Return total number of characters that put_entries will output for
1358 * the nodes in the subtree of the specified node. Works only if
1359 * we are not ctags, but called only in that case. This count
1360 * is irrelevant with the new tags.el, but is still supplied for
1361 * backward compatibility.
1364 total_size_of_entries (node)
1365 register NODE *node;
1367 register int total;
1369 if (node == NULL)
1370 return 0;
1372 total = 0;
1373 for (; node; node = node->right)
1375 /* Count left subentries. */
1376 total += total_size_of_entries (node->left);
1378 /* Count this entry */
1379 total += strlen (node->pat) + 1;
1380 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1381 if (node->name != NULL)
1382 total += 1 + strlen (node->name); /* \001name */
1385 return total;
1389 * The C symbol tables.
1391 enum sym_type
1393 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
1396 /* Feed stuff between (but not including) %[ and %] lines to:
1397 gperf -c -k1,3 -o -p -r -t
1399 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1401 class, C_PLPL, st_C_struct
1402 domain, C_STAR, st_C_struct
1403 union, 0, st_C_struct
1404 struct, 0, st_C_struct
1405 enum, 0, st_C_enum
1406 typedef, 0, st_C_typedef
1407 define, 0, st_C_define
1408 long, 0, st_C_typespec
1409 short, 0, st_C_typespec
1410 int, 0, st_C_typespec
1411 char, 0, st_C_typespec
1412 float, 0, st_C_typespec
1413 double, 0, st_C_typespec
1414 signed, 0, st_C_typespec
1415 unsigned, 0, st_C_typespec
1416 auto, 0, st_C_typespec
1417 void, 0, st_C_typespec
1418 extern, 0, st_C_typespec
1419 static, 0, st_C_typespec
1420 const, 0, st_C_typespec
1421 volatile, 0, st_C_typespec
1423 and replace lines between %< and %> with its output. */
1424 /*%<*/
1425 /* C code produced by gperf version 1.8.1 (K&R C version) */
1426 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1429 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1431 #define MIN_WORD_LENGTH 3
1432 #define MAX_WORD_LENGTH 8
1433 #define MIN_HASH_VALUE 10
1434 #define MAX_HASH_VALUE 62
1436 21 keywords
1437 53 is the maximum key range
1440 static int
1441 hash (str, len)
1442 register char *str;
1443 register int len;
1445 static unsigned char hash_table[] =
1447 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1448 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1449 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1450 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1451 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1452 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1453 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1454 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1455 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1456 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1457 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1458 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1459 62, 62, 62, 62, 62, 62, 62, 62,
1461 return len + hash_table[str[2]] + hash_table[str[0]];
1464 struct C_stab_entry *
1465 in_word_set (str, len)
1466 register char *str;
1467 register int len;
1470 static struct C_stab_entry wordlist[] =
1472 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1473 {"",},
1474 {"volatile", 0, st_C_typespec},
1475 {"",},
1476 {"long", 0, st_C_typespec},
1477 {"char", 0, st_C_typespec},
1478 {"class", C_PLPL, st_C_struct},
1479 {"",}, {"",}, {"",}, {"",},
1480 {"const", 0, st_C_typespec},
1481 {"",}, {"",}, {"",}, {"",},
1482 {"auto", 0, st_C_typespec},
1483 {"",}, {"",},
1484 {"define", 0, st_C_define},
1485 {"",},
1486 {"void", 0, st_C_typespec},
1487 {"",}, {"",}, {"",},
1488 {"extern", 0, st_C_typespec},
1489 {"static", 0, st_C_typespec},
1490 {"",},
1491 {"domain", C_STAR, st_C_struct},
1492 {"",},
1493 {"typedef", 0, st_C_typedef},
1494 {"double", 0, st_C_typespec},
1495 {"enum", 0, st_C_enum},
1496 {"",}, {"",}, {"",}, {"",},
1497 {"int", 0, st_C_typespec},
1498 {"",},
1499 {"float", 0, st_C_typespec},
1500 {"",}, {"",}, {"",},
1501 {"struct", 0, st_C_struct},
1502 {"",}, {"",}, {"",}, {"",},
1503 {"union", 0, st_C_struct},
1504 {"",},
1505 {"short", 0, st_C_typespec},
1506 {"",}, {"",},
1507 {"unsigned", 0, st_C_typespec},
1508 {"signed", 0, st_C_typespec},
1511 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1513 register int key = hash (str, len);
1515 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1517 register char *s = wordlist[key].name;
1519 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1520 return &wordlist[key];
1523 return 0;
1525 /*%>*/
1527 enum sym_type
1528 C_symtype(str, len, c_ext)
1529 char *str;
1530 int len;
1531 int c_ext;
1533 register struct C_stab_entry *se = in_word_set(str, len);
1535 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1536 return st_none;
1537 return se->type;
1541 * C functions are recognized using a simple finite automaton.
1542 * funcdef is its state variable.
1544 typedef enum
1546 fnone, /* nothing seen */
1547 ftagseen, /* function-like tag seen */
1548 fstartlist, /* just after open parenthesis */
1549 finlist, /* in parameter list */
1550 flistseen, /* after parameter list */
1551 fignore /* before open brace */
1552 } FUNCST;
1553 FUNCST funcdef;
1557 * typedefs are recognized using a simple finite automaton.
1558 * typeddef is its state variable.
1560 typedef enum
1562 tnone, /* nothing seen */
1563 ttypedseen, /* typedef keyword seen */
1564 tinbody, /* inside typedef body */
1565 tend, /* just before typedef tag */
1566 tignore /* junk after typedef tag */
1567 } TYPEDST;
1568 TYPEDST typdef;
1572 * struct-like structures (enum, struct and union) are recognized
1573 * using another simple finite automaton. `structdef' is its state
1574 * variable.
1576 typedef enum
1578 snone, /* nothing seen yet */
1579 skeyseen, /* struct-like keyword seen */
1580 stagseen, /* struct-like tag seen */
1581 scolonseen, /* colon seen after struct-like tag */
1582 sinbody /* in struct body: recognize member func defs*/
1583 } STRUCTST;
1584 STRUCTST structdef;
1587 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1588 * struct tag, and structtype is the type of the preceding struct-like
1589 * keyword.
1591 char *structtag = "<uninited>";
1592 enum sym_type structtype;
1595 * Yet another little state machine to deal with preprocessor lines.
1597 typedef enum
1599 dnone, /* nothing seen */
1600 dsharpseen, /* '#' seen as first char on line */
1601 ddefineseen, /* '#' and 'define' seen */
1602 dignorerest /* ignore rest of line */
1603 } DEFINEST;
1604 DEFINEST definedef;
1607 * Set this to TRUE, and the next token considered is called a function.
1608 * Used only for GNU emacs's function-defining macros.
1610 logical next_token_is_func;
1613 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1615 logical yacc_rules;
1618 * consider_token ()
1619 * checks to see if the current token is at the start of a
1620 * function, or corresponds to a typedef, or is a struct/union/enum
1621 * tag.
1623 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1624 * C_EXT is which language we are looking at.
1626 * In the future we will need some way to adjust where the end of
1627 * the token is; for instance, implementing the C++ keyword
1628 * `operator' properly will adjust the end of the token to be after
1629 * whatever follows `operator'.
1631 * Globals
1632 * funcdef IN OUT
1633 * structdef IN OUT
1634 * definedef IN OUT
1635 * typdef IN OUT
1636 * next_token_is_func IN OUT
1639 logical
1640 consider_token (str, len, c, c_ext, cblev, is_func)
1641 register char *str; /* IN: token pointer */
1642 register int len; /* IN: token length */
1643 register char c; /* IN: first char after the token */
1644 int c_ext; /* IN: C extensions mask */
1645 int cblev; /* IN: curly brace level */
1646 logical *is_func; /* OUT: function found */
1648 enum sym_type toktype = C_symtype (str, len, c_ext);
1651 * Advance the definedef state machine.
1653 switch (definedef)
1655 case dnone:
1656 /* We're not on a preprocessor line. */
1657 break;
1658 case dsharpseen:
1659 if (toktype == st_C_define)
1661 definedef = ddefineseen;
1663 else
1665 definedef = dignorerest;
1667 return FALSE;
1668 case ddefineseen:
1670 * Make a tag for any macro, unless it is a constant
1671 * and constantypedefs is FALSE.
1673 definedef = dignorerest;
1674 *is_func = (c == '(');
1675 if (!*is_func && !constantypedefs)
1676 return FALSE;
1677 else
1678 return TRUE;
1679 case dignorerest:
1680 return FALSE;
1681 default:
1682 error ("internal error: definedef value.", 0);
1686 * Now typedefs
1688 switch (typdef)
1690 case tnone:
1691 if (toktype == st_C_typedef)
1693 if (typedefs)
1694 typdef = ttypedseen;
1695 funcdef = fnone;
1696 return FALSE;
1698 break;
1699 case ttypedseen:
1700 switch (toktype)
1702 case st_none:
1703 case st_C_typespec:
1704 typdef = tend;
1705 break;
1706 case st_C_struct:
1707 case st_C_enum:
1708 break;
1710 /* Do not return here, so the structdef stuff has a chance. */
1711 break;
1712 case tend:
1713 switch (toktype)
1715 case st_C_typespec:
1716 case st_C_struct:
1717 case st_C_enum:
1718 return FALSE;
1720 return TRUE;
1724 * This structdef business is currently only invoked when cblev==0.
1725 * It should be recursively invoked whatever the curly brace level,
1726 * and a stack of states kept, to allow for definitions of structs
1727 * within structs.
1729 * This structdef business is NOT invoked when we are ctags and the
1730 * file is plain C. This is because a struct tag may have the same
1731 * name as another tag, and this loses with ctags.
1733 * This if statement deals with the typdef state machine as
1734 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1735 * return FALSE. All the other code here is for the structdef
1736 * state machine.
1738 switch (toktype)
1740 case st_C_struct:
1741 case st_C_enum:
1742 if (typdef == ttypedseen
1743 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1745 structdef = skeyseen;
1746 structtype = toktype;
1748 return FALSE;
1750 if (structdef == skeyseen)
1752 /* Save the tag for struct/union/class, for functions that may be
1753 defined inside. */
1754 if (structtype == st_C_struct)
1755 structtag = savenstr (str, len);
1756 else
1757 structtag = "<enum>";
1758 structdef = stagseen;
1759 return TRUE;
1762 /* Avoid entering funcdef stuff if typdef is going on. */
1763 if (typdef != tnone)
1765 definedef = dnone;
1766 return FALSE;
1769 /* Detect GNU macros. */
1770 if (definedef == dnone)
1771 if (strneq (str, "DEFUN", len) /* Used in emacs */
1772 #if FALSE
1773 These are defined inside C functions, so currently they
1774 are not met anyway.
1775 || strneq (str, "EXFUN", len) /* Used in glibc */
1776 || strneq (str, "DEFVAR_", 7) /* Used in emacs */
1777 #endif
1778 || strneq (str, "SYSCALL", len) /* Used in glibc (mach) */
1779 || strneq (str, "ENTRY", len) /* Used in glibc */
1780 || strneq (str, "PSEUDO", len)) /* Used in glibc */
1783 next_token_is_func = TRUE;
1784 return FALSE;
1786 if (next_token_is_func)
1788 next_token_is_func = FALSE;
1789 funcdef = fignore;
1790 *is_func = TRUE;
1791 return TRUE;
1794 /* A function? */
1795 switch (toktype)
1797 case st_C_typespec:
1798 if (funcdef != finlist && funcdef != fignore)
1799 funcdef = fnone; /* should be useless */
1800 return FALSE;
1801 default:
1802 if (funcdef == fnone)
1804 funcdef = ftagseen;
1805 *is_func = TRUE;
1806 return TRUE;
1810 return FALSE;
1814 * C_entries ()
1815 * This routine finds functions, typedefs, #define's and
1816 * struct/union/enum definitions in C syntax and adds them
1817 * to the list.
1819 typedef struct
1821 logical valid;
1822 char *str;
1823 logical named;
1824 int linelen;
1825 int lineno;
1826 long linepos;
1827 char *buffer;
1828 } TOKEN;
1830 #define current_lb_is_new (newndx == curndx)
1831 #define switch_line_buffers() (curndx = 1 - curndx)
1833 #define curlb (lbs[curndx].lb)
1834 #define othlb (lbs[1-curndx].lb)
1835 #define newlb (lbs[newndx].lb)
1836 #define curlinepos (lbs[curndx].linepos)
1837 #define othlinepos (lbs[1-curndx].linepos)
1838 #define newlinepos (lbs[newndx].linepos)
1840 #define CNL_SAVE_DEFINEDEF \
1841 do { \
1842 curlinepos = charno; \
1843 lineno++; \
1844 charno += readline (&curlb, inf); \
1845 lp = curlb.buffer; \
1846 quotednl = FALSE; \
1847 newndx = curndx; \
1848 } while (0)
1850 #define CNL \
1851 do { \
1852 CNL_SAVE_DEFINEDEF; \
1853 if (savetok.valid) \
1855 tok = savetok; \
1856 savetok.valid = FALSE; \
1858 definedef = dnone; \
1859 } while (0)
1861 #define make_tag(isfun) do \
1863 if (tok.valid) \
1865 char *name = NULL; \
1866 if (tok.named) \
1867 name = savestr (token_name.buffer); \
1868 pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \
1870 else if (DEBUG) abort (); \
1871 tok.valid = FALSE; \
1872 } while (0)
1874 void
1875 C_entries (c_ext, inf)
1876 int c_ext; /* extension of C */
1877 FILE *inf; /* input file */
1879 register char c; /* latest char read; '\0' for end of line */
1880 register char *lp; /* pointer one beyond the character `c' */
1881 int curndx, newndx; /* indices for current and new lb */
1882 TOKEN tok; /* latest token read */
1883 register int tokoff; /* offset in line of start of current token */
1884 register int toklen; /* length of current token */
1885 int cblev; /* current curly brace level */
1886 int parlev; /* current parenthesis level */
1887 logical incomm, inquote, inchar, quotednl, midtoken;
1888 logical cplpl;
1889 TOKEN savetok; /* token saved during preprocessor handling */
1892 curndx = newndx = 0;
1893 lineno = 0;
1894 charno = 0;
1895 lp = curlb.buffer;
1896 *lp = 0;
1898 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1899 next_token_is_func = yacc_rules = FALSE;
1900 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1901 tok.valid = savetok.valid = FALSE;
1902 cblev = 0;
1903 parlev = 0;
1904 cplpl = c_ext & C_PLPL;
1906 while (!feof (inf))
1908 c = *lp++;
1909 if (c == '\\')
1911 /* If we're at the end of the line, the next character is a
1912 '\0'; don't skip it, because it's the thing that tells us
1913 to read the next line. */
1914 if (*lp == '\0')
1916 quotednl = TRUE;
1917 continue;
1919 lp++;
1920 c = ' ';
1922 else if (incomm)
1924 switch (c)
1926 case '*':
1927 if (*lp == '/')
1929 c = *lp++;
1930 incomm = FALSE;
1932 break;
1933 case '\0':
1934 /* Newlines inside comments do not end macro definitions in
1935 traditional cpp. */
1936 CNL_SAVE_DEFINEDEF;
1937 break;
1939 continue;
1941 else if (inquote)
1943 switch (c)
1945 case '"':
1946 inquote = FALSE;
1947 break;
1948 case '\0':
1949 /* Newlines inside strings do not end macro definitions
1950 in traditional cpp, even though compilers don't
1951 usually accept them. */
1952 CNL_SAVE_DEFINEDEF;
1953 break;
1955 continue;
1957 else if (inchar)
1959 switch (c)
1961 case '\0':
1962 /* Hmmm, something went wrong. */
1963 CNL;
1964 /* FALLTHRU */
1965 case '\'':
1966 inchar = FALSE;
1967 break;
1969 continue;
1971 else
1972 switch (c)
1974 case '"':
1975 inquote = TRUE;
1976 if (funcdef != finlist && funcdef != fignore)
1977 funcdef = fnone;
1978 continue;
1979 case '\'':
1980 inchar = TRUE;
1981 if (funcdef != finlist && funcdef != fignore)
1982 funcdef = fnone;
1983 continue;
1984 case '/':
1985 if (*lp == '*')
1987 lp++;
1988 incomm = TRUE;
1989 continue;
1991 else if (cplpl && *lp == '/')
1993 c = 0;
1994 break;
1996 else
1997 break;
1998 case '%':
1999 if ((c_ext & YACC) && *lp == '%')
2001 /* entering or exiting rules section in yacc file */
2002 lp++;
2003 definedef = dnone; funcdef = fnone;
2004 typdef = tnone; structdef = snone;
2005 next_token_is_func = FALSE;
2006 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2007 cblev = 0;
2008 yacc_rules = !yacc_rules;
2009 continue;
2011 else
2012 break;
2013 case '#':
2014 if (definedef == dnone)
2016 char *cp;
2017 logical cpptoken = TRUE;
2019 /* Look back on this line. If all blanks, or nonblanks
2020 followed by an end of comment, this is a preprocessor
2021 token. */
2022 for (cp = newlb.buffer; cp < lp-1; cp++)
2023 if (!iswhite (*cp))
2025 if (*cp == '*' && *(cp+1) == '/')
2027 cp++;
2028 cpptoken = TRUE;
2030 else
2031 cpptoken = FALSE;
2033 if (cpptoken)
2034 definedef = dsharpseen;
2035 } /* if (definedef == dnone) */
2037 continue;
2038 } /* switch (c) */
2041 /* Consider token only if some complicated conditions are satisfied. */
2042 if ((definedef != dnone
2043 || (cblev == 0 && structdef != scolonseen)
2044 || (cblev == 1 && cplpl && structdef == sinbody))
2045 && typdef != tignore
2046 && definedef != dignorerest
2047 && funcdef != finlist)
2049 if (midtoken)
2051 if (endtoken (c))
2053 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
2056 * This handles :: in the middle, but not at the
2057 * beginning of an identifier.
2059 lp += 2;
2060 toklen += 3;
2062 else
2064 logical is_func = FALSE;
2066 if (yacc_rules
2067 || consider_token (newlb.buffer + tokoff, toklen,
2068 c, c_ext, cblev, &is_func))
2070 if (structdef == sinbody
2071 && definedef == dnone
2072 && is_func)
2073 /* function defined in C++ class body */
2075 int strsize = strlen(structtag) + 2 + toklen + 1;
2076 while (token_name.size < strsize)
2078 token_name.size *= 2;
2079 token_name.buffer
2080 = (char *) xrealloc (token_name.buffer,
2081 token_name.size);
2083 strcpy (token_name.buffer, structtag);
2084 strcat (token_name.buffer, "::");
2085 strncat (token_name.buffer,
2086 newlb.buffer+tokoff, toklen);
2087 tok.named = TRUE;
2089 else
2091 while (token_name.size < toklen + 1)
2093 token_name.size *= 2;
2094 token_name.buffer
2095 = (char *) xrealloc (token_name.buffer,
2096 token_name.size);
2098 strncpy (token_name.buffer,
2099 newlb.buffer+tokoff, toklen);
2100 token_name.buffer[toklen] = '\0';
2101 if (structdef == stagseen
2102 || typdef == tend
2103 || (is_func
2104 && definedef == dignorerest)) /* macro */
2105 tok.named = TRUE;
2106 else
2107 tok.named = FALSE;
2109 tok.lineno = lineno;
2110 tok.linelen = tokoff + toklen + 1;
2111 tok.buffer = newlb.buffer;
2112 tok.linepos = newlinepos;
2113 tok.valid = TRUE;
2115 if (definedef == dnone
2116 && (funcdef == ftagseen
2117 || structdef == stagseen
2118 || typdef == tend))
2120 if (current_lb_is_new)
2121 switch_line_buffers ();
2123 else
2124 make_tag (is_func);
2126 midtoken = FALSE;
2128 } /* if (endtoken (c)) */
2129 else if (intoken (c))
2131 toklen++;
2132 continue;
2134 } /* if (midtoken) */
2135 else if (begtoken (c))
2137 switch (definedef)
2139 case dnone:
2140 switch (funcdef)
2142 case fstartlist:
2143 funcdef = finlist;
2144 continue;
2145 case flistseen:
2146 make_tag (TRUE);
2147 funcdef = fignore;
2148 break;
2149 case ftagseen:
2150 funcdef = fnone;
2151 break;
2153 if (structdef == stagseen)
2154 structdef = snone;
2155 break;
2156 case dsharpseen:
2157 savetok = tok;
2159 if (!yacc_rules || lp == newlb.buffer + 1)
2161 tokoff = lp - 1 - newlb.buffer;
2162 toklen = 1;
2163 midtoken = TRUE;
2165 continue;
2166 } /* if (begtoken) */
2167 } /* if must look at token */
2170 /* Detect end of line, colon, comma, semicolon and various braces
2171 after having handled a token.*/
2172 switch (c)
2174 case ':':
2175 if (definedef != dnone)
2176 break;
2177 if (structdef == stagseen)
2178 structdef = scolonseen;
2179 else
2180 switch (funcdef)
2182 case ftagseen:
2183 if (yacc_rules)
2185 make_tag (FALSE);
2186 funcdef = fignore;
2188 break;
2189 case fstartlist:
2190 funcdef = fnone;
2191 break;
2193 break;
2194 case ';':
2195 if (definedef != dnone)
2196 break;
2197 if (cblev == 0)
2198 switch (typdef)
2200 case tend:
2201 make_tag (FALSE);
2202 /* FALLTHRU */
2203 default:
2204 typdef = tnone;
2206 if (funcdef != fignore)
2207 funcdef = fnone;
2208 if (structdef == stagseen)
2209 structdef = snone;
2210 break;
2211 case ',':
2212 if (definedef != dnone)
2213 break;
2214 if (funcdef != finlist && funcdef != fignore)
2215 funcdef = fnone;
2216 if (structdef == stagseen)
2217 structdef = snone;
2218 break;
2219 case '[':
2220 if (definedef != dnone)
2221 break;
2222 if (cblev == 0 && typdef == tend)
2224 typdef = tignore;
2225 make_tag (FALSE);
2226 break;
2228 if (funcdef != finlist && funcdef != fignore)
2229 funcdef = fnone;
2230 if (structdef == stagseen)
2231 structdef = snone;
2232 break;
2233 case '(':
2234 if (definedef != dnone)
2235 break;
2236 switch (funcdef)
2238 case fnone:
2239 switch (typdef)
2241 case ttypedseen:
2242 case tend:
2243 /* Make sure that the next char is not a '*'.
2244 This handles constructs like:
2245 typedef void OperatorFun (int fun); */
2246 if (*lp != '*')
2248 typdef = tignore;
2249 make_tag (FALSE);
2251 break;
2252 } /* switch (typdef) */
2253 break;
2254 case ftagseen:
2255 funcdef = fstartlist;
2256 break;
2257 case flistseen:
2258 funcdef = finlist;
2259 break;
2261 parlev++;
2262 break;
2263 case ')':
2264 if (definedef != dnone)
2265 break;
2266 if (--parlev == 0)
2268 switch (funcdef)
2270 case fstartlist:
2271 case finlist:
2272 funcdef = flistseen;
2273 break;
2275 if (cblev == 0 && typdef == tend)
2277 typdef = tignore;
2278 make_tag (FALSE);
2281 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2282 parlev = 0;
2283 break;
2284 case '{':
2285 if (definedef != dnone)
2286 break;
2287 if (typdef == ttypedseen)
2288 typdef = tinbody;
2289 switch (structdef)
2291 case skeyseen: /* unnamed struct */
2292 structtag = "_anonymous_";
2293 structdef = sinbody;
2294 break;
2295 case stagseen:
2296 case scolonseen: /* named struct */
2297 structdef = sinbody;
2298 make_tag (FALSE);
2299 break;
2301 switch (funcdef)
2303 case flistseen:
2304 make_tag (TRUE);
2305 /* FALLTHRU */
2306 case fignore:
2307 funcdef = fnone;
2308 break;
2309 case fnone:
2310 /* Neutralize `extern "C" {' grot and look inside structs. */
2311 if (cblev == 0 && structdef == snone && typdef == tnone)
2312 cblev = -1;
2314 cblev++;
2315 break;
2316 case '*':
2317 if (definedef != dnone)
2318 break;
2319 if (funcdef == fstartlist)
2320 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
2321 break;
2322 case '}':
2323 if (definedef != dnone)
2324 break;
2325 if (!noindentypedefs && lp == newlb.buffer + 1)
2327 cblev = 0; /* reset curly brace level if first column */
2328 parlev = 0; /* also reset paren level, just in case... */
2330 else if (cblev > 0)
2331 cblev--;
2332 if (cblev == 0)
2334 if (typdef == tinbody)
2335 typdef = tend;
2336 if (FALSE) /* too risky */
2337 if (structdef == sinbody)
2338 free (structtag);
2340 structdef = snone;
2341 structtag = "<error>";
2343 break;
2344 case '=':
2345 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2346 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
2347 if (definedef != dnone)
2348 break;
2349 /* These surely cannot follow a function tag. */
2350 if (funcdef != finlist && funcdef != fignore)
2351 funcdef = fnone;
2352 break;
2353 case '\0':
2354 /* If a macro spans multiple lines don't reset its state. */
2355 if (quotednl)
2356 CNL_SAVE_DEFINEDEF;
2357 else
2358 CNL;
2359 break;
2360 } /* switch (c) */
2362 } /* while not eof */
2366 * Process either a C++ file or a C file depending on the setting
2367 * of a global flag.
2369 void
2370 default_C_entries (inf)
2371 FILE *inf;
2373 C_entries (cplusplus ? C_PLPL : 0, inf);
2376 /* Always do plain ANSI C. */
2377 void
2378 plain_C_entries (inf)
2379 FILE *inf;
2381 C_entries (0, inf);
2384 /* Always do C++. */
2385 void
2386 Cplusplus_entries (inf)
2387 FILE *inf;
2389 C_entries (C_PLPL, inf);
2392 /* Always do C*. */
2393 void
2394 Cstar_entries (inf)
2395 FILE *inf;
2397 C_entries (C_STAR, inf);
2400 /* Always do Yacc. */
2401 void
2402 Yacc_entries (inf)
2403 FILE *inf;
2405 C_entries (YACC, inf);
2408 /* Fortran parsing */
2410 char *dbp;
2412 logical
2413 tail (cp)
2414 char *cp;
2416 register int len = 0;
2418 while (*cp && lowcase(*cp) == lowcase(dbp[len]))
2419 cp++, len++;
2420 if (*cp == '\0' && !intoken(dbp[len]))
2422 dbp += len;
2423 return TRUE;
2425 return FALSE;
2428 void
2429 takeprec ()
2431 while (isspace (*dbp))
2432 dbp++;
2433 if (*dbp != '*')
2434 return;
2435 dbp++;
2436 while (isspace (*dbp))
2437 dbp++;
2438 if (strneq (dbp, "(*)", 3))
2440 dbp += 3;
2441 return;
2443 if (!isdigit (*dbp))
2445 --dbp; /* force failure */
2446 return;
2449 dbp++;
2450 while (isdigit (*dbp));
2453 void
2454 getit (inf)
2455 FILE *inf;
2457 register char *cp;
2459 while (isspace (*dbp))
2460 dbp++;
2461 if (*dbp == '\0')
2463 lineno++;
2464 linecharno = charno;
2465 charno += readline (&lb, inf);
2466 dbp = lb.buffer;
2467 if (dbp[5] != '&')
2468 return;
2469 dbp += 6;
2470 while (isspace (*dbp))
2471 dbp++;
2473 if (!isalpha (*dbp)
2474 && *dbp != '_'
2475 && *dbp != '$')
2476 return;
2477 for (cp = dbp + 1;
2478 (*cp
2479 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2480 cp++)
2481 continue;
2482 pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2485 void
2486 Fortran_functions (inf)
2487 FILE *inf;
2489 lineno = 0;
2490 charno = 0;
2492 while (!feof (inf))
2494 lineno++;
2495 linecharno = charno;
2496 charno += readline (&lb, inf);
2497 dbp = lb.buffer;
2498 if (*dbp == '%')
2499 dbp++; /* Ratfor escape to fortran */
2500 while (isspace (*dbp))
2501 dbp++;
2502 if (*dbp == '\0')
2503 continue;
2504 switch (lowcase (*dbp))
2506 case 'i':
2507 if (tail ("integer"))
2508 takeprec ();
2509 break;
2510 case 'r':
2511 if (tail ("real"))
2512 takeprec ();
2513 break;
2514 case 'l':
2515 if (tail ("logical"))
2516 takeprec ();
2517 break;
2518 case 'c':
2519 if (tail ("complex") || tail ("character"))
2520 takeprec ();
2521 break;
2522 case 'd':
2523 if (tail ("double"))
2525 while (isspace (*dbp))
2526 dbp++;
2527 if (*dbp == '\0')
2528 continue;
2529 if (tail ("precision"))
2530 break;
2531 continue;
2533 break;
2535 while (isspace (*dbp))
2536 dbp++;
2537 if (*dbp == '\0')
2538 continue;
2539 switch (lowcase (*dbp))
2541 case 'f':
2542 if (tail ("function"))
2543 getit (inf);
2544 continue;
2545 case 's':
2546 if (tail ("subroutine"))
2547 getit (inf);
2548 continue;
2549 case 'e':
2550 if (tail ("entry"))
2551 getit (inf);
2552 continue;
2553 case 'p':
2554 if (tail ("program"))
2556 getit (inf);
2557 continue;
2559 if (tail ("procedure"))
2560 getit (inf);
2561 continue;
2567 * Bob Weiner, Motorola Inc., 4/3/94
2568 * Unix and microcontroller assembly tag handling
2569 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2571 void
2572 Asm_labels (inf)
2573 FILE *inf;
2575 register char *cp;
2577 lineno = 0;
2578 charno = 0;
2580 while (!feof (inf))
2582 lineno++;
2583 linecharno = charno;
2584 charno += readline (&lb, inf);
2585 cp = lb.buffer;
2587 /* If first char is alphabetic or one of [_.$], test for colon
2588 following identifier. */
2589 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2591 /* Read past label. */
2592 cp++;
2593 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2594 cp++;
2595 if (*cp == ':' || isspace (*cp))
2597 /* Found end of label, so copy it and add it to the table. */
2598 pfnote (NULL, TRUE,
2599 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2605 /* Added by Mosur Mohan, 4/22/88 */
2606 /* Pascal parsing */
2608 #define GET_NEW_LINE \
2610 linecharno = charno; lineno++; \
2611 charno += 1 + readline (&lb, inf); \
2612 dbp = lb.buffer; \
2616 * Locates tags for procedures & functions. Doesn't do any type- or
2617 * var-definitions. It does look for the keyword "extern" or
2618 * "forward" immediately following the procedure statement; if found,
2619 * the tag is skipped.
2621 void
2622 Pascal_functions (inf)
2623 FILE *inf;
2625 struct linebuffer tline; /* mostly copied from C_entries */
2626 long save_lcno;
2627 int save_lineno, save_len;
2628 char c;
2630 logical /* each of these flags is TRUE iff: */
2631 incomment, /* point is inside a comment */
2632 inquote, /* point is inside '..' string */
2633 get_tagname, /* point is after PROCEDURE/FUNCTION
2634 keyword, so next item = potential tag */
2635 found_tag, /* point is after a potential tag */
2636 inparms, /* point is within parameter-list */
2637 verify_tag; /* point has passed the parm-list, so the
2638 next token will determine whether this
2639 is a FORWARD/EXTERN to be ignored, or
2640 whether it is a real tag */
2642 lineno = 0;
2643 charno = 0;
2644 dbp = lb.buffer;
2645 *dbp = '\0';
2646 save_len = 0;
2647 initbuffer (&tline);
2649 incomment = inquote = FALSE;
2650 found_tag = FALSE; /* have a proc name; check if extern */
2651 get_tagname = FALSE; /* have found "procedure" keyword */
2652 inparms = FALSE; /* found '(' after "proc" */
2653 verify_tag = FALSE; /* check if "extern" is ahead */
2655 /* long main loop to get next char */
2656 while (!feof (inf))
2658 c = *dbp++;
2659 if (c == '\0') /* if end of line */
2661 GET_NEW_LINE;
2662 if (*dbp == '\0')
2663 continue;
2664 if (!((found_tag && verify_tag) ||
2665 get_tagname))
2666 c = *dbp++; /* only if don't need *dbp pointing
2667 to the beginning of the name of
2668 the procedure or function */
2670 if (incomment)
2672 if (c == '}') /* within { } comments */
2673 incomment = FALSE;
2674 else if (c == '*' && *dbp == ')') /* within (* *) comments */
2676 dbp++;
2677 incomment = FALSE;
2679 continue;
2681 else if (inquote)
2683 if (c == '\'')
2684 inquote = FALSE;
2685 continue;
2687 else
2688 switch (c)
2690 case '\'':
2691 inquote = TRUE; /* found first quote */
2692 continue;
2693 case '{': /* found open { comment */
2694 incomment = TRUE;
2695 continue;
2696 case '(':
2697 if (*dbp == '*') /* found open (* comment */
2699 incomment = TRUE;
2700 dbp++;
2702 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2703 inparms = TRUE;
2704 continue;
2705 case ')': /* end of parms list */
2706 if (inparms)
2707 inparms = FALSE;
2708 continue;
2709 case ';':
2710 if (found_tag && !inparms) /* end of proc or fn stmt */
2712 verify_tag = TRUE;
2713 break;
2715 continue;
2717 if (found_tag && verify_tag && (*dbp != ' '))
2719 /* check if this is an "extern" declaration */
2720 if (*dbp == '\0')
2721 continue;
2722 if (lowcase (*dbp == 'e'))
2724 if (tail ("extern")) /* superfluous, really! */
2726 found_tag = FALSE;
2727 verify_tag = FALSE;
2730 else if (lowcase (*dbp) == 'f')
2732 if (tail ("forward")) /* check for forward reference */
2734 found_tag = FALSE;
2735 verify_tag = FALSE;
2738 if (found_tag && verify_tag) /* not external proc, so make tag */
2740 found_tag = FALSE;
2741 verify_tag = FALSE;
2742 pfnote (NULL, TRUE,
2743 tline.buffer, save_len, save_lineno, save_lcno);
2744 continue;
2747 if (get_tagname) /* grab name of proc or fn */
2749 int size;
2751 if (*dbp == '\0')
2752 continue;
2754 /* save all values for later tagging */
2755 size = strlen (lb.buffer) + 1;
2756 while (size > tline.size)
2758 tline.size *= 2;
2759 tline.buffer = (char *) xrealloc (tline.buffer, tline.size);
2761 strcpy (tline.buffer, lb.buffer);
2762 save_lineno = lineno;
2763 save_lcno = linecharno;
2765 /* grab block name */
2766 for (dbp++; *dbp && (!endtoken (*dbp)); dbp++)
2767 continue;
2768 save_len = dbp - lb.buffer + 1;
2769 get_tagname = FALSE;
2770 found_tag = TRUE;
2771 continue;
2773 /* and proceed to check for "extern" */
2775 else if (!incomment && !inquote && !found_tag)
2777 /* check for proc/fn keywords */
2778 switch (lowcase (c))
2780 case 'p':
2781 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2782 get_tagname = TRUE;
2783 continue;
2784 case 'f':
2785 if (tail ("unction"))
2786 get_tagname = TRUE;
2787 continue;
2790 } /* while not eof */
2792 free (tline.buffer);
2796 * lisp tag functions
2797 * look for (def or (DEF, quote or QUOTE
2800 L_isdef (strp)
2801 register char *strp;
2803 return ((strp[1] == 'd' || strp[1] == 'D')
2804 && (strp[2] == 'e' || strp[2] == 'E')
2805 && (strp[3] == 'f' || strp[3] == 'F'));
2809 L_isquote (strp)
2810 register char *strp;
2812 return ((*(++strp) == 'q' || *strp == 'Q')
2813 && (*(++strp) == 'u' || *strp == 'U')
2814 && (*(++strp) == 'o' || *strp == 'O')
2815 && (*(++strp) == 't' || *strp == 'T')
2816 && (*(++strp) == 'e' || *strp == 'E')
2817 && isspace(*(++strp)));
2820 void
2821 L_getit ()
2823 register char *cp;
2825 if (*dbp == '\'') /* Skip prefix quote */
2826 dbp++;
2827 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2829 dbp += 7;
2830 while (isspace(*dbp))
2831 dbp++;
2833 for (cp = dbp /*+1*/;
2834 *cp && *cp != '(' && *cp != ' ' && *cp != ')';
2835 cp++)
2836 continue;
2837 if (cp == dbp)
2838 return;
2840 pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2843 void
2844 Lisp_functions (inf)
2845 FILE *inf;
2847 lineno = 0;
2848 charno = 0;
2850 while (!feof (inf))
2852 lineno++;
2853 linecharno = charno;
2854 charno += readline (&lb, inf);
2855 dbp = lb.buffer;
2856 if (dbp[0] == '(')
2858 if (L_isdef (dbp))
2860 while (!isspace (*dbp))
2861 dbp++;
2862 while (isspace (*dbp))
2863 dbp++;
2864 L_getit ();
2866 else
2868 /* Check for (foo::defmumble name-defined ... */
2870 dbp++;
2871 while (*dbp && !isspace (*dbp)
2872 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2873 if (*dbp == ':')
2876 dbp++;
2877 while (*dbp == ':');
2879 if (L_isdef (dbp - 1))
2881 while (!isspace (*dbp))
2882 dbp++;
2883 while (isspace (*dbp))
2884 dbp++;
2885 L_getit ();
2894 * Scheme tag functions
2895 * look for (def... xyzzy
2896 * look for (def... (xyzzy
2897 * look for (def ... ((...(xyzzy ....
2898 * look for (set! xyzzy
2901 void get_scheme ();
2903 void
2904 Scheme_functions (inf)
2905 FILE *inf;
2907 lineno = 0;
2908 charno = 0;
2910 while (!feof (inf))
2912 lineno++;
2913 linecharno = charno;
2914 charno += readline (&lb, inf);
2915 dbp = lb.buffer;
2916 if (dbp[0] == '(' &&
2917 (dbp[1] == 'D' || dbp[1] == 'd') &&
2918 (dbp[2] == 'E' || dbp[2] == 'e') &&
2919 (dbp[3] == 'F' || dbp[3] == 'f'))
2921 while (!isspace (*dbp))
2922 dbp++;
2923 /* Skip over open parens and white space */
2924 while (*dbp && (isspace (*dbp) || *dbp == '('))
2925 dbp++;
2926 get_scheme ();
2928 if (dbp[0] == '(' &&
2929 (dbp[1] == 'S' || dbp[1] == 's') &&
2930 (dbp[2] == 'E' || dbp[2] == 'e') &&
2931 (dbp[3] == 'T' || dbp[3] == 't') &&
2932 (dbp[4] == '!' || dbp[4] == '!') &&
2933 (isspace (dbp[5])))
2935 while (!isspace (*dbp))
2936 dbp++;
2937 /* Skip over white space */
2938 while (isspace (*dbp))
2939 dbp++;
2940 get_scheme ();
2945 void
2946 get_scheme ()
2948 register char *cp;
2950 if (*dbp == '\0')
2951 return;
2952 /* Go till you get to white space or a syntactic break */
2953 for (cp = dbp + 1;
2954 *cp && *cp != '(' && *cp != ')' && !isspace (*cp);
2955 cp++)
2956 continue;
2957 pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2960 /* Find tags in TeX and LaTeX input files. */
2962 /* TEX_toktab is a table of TeX control sequences that define tags.
2963 Each TEX_tabent records one such control sequence.
2964 CONVERT THIS TO USE THE Stab TYPE!! */
2965 struct TEX_tabent
2967 char *name;
2968 int len;
2971 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2973 /* Default set of control sequences to put into TEX_toktab.
2974 The value of environment var TEXTAGS is prepended to this. */
2976 char *TEX_defenv = "\
2977 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2979 void TEX_mode ();
2980 struct TEX_tabent *TEX_decode_env ();
2981 int TEX_Token ();
2982 #if TeX_named_tokens
2983 void TEX_getit ();
2984 #endif
2986 char TEX_esc = '\\';
2987 char TEX_opgrp = '{';
2988 char TEX_clgrp = '}';
2991 * TeX/LaTeX scanning loop.
2993 void
2994 TeX_functions (inf)
2995 FILE *inf;
2997 char *lasthit;
2999 lineno = 0;
3000 charno = 0;
3002 /* Select either \ or ! as escape character. */
3003 TEX_mode (inf);
3005 /* Initialize token table once from environment. */
3006 if (!TEX_toktab)
3007 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
3009 while (!feof (inf))
3010 { /* Scan each line in file */
3011 lineno++;
3012 linecharno = charno;
3013 charno += readline (&lb, inf);
3014 dbp = lb.buffer;
3015 lasthit = dbp;
3016 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
3018 register int i;
3020 if (!*(++dbp))
3021 break;
3022 linecharno += dbp - lasthit;
3023 lasthit = dbp;
3024 i = TEX_Token (lasthit);
3025 if (0 <= i)
3027 pfnote (NULL, TRUE,
3028 lb.buffer, strlen (lb.buffer), lineno, linecharno);
3029 #if TeX_named_tokens
3030 TEX_getit (lasthit, TEX_toktab[i].len);
3031 #endif
3032 break; /* We only save a line once */
3038 #define TEX_LESC '\\'
3039 #define TEX_SESC '!'
3040 #define TEX_cmt '%'
3042 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
3043 chars accordingly. */
3044 void
3045 TEX_mode (inf)
3046 FILE *inf;
3048 int c;
3050 while ((c = getc (inf)) != EOF)
3052 /* Skip to next line if we hit the TeX comment char. */
3053 if (c == TEX_cmt)
3054 while (c != '\n')
3055 c = getc (inf);
3056 else if (c == TEX_LESC || c == TEX_SESC )
3057 break;
3060 if (c == TEX_LESC)
3062 TEX_esc = TEX_LESC;
3063 TEX_opgrp = '{';
3064 TEX_clgrp = '}';
3066 else
3068 TEX_esc = TEX_SESC;
3069 TEX_opgrp = '<';
3070 TEX_clgrp = '>';
3072 rewind (inf);
3075 /* Read environment and prepend it to the default string.
3076 Build token table. */
3077 struct TEX_tabent *
3078 TEX_decode_env (evarname, defenv)
3079 char *evarname;
3080 char *defenv;
3082 register char *env, *p;
3084 struct TEX_tabent *tab;
3085 int size, i;
3087 /* Append default string to environment. */
3088 env = getenv (evarname);
3089 if (!env)
3090 env = defenv;
3091 else
3092 env = concat (env, defenv, "");
3094 /* Allocate a token table */
3095 for (size = 1, p = env; p;)
3096 if ((p = etags_strchr (p, ':')) && *(++p))
3097 size++;
3098 /* Add 1 to leave room for null terminator. */
3099 tab = xnew (size + 1, struct TEX_tabent);
3101 /* Unpack environment string into token table. Be careful about */
3102 /* zero-length strings (leading ':', "::" and trailing ':') */
3103 for (i = 0; *env;)
3105 p = etags_strchr (env, ':');
3106 if (!p) /* End of environment string. */
3107 p = env + strlen (env);
3108 if (p - env > 0)
3109 { /* Only non-zero strings. */
3110 tab[i].name = savenstr (env, p - env);
3111 tab[i].len = strlen (tab[i].name);
3112 i++;
3114 if (*p)
3115 env = p + 1;
3116 else
3118 tab[i].name = NULL; /* Mark end of table. */
3119 tab[i].len = 0;
3120 break;
3123 return tab;
3126 #if TeX_named_tokens
3127 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
3128 The name being defined actually starts at (NAME + LEN + 1).
3129 But we seem to include the TeX command in the tag name. */
3130 void
3131 TEX_getit (name, len)
3132 char *name;
3133 int len;
3135 char *p = name + len;
3137 if (*name == '\0')
3138 return;
3140 /* Let tag name extend to next group close (or end of line) */
3141 while (*p && *p != TEX_clgrp)
3142 p++;
3143 pfnote (savenstr (name, p-name), TRUE,
3144 lb.buffer, strlen (lb.buffer), lineno, linecharno);
3146 #endif
3148 /* If the text at CP matches one of the tag-defining TeX command names,
3149 return the pointer to the first occurrence of that command in TEX_toktab.
3150 Otherwise return -1.
3151 Keep the capital `T' in `Token' for dumb truncating compilers
3152 (this distinguishes it from `TEX_toktab' */
3154 TEX_Token (cp)
3155 char *cp;
3157 int i;
3159 for (i = 0; TEX_toktab[i].len > 0; i++)
3160 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
3161 return i;
3162 return -1;
3165 /* Support for Prolog. */
3167 /* Whole head (not only functor, but also arguments)
3168 is gotten in compound term. */
3169 void
3170 prolog_getit (s)
3171 char *s;
3173 char *save_s;
3174 int insquote, npar;
3176 save_s = s;
3177 insquote = FALSE;
3178 npar = 0;
3179 while (1)
3181 if (s[0] == '\0') /* syntax error. */
3182 return;
3183 else if (insquote && s[0] == '\'' && s[1] == '\'')
3184 s += 2;
3185 else if (s[0] == '\'')
3187 insquote = !insquote;
3188 s++;
3190 else if (!insquote && s[0] == '(')
3192 npar++;
3193 s++;
3195 else if (!insquote && s[0] == ')')
3197 npar--;
3198 s++;
3199 if (npar == 0)
3200 break;
3201 else if (npar < 0) /* syntax error. */
3202 return;
3204 else if (!insquote && s[0] == '.'
3205 && (isspace (s[1]) || s[1] == '\0'))
3206 { /* fullstop. */
3207 if (npar != 0) /* syntax error. */
3208 return;
3209 s++;
3210 break;
3212 else
3213 s++;
3215 pfnote (NULL, TRUE, save_s, s-save_s, lineno, linecharno);
3218 /* It is assumed that prolog predicate starts from column 0. */
3219 void
3220 Prolog_functions (inf)
3221 FILE *inf;
3223 void skip_comment (), prolog_getit ();
3225 lineno = linecharno = charno = 0;
3226 while (!feof (inf))
3228 lineno++;
3229 linecharno += charno;
3230 charno = readline (&lb, inf) + 1; /* 1 for newline. */
3231 dbp = lb.buffer;
3232 if (isspace (dbp[0])) /* not predicate header. */
3233 continue;
3234 else if (dbp[0] == '%') /* comment. */
3235 continue;
3236 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
3237 skip_comment (&lb, inf, &lineno, &linecharno);
3238 else /* found. */
3239 prolog_getit (dbp);
3243 void
3244 skip_comment (plb, inf, plineno, plinecharno)
3245 struct linebuffer *plb;
3246 FILE *inf;
3247 int *plineno; /* result */
3248 long *plinecharno; /* result */
3250 char *cp;
3254 for (cp = plb->buffer; *cp != '\0'; cp++)
3255 if (cp[0] == '*' && cp[1] == '/')
3256 return;
3257 (*plineno)++;
3258 *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
3260 while (!feof(inf));
3263 #ifdef ETAGS_REGEXPS
3264 /* Take a string like "/blah/" and turn it into "blah", making sure
3265 that the first and last characters are the same, and handling
3266 quoted separator characters. Actually, stops on the occurence of
3267 an unquoted separator. Also turns "\t" into a Tab character.
3268 Returns pointer to terminating separator. Works in place. Null
3269 terminates name string. */
3270 char *
3271 scan_separators (name)
3272 char *name;
3274 char sep = name[0];
3275 char *copyto = name;
3276 logical quoted = FALSE;
3278 for (++name; *name != '\0'; ++name)
3280 if (quoted)
3282 if (*name == 't')
3283 *copyto++ = '\t';
3284 else if (*name == sep)
3285 *copyto++ = sep;
3286 else
3288 /* Something else is quoted, so preserve the quote. */
3289 *copyto++ = '\\';
3290 *copyto++ = *name;
3292 quoted = FALSE;
3294 else if (*name == '\\')
3295 quoted = TRUE;
3296 else if (*name == sep)
3297 break;
3298 else
3299 *copyto++ = *name;
3302 /* Terminate copied string. */
3303 *copyto = '\0';
3304 return name;
3307 /* Turn a name, which is an ed-style (but Emacs syntax) regular
3308 expression, into a real regular expression by compiling it. */
3309 void
3310 add_regex (regexp_pattern)
3311 char *regexp_pattern;
3313 char *name;
3314 const char *err;
3315 struct re_pattern_buffer *patbuf;
3317 if (regexp_pattern == NULL)
3319 /* Remove existing regexps. */
3320 num_patterns = 0;
3321 patterns = NULL;
3322 return;
3325 if (regexp_pattern[0] == '\0')
3327 error ("missing regexp", 0);
3328 return;
3330 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
3332 error ("%s: unterminated regexp", regexp_pattern);
3333 return;
3335 name = scan_separators (regexp_pattern);
3336 if (regexp_pattern[0] == '\0')
3338 error ("null regexp", 0);
3339 return;
3341 (void) scan_separators (name);
3343 patbuf = xnew (1, struct re_pattern_buffer);
3344 patbuf->translate = NULL;
3345 patbuf->fastmap = NULL;
3346 patbuf->buffer = NULL;
3347 patbuf->allocated = 0;
3349 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
3350 if (err != NULL)
3352 error ("%s while compiling pattern", err);
3353 return;
3356 num_patterns += 1;
3357 if (num_patterns == 1)
3358 patterns = xnew (1, struct pattern);
3359 else
3360 patterns = ((struct pattern *)
3361 xrealloc (patterns,
3362 (num_patterns * sizeof (struct pattern))));
3363 patterns[num_patterns - 1].pattern = patbuf;
3364 patterns[num_patterns - 1].name_pattern = savestr (name);
3365 patterns[num_patterns - 1].error_signaled = FALSE;
3369 * Do the subtitutions indicated by the regular expression and
3370 * arguments.
3372 char *
3373 substitute (in, out, regs)
3374 char *in, *out;
3375 struct re_registers *regs;
3377 char *result = NULL, *t;
3378 int size = 0;
3380 /* Pass 1: figure out how much size to allocate. */
3381 for (t = out; *t; ++t)
3383 if (*t == '\\')
3385 ++t;
3386 if (!*t)
3388 fprintf (stderr, "%s: pattern subtitution ends prematurely\n",
3389 progname);
3390 return NULL;
3392 if (isdigit (*t))
3394 int dig = *t - '0';
3395 size += regs->end[dig] - regs->start[dig];
3400 /* Allocate space and do the substitutions. */
3401 result = xnew (size + 1, char);
3402 size = 0;
3403 for (; *out; ++out)
3405 if (*out == '\\')
3407 ++out;
3408 if (isdigit (*out))
3410 /* Using "dig2" satisfies my debugger. Bleah. */
3411 int dig2 = *out - '0';
3412 strncpy (result + size, in + regs->start[dig2],
3413 regs->end[dig2] - regs->start[dig2]);
3414 size += regs->end[dig2] - regs->start[dig2];
3416 else
3418 switch (*out)
3420 case '\t':
3421 result[size++] = '\t';
3422 break;
3423 case '\\':
3424 *out = '\\';
3425 break;
3426 default:
3427 result[size++] = *out;
3428 break;
3432 else
3433 result[size++] = *out;
3435 result[size] = '\0';
3437 return result;
3440 #endif /* ETAGS_REGEXPS */
3441 /* Initialize a linebuffer for use */
3442 void
3443 initbuffer (linebuffer)
3444 struct linebuffer *linebuffer;
3446 linebuffer->size = 200;
3447 linebuffer->buffer = xnew (200, char);
3451 * Read a line of text from `stream' into `linebuffer'.
3452 * Return the number of characters read from `stream',
3453 * which is the length of the line including the newline, if any.
3455 long
3456 readline_internal (linebuffer, stream)
3457 struct linebuffer *linebuffer;
3458 register FILE *stream;
3460 char *buffer = linebuffer->buffer;
3461 register char *p = linebuffer->buffer;
3462 register char *pend;
3463 int chars_deleted;
3465 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
3467 while (1)
3469 register int c = getc (stream);
3470 if (p == pend)
3472 linebuffer->size *= 2;
3473 buffer = (char *) xrealloc (buffer, linebuffer->size);
3474 p += buffer - linebuffer->buffer;
3475 pend = buffer + linebuffer->size;
3476 linebuffer->buffer = buffer;
3478 if (c == EOF)
3480 chars_deleted = 0;
3481 break;
3483 if (c == '\n')
3485 if (p > buffer && p[-1] == '\r')
3487 *--p = '\0';
3488 chars_deleted = 2;
3490 else
3492 *p = '\0';
3493 chars_deleted = 1;
3495 break;
3497 *p++ = c;
3500 return p - buffer + chars_deleted;
3504 * Like readline_internal, above, but try to match the input
3505 * line against any existing regular expressions.
3507 long
3508 readline (linebuffer, stream)
3509 struct linebuffer *linebuffer;
3510 FILE *stream;
3512 /* Read new line. */
3513 int i;
3514 long result = readline_internal (linebuffer, stream);
3516 #ifdef ETAGS_REGEXPS
3517 /* Match against all listed patterns. */
3518 for (i = 0; i < num_patterns; ++i)
3520 int match = re_match (patterns[i].pattern, linebuffer->buffer,
3521 (int)result, 0, &patterns[i].regs);
3522 switch (match)
3524 case -2:
3525 /* Some error. */
3526 if (!patterns[i].error_signaled)
3528 error ("error while matching pattern %d", i);
3529 patterns[i].error_signaled = TRUE;
3531 break;
3532 case -1:
3533 /* No match. */
3534 break;
3535 default:
3536 /* Match occurred. Construct a tag. */
3537 if (patterns[i].name_pattern[0] != '\0')
3539 /* Make a named tag. */
3540 char *name = substitute (linebuffer->buffer,
3541 patterns[i].name_pattern,
3542 &patterns[i].regs);
3543 if (name != NULL)
3544 pfnote (name, TRUE,
3545 linebuffer->buffer, match, lineno, linecharno);
3547 else
3549 /* Make an unnamed tag. */
3550 pfnote (NULL, TRUE,
3551 linebuffer->buffer, match, lineno, linecharno);
3553 break;
3556 #endif /* ETAGS_REGEXPS */
3558 return result;
3562 * Read a file, but do no processing. This is used to do regexp
3563 * matching on files that have no language defined.
3565 void
3566 just_read_file (inf)
3567 FILE *inf;
3569 while (!feof (inf))
3571 ++lineno;
3572 linecharno = charno;
3573 charno += readline (&lb, inf) + 1;
3579 * Return a pointer to a space of size strlen(cp)+1 allocated
3580 * with xnew where the string CP has been copied.
3582 char *
3583 savestr (cp)
3584 char *cp;
3586 return savenstr (cp, strlen (cp));
3590 * Return a pointer to a space of size LEN+1 allocated with xnew where
3591 * the string CP has been copied for at most the first LEN characters.
3593 char *
3594 savenstr (cp, len)
3595 char *cp;
3596 int len;
3598 register char *dp;
3600 dp = xnew (len + 1, char);
3601 strncpy (dp, cp, len);
3602 dp[len] = '\0';
3603 return dp;
3607 * Return the ptr in sp at which the character c last
3608 * appears; NULL if not found
3610 * Identical to System V strrchr, included for portability.
3612 char *
3613 etags_strrchr (sp, c)
3614 register char *sp, c;
3616 register char *r;
3618 r = NULL;
3621 if (*sp == c)
3622 r = sp;
3623 } while (*sp++);
3624 return r;
3629 * Return the ptr in sp at which the character c first
3630 * appears; NULL if not found
3632 * Identical to System V strchr, included for portability.
3634 char *
3635 etags_strchr (sp, c)
3636 register char *sp, c;
3640 if (*sp == c)
3641 return sp;
3642 } while (*sp++);
3643 return NULL;
3646 /* Print error message and exit. */
3647 void
3648 fatal (s1, s2)
3649 char *s1, *s2;
3651 error (s1, s2);
3652 exit (BAD);
3655 void
3656 pfatal (s1)
3657 char *s1;
3659 perror (s1);
3660 exit (BAD);
3663 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3664 void
3665 error (s1, s2)
3666 char *s1, *s2;
3668 fprintf (stderr, "%s: ", progname);
3669 fprintf (stderr, s1, s2);
3670 fprintf (stderr, "\n");
3673 /* Return a newly-allocated string whose contents
3674 concatenate those of s1, s2, s3. */
3675 char *
3676 concat (s1, s2, s3)
3677 char *s1, *s2, *s3;
3679 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3680 char *result = xnew (len1 + len2 + len3 + 1, char);
3682 strcpy (result, s1);
3683 strcpy (result + len1, s2);
3684 strcpy (result + len1 + len2, s3);
3685 result[len1 + len2 + len3] = '\0';
3687 return result;
3690 /* Does the same work as the system V getcwd, but does not need to
3691 guess buffer size in advance. */
3692 char *
3693 etags_getcwd ()
3695 #ifdef DOS_NT
3696 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3698 getwd (path);
3699 p = path;
3700 while (*p)
3701 if (*p == '\\')
3702 *p++ = '/';
3703 else
3704 *p++ = tolower (*p);
3706 return strdup (path);
3707 #else /* not DOS_NT */
3708 #if HAVE_GETCWD
3709 int bufsize = 200;
3710 char *path = xnew (bufsize, char);
3712 while (getcwd (path, bufsize) == NULL)
3714 if (errno != ERANGE)
3715 pfatal ("getcwd");
3716 bufsize *= 2;
3717 path = xnew (bufsize, char);
3720 return path;
3721 #else /* not DOS_NT and not HAVE_GETCWD */
3722 struct linebuffer path;
3723 FILE *pipe;
3725 initbuffer (&path);
3726 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
3727 if (pipe == NULL || readline_internal (&path, pipe) == 0)
3728 pfatal ("pwd");
3729 pclose (pipe);
3731 return path.buffer;
3732 #endif /* not HAVE_GETCWD */
3733 #endif /* not DOS_NT */
3736 /* Return a newly allocated string containing the filename
3737 of FILE relative to the absolute directory DIR (which
3738 should end with a slash). */
3739 char *
3740 relative_filename (file, dir)
3741 char *file, *dir;
3743 char *fp, *dp, *abs, *res;
3745 /* Find the common root of file and dir. */
3746 abs = absolute_filename (file, cwd);
3747 fp = abs;
3748 dp = dir;
3749 while (*fp++ == *dp++)
3750 continue;
3753 fp--;
3754 dp--;
3756 while (*fp != '/');
3758 /* Build a sequence of "../" strings for the resulting relative filename. */
3759 for (dp = etags_strchr (dp + 1, '/'), res = "";
3760 dp != NULL;
3761 dp = etags_strchr (dp + 1, '/'))
3763 res = concat (res, "../", "");
3766 /* Add the filename relative to the common root of file and dir. */
3767 res = concat (res, fp + 1, "");
3768 free (abs);
3770 return res;
3773 /* Return a newly allocated string containing the
3774 absolute filename of FILE given CWD (which should
3775 end with a slash). */
3776 char *
3777 absolute_filename (file, cwd)
3778 char *file, *cwd;
3780 char *slashp, *cp, *res;
3782 if (absolutefn (file))
3783 res = concat (file, "", "");
3784 else
3785 res = concat (cwd, file, "");
3787 /* Delete the "/dirname/.." and "/." substrings. */
3788 slashp = etags_strchr (res, '/');
3789 while (slashp != NULL && slashp[0] != '\0')
3791 if (slashp[1] == '.')
3793 if (slashp[2] == '.'
3794 && (slashp[3] == '/' || slashp[3] == '\0'))
3796 cp = slashp;
3798 cp--;
3799 while (cp >= res && *cp != '/');
3800 if (*cp == '/')
3802 strcpy (cp, slashp + 3);
3804 else /* else (cp == res) */
3806 if (slashp[3] != '\0')
3807 strcpy (cp, slashp + 4);
3808 else
3809 return ".";
3811 slashp = cp;
3812 continue;
3814 else if (slashp[2] == '/' || slashp[2] == '\0')
3816 strcpy (slashp, slashp + 2);
3817 continue;
3821 slashp = etags_strchr (slashp + 1, '/');
3824 return res;
3827 /* Return a newly allocated string containing the absolute
3828 filename of dir where FILE resides given CWD (which should
3829 end with a slash). */
3830 char *
3831 absolute_dirname (file, cwd)
3832 char *file, *cwd;
3834 char *slashp, *res;
3835 char save;
3837 slashp = etags_strrchr (file, '/');
3838 if (slashp == NULL)
3839 return cwd;
3840 save = slashp[1];
3841 slashp[1] = '\0';
3842 res = absolute_filename (file, cwd);
3843 slashp[1] = save;
3845 return res;
3848 /* Like malloc but get fatal error if memory is exhausted. */
3849 long *
3850 xmalloc (size)
3851 unsigned int size;
3853 long *result = (long *) malloc (size);
3854 if (result == NULL)
3855 fatal ("virtual memory exhausted", 0);
3856 return result;
3859 long *
3860 xrealloc (ptr, size)
3861 char *ptr;
3862 unsigned int size;
3864 long *result = (long *) realloc (ptr, size);
3865 if (result == NULL)
3866 fatal ("virtual memory exhausted");
3867 return result;