(tcl-do-fill-paragraph): New function.
[emacs.git] / lib-src / etags.c
blob92a07c675bd3a4d1ab9822d79b677b9a5bf35480
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 named; /* list name separately */
137 logical been_warned; /* set if noticed dup */
138 int lno; /* line number tag is on */
139 long cno; /* character number line starts on */
140 char *pat; /* search pattern */
141 struct nd_st *left, *right; /* left and right sons */
142 } NODE;
144 extern char *getenv ();
146 char *concat ();
147 char *savenstr (), *savestr ();
148 char *etags_strchr (), *etags_strrchr ();
149 char *etags_getcwd ();
150 char *relative_filename (), *absolute_filename (), *absolute_dirname ();
151 long *xmalloc (), *xrealloc ();
153 typedef void Lang_function ();
154 #if FALSE /* many compilers barf on this */
155 Lang_function Asm_labels;
156 Lang_function default_C_entries;
157 Lang_function C_entries;
158 Lang_function Cplusplus_entries;
159 Lang_function Cstar_entries;
160 Lang_function Fortran_functions;
161 Lang_function Yacc_entries;
162 Lang_function Lisp_functions;
163 Lang_function Pascal_functions;
164 Lang_function Prolog_functions;
165 Lang_function Scheme_functions;
166 Lang_function TeX_functions;
167 Lang_function just_read_file;
168 #else /* so let's write it this way */
169 void Asm_labels ();
170 void C_entries ();
171 void default_C_entries ();
172 void plain_C_entries ();
173 void Cplusplus_entries ();
174 void Cstar_entries ();
175 void Fortran_functions ();
176 void Yacc_entries ();
177 void Lisp_functions ();
178 void Pascal_functions ();
179 void Prolog_functions ();
180 void Scheme_functions ();
181 void TeX_functions ();
182 void just_read_file ();
183 #endif
185 logical get_language ();
186 int total_size_of_entries ();
187 long readline ();
188 long readline_internal ();
189 #ifdef ETAGS_REGEXPS
190 void add_regex ();
191 #endif
192 void add_node ();
193 void error ();
194 void fatal (), pfatal ();
195 void find_entries ();
196 void free_tree ();
197 void getit ();
198 void init ();
199 void initbuffer ();
200 void pfnote ();
201 void process_file ();
202 void put_entries ();
203 void takeprec ();
206 char searchar = '/'; /* use /.../ searches */
208 int lineno; /* line number of current line */
209 long charno; /* current character number */
211 long linecharno; /* charno of start of line; not used by C,
212 but by every other language. */
214 char *curfile; /* current input file name */
215 char *tagfile; /* output file */
216 char *progname; /* name this program was invoked with */
217 char *cwd; /* current working directory */
218 char *tagfiledir; /* directory of tagfile */
220 FILE *tagf; /* ioptr for tags file */
221 NODE *head; /* the head of the binary tree of tags */
224 * A `struct linebuffer' is a structure which holds a line of text.
225 * `readline' reads a line from a stream into a linebuffer and works
226 * regardless of the length of the line.
228 struct linebuffer
230 long size;
231 char *buffer;
234 struct linebuffer lb; /* the current line */
235 struct linebuffer token_name; /* used by C_entries as temporary area */
236 struct
238 long linepos;
239 struct linebuffer lb; /* used by C_entries instead of lb */
240 } lbs[2];
242 /* boolean "functions" (see init) */
243 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
244 char
245 *white = " \f\t\n\013", /* white chars */
246 *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
247 /* token starting chars */
248 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
249 /* valid in-token chars */
250 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
252 logical append_to_tagfile; /* -a: append to tags */
253 /* The following three default to TRUE for etags, but to FALSE for ctags. */
254 logical typedefs; /* -t: create tags for typedefs */
255 logical typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
256 /* 0 struct/enum/union decls, and C++ */
257 /* member functions. */
258 logical constantypedefs; /* -d: create tags for C #define and enum */
259 /* constants. Enum consts not implemented. */
260 /* -D: opposite of -d. Default under ctags. */
261 logical update; /* -u: update tags */
262 logical vgrind_style; /* -v: create vgrind style index output */
263 logical no_warnings; /* -w: suppress warnings */
264 logical cxref_style; /* -x: create cxref style output */
265 logical cplusplus; /* .[hc] means C++, not C */
266 logical noindentypedefs; /* -I: ignore indentation in C */
267 #define permit_duplicates TRUE /* allow duplicate tags */
269 struct option longopts[] =
271 { "append", no_argument, NULL, 'a' },
272 { "backward-search", no_argument, NULL, 'B' },
273 { "c++", no_argument, NULL, 'C' },
274 { "cxref", no_argument, NULL, 'x' },
275 { "defines", no_argument, NULL, 'd' },
276 { "help", no_argument, NULL, 'h' },
277 { "help", no_argument, NULL, 'H' },
278 { "ignore-indentation", no_argument, NULL, 'I' },
279 { "include", required_argument, NULL, 'i' },
280 { "language", required_argument, NULL, 'l' },
281 { "no-defines", no_argument, NULL, 'D' },
282 { "no-regex", no_argument, NULL, 'R' },
283 { "no-warn", no_argument, NULL, 'w' },
284 { "output", required_argument, NULL, 'o' },
285 { "regex", required_argument, NULL, 'r' },
286 { "typedefs", no_argument, NULL, 't' },
287 { "typedefs-and-c++", no_argument, NULL, 'T' },
288 { "update", no_argument, NULL, 'u' },
289 { "version", no_argument, NULL, 'V' },
290 { "vgrind", no_argument, NULL, 'v' },
291 { 0 }
294 #ifdef ETAGS_REGEXPS
295 /* Structure defining a regular expression. Elements are
296 the compiled pattern, and the name string. */
297 struct pattern
299 struct re_pattern_buffer *pattern;
300 struct re_registers regs;
301 char *name_pattern;
302 logical error_signaled;
305 /* Number of regexps found. */
306 int num_patterns = 0;
308 /* Array of all regexps. */
309 struct pattern *patterns = NULL;
310 #endif /* ETAGS_REGEXPS */
312 /* Language stuff. */
313 struct lang_entry
315 char *suffix;
316 Lang_function *function;
319 /* Table of language names and corresponding functions. */
320 /* It is ok for a given function to be listed under more than one
321 name. I just didn't. */
322 /* "auto" language reverts to default behavior. */
323 struct lang_entry lang_names[] =
325 { "asm", Asm_labels },
326 { "c", default_C_entries },
327 { "c++", Cplusplus_entries },
328 { "c*", Cstar_entries },
329 { "fortran", Fortran_functions },
330 { "lisp", Lisp_functions },
331 { "none", just_read_file },
332 { "pascal", Pascal_functions },
333 { "scheme" , Scheme_functions },
334 { "tex", TeX_functions },
335 { "auto", NULL },
336 { NULL, NULL }
339 /* Table of file name suffixes and corresponding language functions. */
340 struct lang_entry lang_suffixes[] =
342 /* Assume that ".s" or ".a" is assembly code. -wolfgang.
343 Or even ".sa". */
344 { "a", Asm_labels }, /* Unix assembler */
345 { "asm", Asm_labels }, /* Microcontroller assembly */
346 { "def", Asm_labels }, /* BSO/Tasking definition includes */
347 { "inc", Asm_labels }, /* Microcontroller include files */
348 { "ins", Asm_labels }, /* Microcontroller include files */
349 { "s", Asm_labels },
350 { "sa", Asm_labels }, /* Unix assembler */
351 { "src", Asm_labels }, /* BSO/Tasking C compiler output */
353 /* .aux, .bbl, .clo, .cls, .dtx or .tex implies LaTeX source code. */
354 { "aux", TeX_functions },
355 { "bbl", TeX_functions },
356 { "clo", TeX_functions },
357 { "cls", TeX_functions },
358 { "dtx", TeX_functions },
359 { "sty", TeX_functions },
360 { "tex", TeX_functions },
362 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
363 { "cl", Lisp_functions },
364 { "clisp", Lisp_functions },
365 { "el", Lisp_functions },
366 { "l", Lisp_functions },
367 { "lisp", Lisp_functions },
368 { "lsp", Lisp_functions },
370 /* .scm or .sm or .scheme implies scheme source code */
371 { "SCM", Scheme_functions },
372 { "SM", Scheme_functions },
373 { "oak", Scheme_functions },
374 { "sch", Scheme_functions },
375 { "scheme", Scheme_functions },
376 { "scm", Scheme_functions },
377 { "sm", Scheme_functions },
378 { "t", Scheme_functions },
379 /* FIXME Can't do the `SCM' or `scm' prefix with a version number */
381 /* Note that .c and .h can be considered C++, if the --c++ flag was
382 given. That is why default_C_entries is called here. */
383 { "c", default_C_entries },
384 { "h", default_C_entries },
386 /* .pc is a Pro*C file. */
387 { "pc", plain_C_entries },
389 /* .C or .H or .c++ or .cc or .cpp or .cxx or .h++ or .hh or .hxx:
390 a C++ file */
391 { "C", Cplusplus_entries },
392 { "H", Cplusplus_entries },
393 { "c++", Cplusplus_entries },
394 { "cc", Cplusplus_entries },
395 { "cpp", Cplusplus_entries },
396 { "cxx", Cplusplus_entries },
397 { "h++", Cplusplus_entries },
398 { "hh", Cplusplus_entries },
399 { "hxx", Cplusplus_entries },
401 /* .y: a yacc file */
402 { "y", Yacc_entries },
404 /* .cs or .hs: a C* file */
405 { "cs", Cstar_entries },
406 { "hs", Cstar_entries },
408 /* .F, .f and .for are FORTRAN. */
409 { "F", Fortran_functions },
410 { "f", Fortran_functions },
411 { "for", Fortran_functions },
413 /* .pl implies prolog source code */
414 { "pl", Prolog_functions },
416 /* .p or .pas: a Pascal file */
417 { "p", Pascal_functions },
418 { "pas", Pascal_functions },
420 { NULL, NULL }
423 /* Non-NULL if language fixed. */
424 Lang_function *lang_func = NULL;
427 void
428 print_language_names ()
430 struct lang_entry *name, *ext;
432 puts ("\nThese are the currently supported languages, along with the\n\
433 default file name suffixes:");
434 for (name = lang_names; name->suffix; ++name)
436 printf ("\t%s\t", name->suffix);
437 for (ext = lang_suffixes; ext->suffix; ++ext)
438 if (name->function == ext->function)
439 printf (" .%s", ext->suffix);
440 puts ("");
442 puts ("Where `auto' means use default language for files based on file\n\
443 name suffix, and `none' means only do regexp processing on files.\n\
444 If no language is specified and no matching suffix is found,\n\
445 Fortran is tried first; if no tags are found, C is tried next.");
448 void
449 print_version ()
451 #ifdef VERSION
452 printf ("%s for Emacs version %s.\n", (CTAGS) ? "CTAGS" : "ETAGS", VERSION);
453 #else
454 printf ("%s for Emacs version 19.\n", (CTAGS) ? "CTAGS" : "ETAGS");
455 #endif
457 exit (GOOD);
460 void
461 print_help ()
463 printf ("These are the options accepted by %s. You may use unambiguous\n\
464 abbreviations for the long option names. A - as file name means read\n\
465 names from stdin.\n\n", progname);
467 puts ("-a, --append\n\
468 Append tag entries to existing tags file.");
470 if (CTAGS)
471 puts ("-B, --backward-search\n\
472 Write the search commands for the tag entries using '?', the\n\
473 backward-search command instead of '/', the forward-search command.");
475 puts ("-C, --c++\n\
476 Treat files whose name suffix defaults to C language as C++ files.");
478 if (CTAGS)
479 puts ("-d, --defines\n\
480 Create tag entries for constant C #defines, too.");
481 else
482 puts ("-D, --no-defines\n\
483 Don't create tag entries for constant C #defines. This makes\n\
484 the tags file smaller.");
486 if (!CTAGS)
488 puts ("-i FILE, --include=FILE\n\
489 Include a note in tag file indicating that, when searching for\n\
490 a tag, one should also consult the tags file FILE after\n\
491 checking the current file.");
492 puts ("-l LANG, --language=LANG\n\
493 Force the following files to be considered as written in the\n\
494 named language up to the next --language=LANG option.");
497 #ifdef ETAGS_REGEXPS
498 puts ("-r /REGEXP/, --regex=/REGEXP/\n\
499 Make a tag for each line matching pattern REGEXP in the\n\
500 following files. REGEXP is anchored (as if preceded by ^).\n\
501 The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
502 named tags can be created with:\n\
503 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
504 puts ("-R, --no-regex\n\
505 Don't create tags from regexps for the following files.");
506 #endif /* ETAGS_REGEXPS */
507 puts ("-o FILE, --output=FILE\n\
508 Write the tags to FILE.");
509 puts ("-I, --ignore-indentation\n\
510 Don't rely on indentation quite as much as normal. Currently,\n\
511 this means not to assume that a closing brace in the first\n\
512 column is the final brace of a function or structure\n\
513 definition in C and C++.");
515 if (CTAGS)
517 puts ("-t, --typedefs\n\
518 Generate tag entries for C typedefs.");
519 puts ("-T, --typedefs-and-c++\n\
520 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
521 and C++ member functions.");
522 puts ("-u, --update\n\
523 Update the tag entries for the given files, leaving tag\n\
524 entries for other files in place. Currently, this is\n\
525 implemented by deleting the existing entries for the given\n\
526 files and then rewriting the new entries at the end of the\n\
527 tags file. It is often faster to simply rebuild the entire\n\
528 tag file than to use this.");
529 puts ("-v, --vgrind\n\
530 Generates an index of items intended for human consumption,\n\
531 similar to the output of vgrind. The index is sorted, and\n\
532 gives the page number of each item.");
533 puts ("-w, --no-warn\n\
534 Suppress warning messages about entries defined in multiple\n\
535 files.");
536 puts ("-x, --cxref\n\
537 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
538 The output uses line numbers instead of page numbers, but\n\
539 beyond that the differences are cosmetic; try both to see\n\
540 which you like.");
543 puts ("-V, --version\n\
544 Print the version of the program.\n\
545 -h, --help\n\
546 Print this help message.");
548 print_language_names ();
550 exit (GOOD);
554 enum argument_type
556 at_language,
557 at_regexp,
558 at_filename
561 /* This structure helps us allow mixing of --lang and filenames. */
562 typedef struct
564 enum argument_type arg_type;
565 char *what;
566 Lang_function *function;
567 } ARGUMENT;
569 #ifdef VMS /* VMS specific functions */
571 #define EOS '\0'
573 /* This is a BUG! ANY arbitrary limit is a BUG!
574 Won't someone please fix this? */
575 #define MAX_FILE_SPEC_LEN 255
576 typedef struct {
577 short curlen;
578 char body[MAX_FILE_SPEC_LEN + 1];
579 } vspec;
582 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
583 returning in each successive call the next filename matching the input
584 spec. The function expects that each in_spec passed
585 to it will be processed to completion; in particular, up to and
586 including the call following that in which the last matching name
587 is returned, the function ignores the value of in_spec, and will
588 only start processing a new spec with the following call.
589 If an error occurs, on return out_spec contains the value
590 of in_spec when the error occurred.
592 With each successive filename returned in out_spec, the
593 function's return value is one. When there are no more matching
594 names the function returns zero. If on the first call no file
595 matches in_spec, or there is any other error, -1 is returned.
598 #include <rmsdef.h>
599 #include <descrip.h>
600 #define OUTSIZE MAX_FILE_SPEC_LEN
601 short
602 fn_exp (out, in)
603 vspec *out;
604 char *in;
606 static long context = 0;
607 static struct dsc$descriptor_s o;
608 static struct dsc$descriptor_s i;
609 static logical pass1 = TRUE;
610 long status;
611 short retval;
613 if (pass1)
615 pass1 = FALSE;
616 o.dsc$a_pointer = (char *) out;
617 o.dsc$w_length = (short)OUTSIZE;
618 i.dsc$a_pointer = in;
619 i.dsc$w_length = (short)strlen(in);
620 i.dsc$b_dtype = DSC$K_DTYPE_T;
621 i.dsc$b_class = DSC$K_CLASS_S;
622 o.dsc$b_dtype = DSC$K_DTYPE_VT;
623 o.dsc$b_class = DSC$K_CLASS_VS;
625 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
627 out->body[out->curlen] = EOS;
628 return 1;
630 else if (status == RMS$_NMF)
631 retval = 0;
632 else
634 strcpy(out->body, in);
635 retval = -1;
637 lib$find_file_end(&context);
638 pass1 = TRUE;
639 return retval;
643 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
644 name of each file specified by the provided arg expanding wildcards.
646 char *
647 gfnames (arg, p_error)
648 char *arg;
649 logical *p_error;
651 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
653 switch (fn_exp (&filename, arg))
655 case 1:
656 *p_error = FALSE;
657 return filename.body;
658 case 0:
659 *p_error = FALSE;
660 return NULL;
661 default:
662 *p_error = TRUE;
663 return filename.body;
667 #ifndef OLD /* Newer versions of VMS do provide `system'. */
668 system (cmd)
669 char *cmd;
671 fprintf (stderr, "system() function not implemented under VMS\n");
673 #endif
675 #define VERSION_DELIM ';'
676 char *massage_name (s)
677 char *s;
679 char *start = s;
681 for ( ; *s; s++)
682 if (*s == VERSION_DELIM)
684 *s = EOS;
685 break;
687 else
688 *s = tolower(*s);
689 return start;
691 #endif /* VMS */
694 void
695 main (argc, argv)
696 int argc;
697 char *argv[];
699 int i;
700 unsigned int nincluded_files = 0;
701 char **included_files = xnew (argc, char *);
702 char *this_file;
703 ARGUMENT *argbuffer;
704 int current_arg = 0, file_count = 0;
705 struct linebuffer filename_lb;
706 #ifdef VMS
707 logical got_err;
708 #endif
710 #ifdef DOS_NT
711 _fmode = O_BINARY; /* all of files are treated as binary files */
712 #endif /* DOS_NT */
714 progname = argv[0];
716 /* Allocate enough no matter what happens. Overkill, but each one
717 is small. */
718 argbuffer = xnew (argc, ARGUMENT);
720 #ifdef ETAGS_REGEXPS
721 /* Set syntax for regular expression routines. */
722 re_set_syntax (RE_SYNTAX_EMACS);
723 #endif /* ETAGS_REGEXPS */
726 * If etags, always find typedefs and structure tags. Why not?
727 * Also default is to find macro constants.
729 if (!CTAGS)
730 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
732 while (1)
734 int opt = getopt_long (argc, argv,
735 "-aCdDf:Il:o:r:RStTi:BuvxwVhH", longopts, 0);
737 if (opt == EOF)
738 break;
740 switch (opt)
742 case 0:
743 /* If getopt returns 0, then it has already processed a
744 long-named option. We should do nothing. */
745 break;
747 case 1:
748 /* This means that a filename has been seen. Record it. */
749 argbuffer[current_arg].arg_type = at_filename;
750 argbuffer[current_arg].what = optarg;
751 ++current_arg;
752 ++file_count;
753 break;
755 /* Common options. */
756 case 'a':
757 append_to_tagfile = TRUE;
758 break;
759 case 'C':
760 cplusplus = TRUE;
761 break;
762 case 'd':
763 constantypedefs = TRUE;
764 break;
765 case 'D':
766 constantypedefs = FALSE;
767 break;
768 case 'f': /* for compatibility with old makefiles */
769 case 'o':
770 if (tagfile)
772 fprintf (stderr, "%s: -%c option may only be given once.\n",
773 progname, opt);
774 goto usage;
776 tagfile = optarg;
777 break;
778 case 'I':
779 case 'S': /* for backward compatibility */
780 noindentypedefs = TRUE;
781 break;
782 case 'l':
783 if (!get_language (optarg, &argbuffer[current_arg].function))
785 fprintf (stderr, "%s: language \"%s\" not recognized.\n",
786 progname, optarg);
787 goto usage;
789 argbuffer[current_arg].arg_type = at_language;
790 ++current_arg;
791 break;
792 #ifdef ETAGS_REGEXPS
793 case 'r':
794 argbuffer[current_arg].arg_type = at_regexp;
795 argbuffer[current_arg].what = optarg;
796 ++current_arg;
797 break;
798 case 'R':
799 argbuffer[current_arg].arg_type = at_regexp;
800 argbuffer[current_arg].what = NULL;
801 ++current_arg;
802 break;
803 #endif /* ETAGS_REGEXPS */
804 case 'V':
805 print_version ();
806 break;
807 case 'h':
808 case 'H':
809 print_help ();
810 break;
811 case 't':
812 typedefs = TRUE;
813 break;
814 case 'T':
815 typedefs = typedefs_and_cplusplus = TRUE;
816 break;
817 #if (!CTAGS)
818 /* Etags options */
819 case 'i':
820 included_files[nincluded_files++] = optarg;
821 break;
822 #else /* CTAGS */
823 /* Ctags options. */
824 case 'B':
825 searchar = '?';
826 break;
827 case 'u':
828 update = TRUE;
829 break;
830 case 'v':
831 vgrind_style = TRUE;
832 /*FALLTHRU*/
833 case 'x':
834 cxref_style = TRUE;
835 break;
836 case 'w':
837 no_warnings = TRUE;
838 break;
839 #endif /* CTAGS */
840 default:
841 goto usage;
845 for (; optind < argc; ++optind)
847 argbuffer[current_arg].arg_type = at_filename;
848 argbuffer[current_arg].what = argv[optind];
849 ++current_arg;
850 ++file_count;
853 if (nincluded_files == 0 && file_count == 0)
855 fprintf (stderr, "%s: No input files specified.\n", progname);
857 usage:
858 fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
859 progname);
860 exit (BAD);
863 if (tagfile == NULL)
865 tagfile = CTAGS ? "tags" : "TAGS";
867 cwd = etags_getcwd (); /* the current working directory */
868 strcat (cwd, "/");
869 if (streq (tagfile, "-"))
871 tagfiledir = cwd;
873 else
875 tagfiledir = absolute_dirname (tagfile, cwd);
878 init (); /* set up boolean "functions" */
880 initbuffer (&lb);
881 initbuffer (&token_name);
882 initbuffer (&lbs[0].lb);
883 initbuffer (&lbs[1].lb);
884 initbuffer (&filename_lb);
886 if (!CTAGS)
888 if (streq (tagfile, "-"))
889 tagf = stdout;
890 else
891 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
892 if (tagf == NULL)
893 pfatal (tagfile);
897 * Loop through files finding functions.
899 for (i = 0; i < current_arg; ++i)
901 switch (argbuffer[i].arg_type)
903 case at_language:
904 lang_func = argbuffer[i].function;
905 break;
906 #ifdef ETAGS_REGEXPS
907 case at_regexp:
908 add_regex (argbuffer[i].what);
909 break;
910 #endif
911 case at_filename:
912 #ifdef VMS
913 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
915 if (got_err)
917 error ("Can't find file %s\n", this_file);
918 argc--, argv++;
920 else
922 this_file = massage_name (this_file);
924 #else
925 this_file = argbuffer[i].what;
926 #endif
927 /* Input file named "-" means read file names from stdin
928 and use them. */
929 if (streq (this_file, "-"))
930 while (readline_internal (&filename_lb, stdin) > 0)
931 process_file (filename_lb.buffer);
932 else
933 process_file (this_file);
934 #ifdef VMS
936 #endif
937 break;
941 if (!CTAGS)
943 while (nincluded_files-- > 0)
944 fprintf (tagf, "\f\n%s,include\n", *included_files++);
946 fclose (tagf);
947 exit (GOOD);
950 /* If CTAGS, we are here. process_file did not write the tags yet,
951 because we want them ordered. Let's do it now. */
952 if (cxref_style)
954 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
955 if (tagf == NULL)
956 pfatal (tagfile);
957 put_entries (head);
958 exit (GOOD);
961 if (update)
963 char cmd[BUFSIZ];
964 for (i = 0; i < current_arg; ++i)
966 if (argbuffer[i].arg_type != at_filename)
967 continue;
968 sprintf (cmd,
969 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
970 tagfile, argbuffer[i].what, tagfile);
971 if (system (cmd) != GOOD)
972 fatal ("failed to execute shell command");
974 append_to_tagfile = TRUE;
977 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
978 if (tagf == NULL)
979 pfatal (tagfile);
980 put_entries (head);
981 fclose (tagf);
983 if (update)
985 char cmd[BUFSIZ];
986 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
987 exit (system (cmd));
989 exit (GOOD);
994 * Set the language, given the name.
996 logical
997 get_language (language, func)
998 char *language;
999 Lang_function **func;
1001 struct lang_entry *lang;
1003 for (lang = lang_names; lang->suffix; ++lang)
1005 if (streq (language, lang->suffix))
1007 *func = lang->function;
1008 return TRUE;
1012 return FALSE;
1017 * This routine is called on each file argument.
1019 void
1020 process_file (file)
1021 char *file;
1023 struct stat stat_buf;
1024 FILE *inf;
1026 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
1028 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
1029 return;
1031 if (streq (file, tagfile) && !streq (tagfile, "-"))
1033 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
1034 return;
1036 inf = fopen (file, "r");
1037 if (inf == NULL)
1039 perror (file);
1040 return;
1043 find_entries (file, inf);
1045 if (!CTAGS)
1047 char *filename;
1049 if (absolutefn (file))
1051 /* file is an absolute filename. Canonicalise it. */
1052 filename = absolute_filename (file, cwd);
1054 else
1056 /* file is a filename relative to cwd. Make it relative
1057 to the directory of the tags file. */
1058 filename = relative_filename (file, tagfiledir);
1060 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1061 free (filename);
1062 put_entries (head);
1063 free_tree (head);
1064 head = NULL;
1069 * This routine sets up the boolean pseudo-functions which work
1070 * by setting boolean flags dependent upon the corresponding character
1071 * Every char which is NOT in that string is not a white char. Therefore,
1072 * all of the array "_wht" is set to FALSE, and then the elements
1073 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1074 * of a char is TRUE if it is the string "white", else FALSE.
1076 void
1077 init ()
1079 register char *sp;
1080 register int i;
1082 for (i = 0; i < 0177; i++)
1083 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
1084 for (sp = white; *sp; sp++)
1085 _wht[*sp] = TRUE;
1086 for (sp = endtk; *sp; sp++)
1087 _etk[*sp] = TRUE;
1088 for (sp = intk; *sp; sp++)
1089 _itk[*sp] = TRUE;
1090 for (sp = begtk; *sp; sp++)
1091 _btk[*sp] = TRUE;
1092 _wht[0] = _wht['\n'];
1093 _etk[0] = _etk['\n'];
1094 _btk[0] = _btk['\n'];
1095 _itk[0] = _itk['\n'];
1099 * This routine opens the specified file and calls the function
1100 * which finds the function and type definitions.
1102 void
1103 find_entries (file, inf)
1104 char *file;
1105 FILE *inf;
1107 char *cp;
1108 struct lang_entry *lang;
1109 NODE *old_last_node;
1110 extern NODE *last_node;
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, named, linestart, linelen, lno, cno)
1153 char *name; /* tag name */
1154 logical is_func; /* tag is a function */
1155 logical named; /* tag different from text of definition */
1156 char *linestart; /* start of the line where tag is */
1157 int linelen; /* length of the line where tag is */
1158 int lno; /* line number */
1159 long cno; /* character number */
1161 register NODE *np = xnew (1, NODE);
1162 register char *fp;
1164 /* If ctags mode, change name "main" to M<thisfilename>. */
1165 if (CTAGS && !cxref_style && streq (name, "main"))
1167 fp = etags_strrchr (curfile, '/');
1168 np->name = concat ("M", fp == 0 ? curfile : fp + 1, "");
1169 fp = etags_strrchr (np->name, '.');
1170 if (fp && fp[1] != '\0' && fp[2] == '\0')
1171 fp[0] = 0;
1172 np->named = TRUE;
1174 else
1176 np->name = name;
1177 np->named = named;
1179 np->been_warned = FALSE;
1180 np->file = curfile;
1181 np->is_func = is_func;
1182 np->lno = lno;
1183 /* Our char numbers are 0-base, because of C language tradition?
1184 ctags compatibility? old versions compatibility? I don't know.
1185 Anyway, since emacs's are 1-base we espect etags.el to take care
1186 of the difference. If we wanted to have 1-based numbers, we would
1187 uncomment the +1 below. */
1188 np->cno = cno /* + 1 */ ;
1189 np->left = np->right = NULL;
1190 np->pat = savenstr (linestart, ((CTAGS && !cxref_style) ? 50 : linelen));
1192 add_node (np, &head);
1196 * free_tree ()
1197 * recurse on left children, iterate on right children.
1199 void
1200 free_tree (node)
1201 register NODE *node;
1203 while (node)
1205 register NODE *node_right = node->right;
1206 free_tree (node->left);
1207 if (node->named)
1208 free (node->name);
1209 free (node->pat);
1210 free ((char *) node);
1211 node = node_right;
1216 * add_node ()
1217 * Adds a node to the tree of nodes. In etags mode, we don't keep
1218 * it sorted; we just keep a linear list. In ctags mode, maintain
1219 * an ordered tree, with no attempt at balancing.
1221 * add_node is the only function allowed to add nodes, so it can
1222 * maintain state.
1224 NODE *last_node = NULL;
1225 void
1226 add_node (node, cur_node_p)
1227 NODE *node, **cur_node_p;
1229 register int dif;
1230 register NODE *cur_node = *cur_node_p;
1232 if (cur_node == NULL)
1234 *cur_node_p = node;
1235 last_node = node;
1236 return;
1239 if (!CTAGS)
1241 /* Etags Mode */
1242 if (last_node == NULL)
1243 fatal ("internal error in add_node", 0);
1244 last_node->right = node;
1245 last_node = node;
1247 else
1249 /* Ctags Mode */
1250 dif = strcmp (node->name, cur_node->name);
1253 * If this tag name matches an existing one, then
1254 * do not add the node, but maybe print a warning.
1256 if (!dif)
1258 if (node->file == cur_node->file)
1260 if (!no_warnings)
1262 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1263 node->file, lineno, node->name);
1264 fprintf (stderr, "Second entry ignored\n");
1266 return;
1268 if (!cur_node->been_warned && !no_warnings)
1270 fprintf (stderr,
1271 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1272 node->file, cur_node->file, node->name);
1274 cur_node->been_warned = TRUE;
1275 return;
1278 /* Maybe refuse to add duplicate nodes. */
1279 if (!permit_duplicates)
1281 if (streq (node->name, cur_node->name)
1282 && streq (node->file, cur_node->file))
1283 return;
1286 /* Actually add the node */
1287 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1291 void
1292 put_entries (node)
1293 register NODE *node;
1295 register char *sp;
1297 if (node == NULL)
1298 return;
1300 /* Output subentries that precede this one */
1301 put_entries (node->left);
1303 /* Output this entry */
1305 if (!CTAGS)
1307 if (node->named)
1309 fprintf (tagf, "%s\177%s\001%d,%d\n",
1310 node->pat, node->name,
1311 node->lno, node->cno);
1313 else
1315 fprintf (tagf, "%s\177%d,%d\n",
1316 node->pat,
1317 node->lno, node->cno);
1320 else if (!cxref_style)
1322 fprintf (tagf, "%s\t%s\t",
1323 node->name, node->file);
1325 if (node->is_func)
1326 { /* a function */
1327 putc (searchar, tagf);
1328 putc ('^', tagf);
1330 for (sp = node->pat; *sp; sp++)
1332 if (*sp == '\\' || *sp == searchar)
1333 putc ('\\', tagf);
1334 putc (*sp, tagf);
1336 putc (searchar, tagf);
1338 else
1339 { /* a typedef; text pattern inadequate */
1340 fprintf (tagf, "%d", node->lno);
1342 putc ('\n', tagf);
1344 else if (vgrind_style)
1345 fprintf (stdout, "%s %s %d\n",
1346 node->name, node->file, (node->lno + 63) / 64);
1347 else
1348 fprintf (stdout, "%-16s %3d %-16s %s\n",
1349 node->name, node->lno, node->file, node->pat);
1351 /* Output subentries that follow this one */
1352 put_entries (node->right);
1355 /* Length of a number's decimal representation. */
1357 number_len (num)
1358 long num;
1360 int len = 0;
1361 if (!num)
1362 return 1;
1363 for (; num; num /= 10)
1364 ++len;
1365 return len;
1369 * Return total number of characters that put_entries will output for
1370 * the nodes in the subtree of the specified node. Works only if
1371 * we are not ctags, but called only in that case. This count
1372 * is irrelevant with the new tags.el, but is still supplied for
1373 * backward compatibility.
1376 total_size_of_entries (node)
1377 register NODE *node;
1379 register int total;
1381 if (node == NULL)
1382 return 0;
1384 total = 0;
1385 for (; node; node = node->right)
1387 /* Count left subentries. */
1388 total += total_size_of_entries (node->left);
1390 /* Count this entry */
1391 total += strlen (node->pat) + 1;
1392 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
1393 if (node->named)
1394 total += 1 + strlen (node->name); /* \001name */
1397 return total;
1401 * The C symbol tables.
1403 enum sym_type
1405 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
1408 /* Feed stuff between (but not including) %[ and %] lines to:
1409 gperf -c -k1,3 -o -p -r -t
1411 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1413 class, C_PLPL, st_C_struct
1414 domain, C_STAR, st_C_struct
1415 union, 0, st_C_struct
1416 struct, 0, st_C_struct
1417 enum, 0, st_C_enum
1418 typedef, 0, st_C_typedef
1419 define, 0, st_C_define
1420 long, 0, st_C_typespec
1421 short, 0, st_C_typespec
1422 int, 0, st_C_typespec
1423 char, 0, st_C_typespec
1424 float, 0, st_C_typespec
1425 double, 0, st_C_typespec
1426 signed, 0, st_C_typespec
1427 unsigned, 0, st_C_typespec
1428 auto, 0, st_C_typespec
1429 void, 0, st_C_typespec
1430 extern, 0, st_C_typespec
1431 static, 0, st_C_typespec
1432 const, 0, st_C_typespec
1433 volatile, 0, st_C_typespec
1435 and replace lines between %< and %> with its output. */
1436 /*%<*/
1437 /* C code produced by gperf version 1.8.1 (K&R C version) */
1438 /* Command-line: gperf -c -k1,3 -o -p -r -t */
1441 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1443 #define MIN_WORD_LENGTH 3
1444 #define MAX_WORD_LENGTH 8
1445 #define MIN_HASH_VALUE 10
1446 #define MAX_HASH_VALUE 62
1448 21 keywords
1449 53 is the maximum key range
1452 static int
1453 hash (str, len)
1454 register char *str;
1455 register int len;
1457 static unsigned char hash_table[] =
1459 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1460 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1461 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1462 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1463 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1464 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1465 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1466 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1467 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
1468 62, 62, 62, 62, 62, 62, 62, 2, 62, 7,
1469 6, 9, 15, 30, 62, 24, 62, 62, 1, 24,
1470 7, 27, 13, 62, 19, 26, 18, 27, 1, 62,
1471 62, 62, 62, 62, 62, 62, 62, 62,
1473 return len + hash_table[str[2]] + hash_table[str[0]];
1476 struct C_stab_entry *
1477 in_word_set (str, len)
1478 register char *str;
1479 register int len;
1482 static struct C_stab_entry wordlist[] =
1484 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1485 {"",},
1486 {"volatile", 0, st_C_typespec},
1487 {"",},
1488 {"long", 0, st_C_typespec},
1489 {"char", 0, st_C_typespec},
1490 {"class", C_PLPL, st_C_struct},
1491 {"",}, {"",}, {"",}, {"",},
1492 {"const", 0, st_C_typespec},
1493 {"",}, {"",}, {"",}, {"",},
1494 {"auto", 0, st_C_typespec},
1495 {"",}, {"",},
1496 {"define", 0, st_C_define},
1497 {"",},
1498 {"void", 0, st_C_typespec},
1499 {"",}, {"",}, {"",},
1500 {"extern", 0, st_C_typespec},
1501 {"static", 0, st_C_typespec},
1502 {"",},
1503 {"domain", C_STAR, st_C_struct},
1504 {"",},
1505 {"typedef", 0, st_C_typedef},
1506 {"double", 0, st_C_typespec},
1507 {"enum", 0, st_C_enum},
1508 {"",}, {"",}, {"",}, {"",},
1509 {"int", 0, st_C_typespec},
1510 {"",},
1511 {"float", 0, st_C_typespec},
1512 {"",}, {"",}, {"",},
1513 {"struct", 0, st_C_struct},
1514 {"",}, {"",}, {"",}, {"",},
1515 {"union", 0, st_C_struct},
1516 {"",},
1517 {"short", 0, st_C_typespec},
1518 {"",}, {"",},
1519 {"unsigned", 0, st_C_typespec},
1520 {"signed", 0, st_C_typespec},
1523 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1525 register int key = hash (str, len);
1527 if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
1529 register char *s = wordlist[key].name;
1531 if (*s == *str && strneq (str + 1, s + 1, len - 1))
1532 return &wordlist[key];
1535 return 0;
1537 /*%>*/
1539 enum sym_type
1540 C_symtype(str, len, c_ext)
1541 char *str;
1542 int len;
1543 int c_ext;
1545 register struct C_stab_entry *se = in_word_set(str, len);
1547 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
1548 return st_none;
1549 return se->type;
1553 * C functions are recognized using a simple finite automaton.
1554 * funcdef is its state variable.
1556 typedef enum
1558 fnone, /* nothing seen */
1559 ftagseen, /* function-like tag seen */
1560 fstartlist, /* just after open parenthesis */
1561 finlist, /* in parameter list */
1562 flistseen, /* after parameter list */
1563 fignore /* before open brace */
1564 } FUNCST;
1565 FUNCST funcdef;
1569 * typedefs are recognized using a simple finite automaton.
1570 * typeddef is its state variable.
1572 typedef enum
1574 tnone, /* nothing seen */
1575 ttypedseen, /* typedef keyword seen */
1576 tinbody, /* inside typedef body */
1577 tend, /* just before typedef tag */
1578 tignore /* junk after typedef tag */
1579 } TYPEDST;
1580 TYPEDST typdef;
1584 * struct-like structures (enum, struct and union) are recognized
1585 * using another simple finite automaton. `structdef' is its state
1586 * variable.
1588 typedef enum
1590 snone, /* nothing seen yet */
1591 skeyseen, /* struct-like keyword seen */
1592 stagseen, /* struct-like tag seen */
1593 scolonseen, /* colon seen after struct-like tag */
1594 sinbody /* in struct body: recognize member func defs*/
1595 } STRUCTST;
1596 STRUCTST structdef;
1599 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1600 * struct tag, and structtype is the type of the preceding struct-like
1601 * keyword.
1603 char *structtag = "<uninited>";
1604 enum sym_type structtype;
1607 * Yet another little state machine to deal with preprocessor lines.
1609 typedef enum
1611 dnone, /* nothing seen */
1612 dsharpseen, /* '#' seen as first char on line */
1613 ddefineseen, /* '#' and 'define' seen */
1614 dignorerest /* ignore rest of line */
1615 } DEFINEST;
1616 DEFINEST definedef;
1619 * Set this to TRUE, and the next token considered is called a function.
1620 * Used only for GNU emacs's function-defining macros.
1622 logical next_token_is_func;
1625 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1627 logical yacc_rules;
1630 * consider_token ()
1631 * checks to see if the current token is at the start of a
1632 * function, or corresponds to a typedef, or is a struct/union/enum
1633 * tag.
1635 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
1636 * C_EXT is which language we are looking at.
1638 * In the future we will need some way to adjust where the end of
1639 * the token is; for instance, implementing the C++ keyword
1640 * `operator' properly will adjust the end of the token to be after
1641 * whatever follows `operator'.
1643 * Globals
1644 * funcdef IN OUT
1645 * structdef IN OUT
1646 * definedef IN OUT
1647 * typdef IN OUT
1648 * next_token_is_func IN OUT
1651 logical
1652 consider_token (str, len, c, c_ext, cblev, is_func)
1653 register char *str; /* IN: token pointer */
1654 register int len; /* IN: token length */
1655 register char c; /* IN: first char after the token */
1656 int c_ext; /* IN: C extensions mask */
1657 int cblev; /* IN: curly brace level */
1658 logical *is_func; /* OUT: function found */
1660 enum sym_type toktype = C_symtype (str, len, c_ext);
1663 * Advance the definedef state machine.
1665 switch (definedef)
1667 case dnone:
1668 /* We're not on a preprocessor line. */
1669 break;
1670 case dsharpseen:
1671 if (toktype == st_C_define)
1673 definedef = ddefineseen;
1675 else
1677 definedef = dignorerest;
1679 return FALSE;
1680 case ddefineseen:
1682 * Make a tag for any macro, unless it is a constant
1683 * and constantypedefs is FALSE.
1685 definedef = dignorerest;
1686 *is_func = (c == '(');
1687 if (!*is_func && !constantypedefs)
1688 return FALSE;
1689 else
1690 return TRUE;
1691 case dignorerest:
1692 return FALSE;
1693 default:
1694 error ("internal error: definedef value.", 0);
1698 * Now typedefs
1700 switch (typdef)
1702 case tnone:
1703 if (toktype == st_C_typedef)
1705 if (typedefs)
1706 typdef = ttypedseen;
1707 funcdef = fnone;
1708 return FALSE;
1710 break;
1711 case ttypedseen:
1712 switch (toktype)
1714 case st_none:
1715 case st_C_typespec:
1716 typdef = tend;
1717 break;
1718 case st_C_struct:
1719 case st_C_enum:
1720 break;
1722 /* Do not return here, so the structdef stuff has a chance. */
1723 break;
1724 case tend:
1725 switch (toktype)
1727 case st_C_typespec:
1728 case st_C_struct:
1729 case st_C_enum:
1730 return FALSE;
1732 return TRUE;
1736 * This structdef business is currently only invoked when cblev==0.
1737 * It should be recursively invoked whatever the curly brace level,
1738 * and a stack of states kept, to allow for definitions of structs
1739 * within structs.
1741 * This structdef business is NOT invoked when we are ctags and the
1742 * file is plain C. This is because a struct tag may have the same
1743 * name as another tag, and this loses with ctags.
1745 * This if statement deals with the typdef state machine as
1746 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1747 * return FALSE. All the other code here is for the structdef
1748 * state machine.
1750 switch (toktype)
1752 case st_C_struct:
1753 case st_C_enum:
1754 if (typdef == ttypedseen
1755 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
1757 structdef = skeyseen;
1758 structtype = toktype;
1760 return FALSE;
1762 if (structdef == skeyseen)
1764 /* Save the tag for struct/union/class, for functions that may be
1765 defined inside. */
1766 if (structtype == st_C_struct)
1767 structtag = savenstr (str, len);
1768 else
1769 structtag = "<enum>";
1770 structdef = stagseen;
1771 return TRUE;
1774 /* Avoid entering funcdef stuff if typdef is going on. */
1775 if (typdef != tnone)
1777 definedef = dnone;
1778 return FALSE;
1781 /* Detect GNU macros. */
1782 if (definedef == dnone)
1783 if (strneq (str, "DEFUN", len) /* Used in emacs */
1784 #if FALSE
1785 These are defined inside C functions, so currently they
1786 are not met anyway.
1787 || strneq (str, "EXFUN", len) /* Used in glibc */
1788 || strneq (str, "DEFVAR_", 7) /* Used in emacs */
1789 #endif
1790 || strneq (str, "SYSCALL", len) /* Used in glibc (mach) */
1791 || strneq (str, "ENTRY", len) /* Used in glibc */
1792 || strneq (str, "PSEUDO", len)) /* Used in glibc */
1795 next_token_is_func = TRUE;
1796 return FALSE;
1798 if (next_token_is_func)
1800 next_token_is_func = FALSE;
1801 funcdef = fignore;
1802 *is_func = TRUE;
1803 return TRUE;
1806 /* A function? */
1807 switch (toktype)
1809 case st_C_typespec:
1810 if (funcdef != finlist && funcdef != fignore)
1811 funcdef = fnone; /* should be useless */
1812 return FALSE;
1813 default:
1814 if (funcdef == fnone)
1816 funcdef = ftagseen;
1817 *is_func = TRUE;
1818 return TRUE;
1822 return FALSE;
1826 * C_entries ()
1827 * This routine finds functions, typedefs, #define's and
1828 * struct/union/enum definitions in C syntax and adds them
1829 * to the list.
1831 typedef struct
1833 logical valid;
1834 char *str;
1835 logical named;
1836 int linelen;
1837 int lineno;
1838 long linepos;
1839 char *buffer;
1840 } TOKEN;
1842 #define current_lb_is_new (newndx == curndx)
1843 #define switch_line_buffers() (curndx = 1 - curndx)
1845 #define curlb (lbs[curndx].lb)
1846 #define othlb (lbs[1-curndx].lb)
1847 #define newlb (lbs[newndx].lb)
1848 #define curlinepos (lbs[curndx].linepos)
1849 #define othlinepos (lbs[1-curndx].linepos)
1850 #define newlinepos (lbs[newndx].linepos)
1852 #define CNL_SAVE_DEFINEDEF \
1853 do { \
1854 curlinepos = charno; \
1855 lineno++; \
1856 charno += readline (&curlb, inf); \
1857 lp = curlb.buffer; \
1858 quotednl = FALSE; \
1859 newndx = curndx; \
1860 } while (0)
1862 #define CNL \
1863 do { \
1864 CNL_SAVE_DEFINEDEF; \
1865 if (savetok.valid) \
1867 tok = savetok; \
1868 savetok.valid = FALSE; \
1870 definedef = dnone; \
1871 } while (0)
1873 #define make_tag(isfun) do \
1875 if (tok.valid) \
1876 pfnote (savestr (token_name.buffer), isfun, tok.named, \
1877 tok.buffer, tok.linelen, tok.lineno, tok.linepos); \
1878 else if (DEBUG) abort (); \
1879 tok.valid = FALSE; \
1880 } while (0)
1882 void
1883 C_entries (c_ext, inf)
1884 int c_ext; /* extension of C */
1885 FILE *inf; /* input file */
1887 register char c; /* latest char read; '\0' for end of line */
1888 register char *lp; /* pointer one beyond the character `c' */
1889 int curndx, newndx; /* indices for current and new lb */
1890 TOKEN tok; /* latest token read */
1891 register int tokoff; /* offset in line of start of current token */
1892 register int toklen; /* length of current token */
1893 int cblev; /* current curly brace level */
1894 int parlev; /* current parenthesis level */
1895 logical incomm, inquote, inchar, quotednl, midtoken;
1896 logical cplpl;
1897 TOKEN savetok; /* token saved during preprocessor handling */
1900 curndx = newndx = 0;
1901 lineno = 0;
1902 charno = 0;
1903 lp = curlb.buffer;
1904 *lp = 0;
1906 definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
1907 next_token_is_func = yacc_rules = FALSE;
1908 midtoken = inquote = inchar = incomm = quotednl = FALSE;
1909 tok.valid = savetok.valid = FALSE;
1910 cblev = 0;
1911 parlev = 0;
1912 cplpl = c_ext & C_PLPL;
1914 while (!feof (inf))
1916 c = *lp++;
1917 if (c == '\\')
1919 /* If we're at the end of the line, the next character is a
1920 '\0'; don't skip it, because it's the thing that tells us
1921 to read the next line. */
1922 if (*lp == '\0')
1924 quotednl = TRUE;
1925 continue;
1927 lp++;
1928 c = ' ';
1930 else if (incomm)
1932 switch (c)
1934 case '*':
1935 if (*lp == '/')
1937 c = *lp++;
1938 incomm = FALSE;
1940 break;
1941 case '\0':
1942 /* Newlines inside comments do not end macro definitions in
1943 traditional cpp. */
1944 CNL_SAVE_DEFINEDEF;
1945 break;
1947 continue;
1949 else if (inquote)
1951 switch (c)
1953 case '"':
1954 inquote = FALSE;
1955 break;
1956 case '\0':
1957 /* Newlines inside strings do not end macro definitions
1958 in traditional cpp, even though compilers don't
1959 usually accept them. */
1960 CNL_SAVE_DEFINEDEF;
1961 break;
1963 continue;
1965 else if (inchar)
1967 switch (c)
1969 case '\0':
1970 /* Hmmm, something went wrong. */
1971 CNL;
1972 /* FALLTHRU */
1973 case '\'':
1974 inchar = FALSE;
1975 break;
1977 continue;
1979 else
1980 switch (c)
1982 case '"':
1983 inquote = TRUE;
1984 if (funcdef != finlist && funcdef != fignore)
1985 funcdef = fnone;
1986 continue;
1987 case '\'':
1988 inchar = TRUE;
1989 if (funcdef != finlist && funcdef != fignore)
1990 funcdef = fnone;
1991 continue;
1992 case '/':
1993 if (*lp == '*')
1995 lp++;
1996 incomm = TRUE;
1997 continue;
1999 else if (cplpl && *lp == '/')
2001 c = 0;
2002 break;
2004 else
2005 break;
2006 case '%':
2007 if ((c_ext & YACC) && *lp == '%')
2009 /* entering or exiting rules section in yacc file */
2010 lp++;
2011 definedef = dnone; funcdef = fnone;
2012 typdef = tnone; structdef = snone;
2013 next_token_is_func = FALSE;
2014 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2015 cblev = 0;
2016 yacc_rules = !yacc_rules;
2017 continue;
2019 else
2020 break;
2021 case '#':
2022 if (definedef == dnone)
2024 char *cp;
2025 logical cpptoken = TRUE;
2027 /* Look back on this line. If all blanks, or nonblanks
2028 followed by an end of comment, this is a preprocessor
2029 token. */
2030 for (cp = newlb.buffer; cp < lp-1; cp++)
2031 if (!iswhite (*cp))
2033 if (*cp == '*' && *(cp+1) == '/')
2035 cp++;
2036 cpptoken = TRUE;
2038 else
2039 cpptoken = FALSE;
2041 if (cpptoken)
2042 definedef = dsharpseen;
2043 } /* if (definedef == dnone) */
2045 continue;
2046 } /* switch (c) */
2049 /* Consider token only if some complicated conditions are satisfied. */
2050 if ((definedef != dnone
2051 || (cblev == 0 && structdef != scolonseen)
2052 || (cblev == 1 && cplpl && structdef == sinbody))
2053 && typdef != tignore
2054 && definedef != dignorerest
2055 && funcdef != finlist)
2057 if (midtoken)
2059 if (endtoken (c))
2061 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
2064 * This handles :: in the middle, but not at the
2065 * beginning of an identifier.
2067 lp += 2;
2068 toklen += 3;
2070 else
2072 logical is_func = FALSE;
2074 if (yacc_rules
2075 || consider_token (newlb.buffer + tokoff, toklen,
2076 c, c_ext, cblev, &is_func))
2078 if (structdef == sinbody
2079 && definedef == dnone
2080 && is_func)
2081 /* function defined in C++ class body */
2083 int strsize = strlen(structtag) + 2 + toklen + 1;
2084 while (token_name.size < strsize)
2086 token_name.size *= 2;
2087 token_name.buffer
2088 = (char *) xrealloc (token_name.buffer,
2089 token_name.size);
2091 strcpy (token_name.buffer, structtag);
2092 strcat (token_name.buffer, "::");
2093 strncat (token_name.buffer,
2094 newlb.buffer+tokoff, toklen);
2095 tok.named = TRUE;
2097 else
2099 while (token_name.size < toklen + 1)
2101 token_name.size *= 2;
2102 token_name.buffer
2103 = (char *) xrealloc (token_name.buffer,
2104 token_name.size);
2106 strncpy (token_name.buffer,
2107 newlb.buffer+tokoff, toklen);
2108 token_name.buffer[toklen] = '\0';
2109 if (structdef == stagseen
2110 || typdef == tend
2111 || (is_func
2112 && definedef == dignorerest)) /* macro */
2113 tok.named = TRUE;
2114 else
2115 tok.named = FALSE;
2117 tok.lineno = lineno;
2118 tok.linelen = tokoff + toklen + 1;
2119 tok.buffer = newlb.buffer;
2120 tok.linepos = newlinepos;
2121 tok.valid = TRUE;
2123 if (definedef == dnone
2124 && (funcdef == ftagseen
2125 || structdef == stagseen
2126 || typdef == tend))
2128 if (current_lb_is_new)
2129 switch_line_buffers ();
2131 else
2132 make_tag (is_func);
2134 midtoken = FALSE;
2136 } /* if (endtoken (c)) */
2137 else if (intoken (c))
2139 toklen++;
2140 continue;
2142 } /* if (midtoken) */
2143 else if (begtoken (c))
2145 switch (definedef)
2147 case dnone:
2148 switch (funcdef)
2150 case fstartlist:
2151 funcdef = finlist;
2152 continue;
2153 case flistseen:
2154 make_tag (TRUE);
2155 funcdef = fignore;
2156 break;
2157 case ftagseen:
2158 funcdef = fnone;
2159 break;
2161 if (structdef == stagseen)
2162 structdef = snone;
2163 break;
2164 case dsharpseen:
2165 savetok = tok;
2167 if (!yacc_rules || lp == newlb.buffer + 1)
2169 tokoff = lp - 1 - newlb.buffer;
2170 toklen = 1;
2171 midtoken = TRUE;
2173 continue;
2174 } /* if (begtoken) */
2175 } /* if must look at token */
2178 /* Detect end of line, colon, comma, semicolon and various braces
2179 after having handled a token.*/
2180 switch (c)
2182 case ':':
2183 if (definedef != dnone)
2184 break;
2185 if (structdef == stagseen)
2186 structdef = scolonseen;
2187 else
2188 switch (funcdef)
2190 case ftagseen:
2191 if (yacc_rules)
2193 make_tag (FALSE);
2194 funcdef = fignore;
2196 break;
2197 case fstartlist:
2198 funcdef = fnone;
2199 break;
2201 break;
2202 case ';':
2203 if (definedef != dnone)
2204 break;
2205 if (cblev == 0)
2206 switch (typdef)
2208 case tend:
2209 make_tag (FALSE);
2210 /* FALLTHRU */
2211 default:
2212 typdef = tnone;
2214 if (funcdef != fignore)
2215 funcdef = fnone;
2216 if (structdef == stagseen)
2217 structdef = snone;
2218 break;
2219 case ',':
2220 if (definedef != dnone)
2221 break;
2222 if (funcdef != finlist && funcdef != fignore)
2223 funcdef = fnone;
2224 if (structdef == stagseen)
2225 structdef = snone;
2226 break;
2227 case '[':
2228 if (definedef != dnone)
2229 break;
2230 if (cblev == 0 && typdef == tend)
2232 typdef = tignore;
2233 make_tag (FALSE);
2234 break;
2236 if (funcdef != finlist && funcdef != fignore)
2237 funcdef = fnone;
2238 if (structdef == stagseen)
2239 structdef = snone;
2240 break;
2241 case '(':
2242 if (definedef != dnone)
2243 break;
2244 switch (funcdef)
2246 case fnone:
2247 switch (typdef)
2249 case ttypedseen:
2250 case tend:
2251 /* Make sure that the next char is not a '*'.
2252 This handles constructs like:
2253 typedef void OperatorFun (int fun); */
2254 if (*lp != '*')
2256 typdef = tignore;
2257 make_tag (FALSE);
2259 break;
2260 } /* switch (typdef) */
2261 break;
2262 case ftagseen:
2263 funcdef = fstartlist;
2264 break;
2265 case flistseen:
2266 funcdef = finlist;
2267 break;
2269 parlev++;
2270 break;
2271 case ')':
2272 if (definedef != dnone)
2273 break;
2274 if (--parlev == 0)
2276 switch (funcdef)
2278 case fstartlist:
2279 case finlist:
2280 funcdef = flistseen;
2281 break;
2283 if (cblev == 0 && typdef == tend)
2285 typdef = tignore;
2286 make_tag (FALSE);
2289 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2290 parlev = 0;
2291 break;
2292 case '{':
2293 if (definedef != dnone)
2294 break;
2295 if (typdef == ttypedseen)
2296 typdef = tinbody;
2297 switch (structdef)
2299 case skeyseen: /* unnamed struct */
2300 structtag = "_anonymous_";
2301 structdef = sinbody;
2302 break;
2303 case stagseen:
2304 case scolonseen: /* named struct */
2305 structdef = sinbody;
2306 make_tag (FALSE);
2307 break;
2309 switch (funcdef)
2311 case flistseen:
2312 make_tag (TRUE);
2313 /* FALLTHRU */
2314 case fignore:
2315 funcdef = fnone;
2316 break;
2317 case fnone:
2318 /* Neutralize `extern "C" {' grot and look inside structs. */
2319 if (cblev == 0 && structdef == snone && typdef == tnone)
2320 cblev = -1;
2322 cblev++;
2323 break;
2324 case '*':
2325 if (definedef != dnone)
2326 break;
2327 if (funcdef == fstartlist)
2328 funcdef = fnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
2329 break;
2330 case '}':
2331 if (definedef != dnone)
2332 break;
2333 if (!noindentypedefs && lp == newlb.buffer + 1)
2335 cblev = 0; /* reset curly brace level if first column */
2336 parlev = 0; /* also reset paren level, just in case... */
2338 else if (cblev > 0)
2339 cblev--;
2340 if (cblev == 0)
2342 if (typdef == tinbody)
2343 typdef = tend;
2344 #if FALSE /* too risky */
2345 if (structdef == sinbody)
2346 free (structtag);
2347 #endif
2349 structdef = snone;
2350 structtag = "<error>";
2352 break;
2353 case '=':
2354 case '#': case '+': case '-': case '~': case '&': case '%': case '/':
2355 case '|': case '^': case '!': case '<': case '>': case '.': case '?':
2356 if (definedef != dnone)
2357 break;
2358 /* These surely cannot follow a function tag. */
2359 if (funcdef != finlist && funcdef != fignore)
2360 funcdef = fnone;
2361 break;
2362 case '\0':
2363 /* If a macro spans multiple lines don't reset its state. */
2364 if (quotednl)
2365 CNL_SAVE_DEFINEDEF;
2366 else
2367 CNL;
2368 break;
2369 } /* switch (c) */
2371 } /* while not eof */
2375 * Process either a C++ file or a C file depending on the setting
2376 * of a global flag.
2378 void
2379 default_C_entries (inf)
2380 FILE *inf;
2382 C_entries (cplusplus ? C_PLPL : 0, inf);
2385 /* Always do plain ANSI C. */
2386 void
2387 plain_C_entries (inf)
2388 FILE *inf;
2390 C_entries (0, inf);
2393 /* Always do C++. */
2394 void
2395 Cplusplus_entries (inf)
2396 FILE *inf;
2398 C_entries (C_PLPL, inf);
2401 /* Always do C*. */
2402 void
2403 Cstar_entries (inf)
2404 FILE *inf;
2406 C_entries (C_STAR, inf);
2409 /* Always do Yacc. */
2410 void
2411 Yacc_entries (inf)
2412 FILE *inf;
2414 C_entries (YACC, inf);
2417 /* Fortran parsing */
2419 char *dbp;
2421 logical
2422 tail (cp)
2423 char *cp;
2425 register int len = 0;
2427 while (*cp && lowcase(*cp) == lowcase(dbp[len]))
2428 cp++, len++;
2429 if (*cp == 0 && !intoken(dbp[len]))
2431 dbp += len;
2432 return TRUE;
2434 return FALSE;
2437 void
2438 takeprec ()
2440 while (isspace (*dbp))
2441 dbp++;
2442 if (*dbp != '*')
2443 return;
2444 dbp++;
2445 while (isspace (*dbp))
2446 dbp++;
2447 if (strneq (dbp, "(*)", 3))
2449 dbp += 3;
2450 return;
2452 if (!isdigit (*dbp))
2454 --dbp; /* force failure */
2455 return;
2458 dbp++;
2459 while (isdigit (*dbp));
2462 void
2463 getit (inf)
2464 FILE *inf;
2466 register char *cp;
2468 while (isspace (*dbp))
2469 dbp++;
2470 if (*dbp == '\0')
2472 lineno++;
2473 linecharno = charno;
2474 charno += readline (&lb, inf);
2475 dbp = lb.buffer;
2476 if (dbp[5] != '&')
2477 return;
2478 dbp += 6;
2479 while (isspace (*dbp))
2480 dbp++;
2482 if (!isalpha (*dbp)
2483 && *dbp != '_'
2484 && *dbp != '$')
2485 return;
2486 for (cp = dbp + 1;
2487 (*cp
2488 && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
2489 cp++)
2490 continue;
2491 pfnote (savenstr (dbp, cp-dbp), TRUE, FALSE, lb.buffer,
2492 cp - lb.buffer + 1, lineno, linecharno);
2495 void
2496 Fortran_functions (inf)
2497 FILE *inf;
2499 lineno = 0;
2500 charno = 0;
2502 while (!feof (inf))
2504 lineno++;
2505 linecharno = charno;
2506 charno += readline (&lb, inf);
2507 dbp = lb.buffer;
2508 if (*dbp == '%')
2509 dbp++; /* Ratfor escape to fortran */
2510 while (isspace (*dbp))
2511 dbp++;
2512 if (*dbp == 0)
2513 continue;
2514 switch (lowcase (*dbp))
2516 case 'i':
2517 if (tail ("integer"))
2518 takeprec ();
2519 break;
2520 case 'r':
2521 if (tail ("real"))
2522 takeprec ();
2523 break;
2524 case 'l':
2525 if (tail ("logical"))
2526 takeprec ();
2527 break;
2528 case 'c':
2529 if (tail ("complex") || tail ("character"))
2530 takeprec ();
2531 break;
2532 case 'd':
2533 if (tail ("double"))
2535 while (isspace (*dbp))
2536 dbp++;
2537 if (*dbp == 0)
2538 continue;
2539 if (tail ("precision"))
2540 break;
2541 continue;
2543 break;
2545 while (isspace (*dbp))
2546 dbp++;
2547 if (*dbp == 0)
2548 continue;
2549 switch (lowcase (*dbp))
2551 case 'f':
2552 if (tail ("function"))
2553 getit (inf);
2554 continue;
2555 case 's':
2556 if (tail ("subroutine"))
2557 getit (inf);
2558 continue;
2559 case 'e':
2560 if (tail ("entry"))
2561 getit (inf);
2562 continue;
2563 case 'p':
2564 if (tail ("program"))
2566 getit (inf);
2567 continue;
2569 if (tail ("procedure"))
2570 getit (inf);
2571 continue;
2577 * Bob Weiner, Motorola Inc., 4/3/94
2578 * Unix and microcontroller assembly tag handling
2579 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
2581 void
2582 Asm_labels (inf)
2583 FILE *inf;
2585 register char *cp;
2587 lineno = 0;
2588 charno = 0;
2590 while (!feof (inf))
2592 lineno++;
2593 linecharno = charno;
2594 charno += readline (&lb, inf);
2595 cp = lb.buffer;
2597 /* If first char is alphabetic or one of [_.$], test for colon
2598 following identifier. */
2599 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2601 /* Read past label. */
2602 cp++;
2603 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
2604 cp++;
2605 if (*cp == ':' || isspace (*cp))
2607 /* Found end of label, so copy it and add it to the table. */
2608 pfnote (savenstr (lb.buffer, cp-lb.buffer), TRUE, FALSE,
2609 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2615 /* Added by Mosur Mohan, 4/22/88 */
2616 /* Pascal parsing */
2618 #define GET_NEW_LINE \
2620 linecharno = charno; lineno++; \
2621 charno += 1 + readline (&lb, inf); \
2622 dbp = lb.buffer; \
2626 * Locates tags for procedures & functions. Doesn't do any type- or
2627 * var-definitions. It does look for the keyword "extern" or
2628 * "forward" immediately following the procedure statement; if found,
2629 * the tag is skipped.
2631 void
2632 Pascal_functions (inf)
2633 FILE *inf;
2635 struct linebuffer tline; /* mostly copied from C_entries */
2636 long save_lcno;
2637 int save_lineno;
2638 char c, *cp;
2639 char *nambuf;
2641 logical /* each of these flags is TRUE iff: */
2642 incomment, /* point is inside a comment */
2643 inquote, /* point is inside '..' string */
2644 get_tagname, /* point is after PROCEDURE/FUNCTION */
2645 /* keyword, so next item = potential tag */
2646 found_tag, /* point is after a potential tag */
2647 inparms, /* point is within parameter-list */
2648 verify_tag; /* point has passed the parm-list, so the */
2649 /* next token will determine whether */
2650 /* this is a FORWARD/EXTERN to be */
2651 /* ignored, or whether it is a real tag */
2653 lineno = 0;
2654 charno = 0;
2655 dbp = lb.buffer;
2656 *dbp = 0;
2657 initbuffer (&tline);
2659 incomment = inquote = FALSE;
2660 found_tag = FALSE; /* have a proc name; check if extern */
2661 get_tagname = FALSE; /* have found "procedure" keyword */
2662 inparms = FALSE; /* found '(' after "proc" */
2663 verify_tag = FALSE; /* check if "extern" is ahead */
2665 /* long main loop to get next char */
2666 while (!feof (inf))
2668 c = *dbp++;
2669 if (c == '\0') /* if end of line */
2671 GET_NEW_LINE;
2672 if (*dbp == '\0')
2673 continue;
2674 if (!((found_tag && verify_tag) ||
2675 get_tagname))
2676 c = *dbp++; /* only if don't need *dbp pointing */
2677 /* to the beginning of the name of */
2678 /* the procedure or function */
2680 if (incomment)
2682 if (c == '}') /* within { - } comments */
2683 incomment = FALSE;
2684 else if (c == '*' && dbp[1] == ')') /* within (* - *) comments */
2686 dbp++;
2687 incomment = FALSE;
2689 continue;
2691 else if (inquote)
2693 if (c == '\'')
2694 inquote = FALSE;
2695 continue;
2697 else
2698 switch (c)
2700 case '\'':
2701 inquote = TRUE; /* found first quote */
2702 continue;
2703 case '{': /* found open-{-comment */
2704 incomment = TRUE;
2705 continue;
2706 case '(':
2707 if (*dbp == '*') /* found open-(*-comment */
2709 incomment = TRUE;
2710 dbp++;
2712 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2713 inparms = TRUE;
2714 continue;
2715 case ')': /* end of parms list */
2716 if (inparms)
2717 inparms = FALSE;
2718 continue;
2719 case ';':
2720 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2722 verify_tag = TRUE;
2723 break;
2725 continue;
2727 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2729 /* check if this is an "extern" declaration */
2730 if (*dbp == 0)
2731 continue;
2732 if ((*dbp == 'e') || (*dbp == 'E'))
2734 if (tail ("extern")) /* superfluous, really! */
2736 found_tag = FALSE;
2737 verify_tag = FALSE;
2740 else if ((*dbp == 'f') || (*dbp == 'F'))
2742 if (tail ("forward")) /* check for forward reference */
2744 found_tag = FALSE;
2745 verify_tag = FALSE;
2748 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2750 found_tag = FALSE;
2751 verify_tag = FALSE;
2752 pfnote (nambuf, TRUE, FALSE, tline.buffer,
2753 cp - tline.buffer + 1, save_lineno, save_lcno);
2754 continue;
2757 if (get_tagname) /* grab name of proc or fn */
2759 if (*dbp == 0)
2760 continue;
2762 /* save all values for later tagging */
2763 tline.size = lb.size;
2764 strcpy (tline.buffer, lb.buffer);
2765 save_lineno = lineno;
2766 save_lcno = linecharno;
2768 /* grab block name */
2769 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2770 continue;
2771 nambuf = savenstr (dbp, cp-dbp);
2772 dbp = cp; /* restore dbp to e-o-token */
2773 get_tagname = FALSE;
2774 found_tag = TRUE;
2775 continue;
2777 /* and proceed to check for "extern" */
2779 else if (!incomment && !inquote && !found_tag)
2781 /* check for proc/fn keywords */
2782 switch (lowcase (c))
2784 case 'p':
2785 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2786 get_tagname = TRUE;
2787 continue;
2788 case 'f':
2789 if (tail ("unction"))
2790 get_tagname = TRUE;
2791 continue;
2794 } /* while not eof */
2798 * lisp tag functions
2799 * look for (def or (DEF, quote or QUOTE
2802 L_isdef (strp)
2803 register char *strp;
2805 return ((strp[1] == 'd' || strp[1] == 'D')
2806 && (strp[2] == 'e' || strp[2] == 'E')
2807 && (strp[3] == 'f' || strp[3] == 'F'));
2811 L_isquote (strp)
2812 register char *strp;
2814 return ((*(++strp) == 'q' || *strp == 'Q')
2815 && (*(++strp) == 'u' || *strp == 'U')
2816 && (*(++strp) == 'o' || *strp == 'O')
2817 && (*(++strp) == 't' || *strp == 'T')
2818 && (*(++strp) == 'e' || *strp == 'E')
2819 && isspace(*(++strp)));
2822 void
2823 L_getit ()
2825 register char *cp;
2827 if (*dbp == '\'') /* Skip prefix quote */
2828 dbp++;
2829 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2831 dbp += 7;
2832 while (isspace(*dbp))
2833 dbp++;
2835 for (cp = dbp /*+1*/;
2836 *cp && *cp != '(' && *cp != ' ' && *cp != ')';
2837 cp++)
2838 continue;
2839 if (cp == dbp)
2840 return;
2842 pfnote (savenstr (dbp, cp-dbp), TRUE, FALSE, lb.buffer,
2843 cp - lb.buffer + 1, lineno, linecharno);
2846 void
2847 Lisp_functions (inf)
2848 FILE *inf;
2850 lineno = 0;
2851 charno = 0;
2853 while (!feof (inf))
2855 lineno++;
2856 linecharno = charno;
2857 charno += readline (&lb, inf);
2858 dbp = lb.buffer;
2859 if (dbp[0] == '(')
2861 if (L_isdef (dbp))
2863 while (!isspace (*dbp))
2864 dbp++;
2865 while (isspace (*dbp))
2866 dbp++;
2867 L_getit ();
2869 else
2871 /* Check for (foo::defmumble name-defined ... */
2873 dbp++;
2874 while (*dbp && !isspace (*dbp)
2875 && *dbp != ':' && *dbp != '(' && *dbp != ')');
2876 if (*dbp == ':')
2879 dbp++;
2880 while (*dbp == ':');
2882 if (L_isdef (dbp - 1))
2884 while (!isspace (*dbp))
2885 dbp++;
2886 while (isspace (*dbp))
2887 dbp++;
2888 L_getit ();
2897 * Scheme tag functions
2898 * look for (def... xyzzy
2899 * look for (def... (xyzzy
2900 * look for (def ... ((...(xyzzy ....
2901 * look for (set! xyzzy
2904 void get_scheme ();
2906 void
2907 Scheme_functions (inf)
2908 FILE *inf;
2910 lineno = 0;
2911 charno = 0;
2913 while (!feof (inf))
2915 lineno++;
2916 linecharno = charno;
2917 charno += readline (&lb, inf);
2918 dbp = lb.buffer;
2919 if (dbp[0] == '(' &&
2920 (dbp[1] == 'D' || dbp[1] == 'd') &&
2921 (dbp[2] == 'E' || dbp[2] == 'e') &&
2922 (dbp[3] == 'F' || dbp[3] == 'f'))
2924 while (!isspace (*dbp))
2925 dbp++;
2926 /* Skip over open parens and white space */
2927 while (*dbp && (isspace (*dbp) || *dbp == '('))
2928 dbp++;
2929 get_scheme ();
2931 if (dbp[0] == '(' &&
2932 (dbp[1] == 'S' || dbp[1] == 's') &&
2933 (dbp[2] == 'E' || dbp[2] == 'e') &&
2934 (dbp[3] == 'T' || dbp[3] == 't') &&
2935 (dbp[4] == '!' || dbp[4] == '!') &&
2936 (isspace (dbp[5])))
2938 while (!isspace (*dbp))
2939 dbp++;
2940 /* Skip over white space */
2941 while (isspace (*dbp))
2942 dbp++;
2943 get_scheme ();
2948 void
2949 get_scheme ()
2951 register char *cp;
2953 if (*dbp == 0)
2954 return;
2955 /* Go till you get to white space or a syntactic break */
2956 for (cp = dbp + 1;
2957 *cp && *cp != '(' && *cp != ')' && !isspace (*cp);
2958 cp++)
2959 continue;
2960 pfnote (savenstr (dbp, cp-dbp), TRUE, FALSE,
2961 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2964 /* Find tags in TeX and LaTeX input files. */
2966 /* TEX_toktab is a table of TeX control sequences that define tags.
2967 Each TEX_tabent records one such control sequence.
2968 CONVERT THIS TO USE THE Stab TYPE!! */
2969 struct TEX_tabent
2971 char *name;
2972 int len;
2975 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2977 /* Default set of control sequences to put into TEX_toktab.
2978 The value of environment var TEXTAGS is prepended to this. */
2980 char *TEX_defenv = "\
2981 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2983 void TEX_mode ();
2984 struct TEX_tabent *TEX_decode_env ();
2985 void TEX_getit ();
2986 int TEX_Token ();
2988 char TEX_esc = '\\';
2989 char TEX_opgrp = '{';
2990 char TEX_clgrp = '}';
2993 * TeX/LaTeX scanning loop.
2995 void
2996 TeX_functions (inf)
2997 FILE *inf;
2999 char *lasthit;
3001 lineno = 0;
3002 charno = 0;
3004 /* Select either \ or ! as escape character. */
3005 TEX_mode (inf);
3007 /* Initialize token table once from environment. */
3008 if (!TEX_toktab)
3009 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
3011 while (!feof (inf))
3012 { /* Scan each line in file */
3013 lineno++;
3014 linecharno = charno;
3015 charno += readline (&lb, inf);
3016 dbp = lb.buffer;
3017 lasthit = dbp;
3018 while (dbp = etags_strchr (dbp, TEX_esc)) /* Look at each esc in line */
3020 register int i;
3022 if (!*(++dbp))
3023 break;
3024 linecharno += dbp - lasthit;
3025 lasthit = dbp;
3026 i = TEX_Token (lasthit);
3027 if (0 <= i)
3029 TEX_getit (lasthit, TEX_toktab[i].len);
3030 break; /* We only save a line once */
3036 #define TEX_LESC '\\'
3037 #define TEX_SESC '!'
3038 #define TEX_cmt '%'
3040 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
3041 chars accordingly. */
3042 void
3043 TEX_mode (inf)
3044 FILE *inf;
3046 int c;
3048 while ((c = getc (inf)) != EOF)
3050 /* Skip to next line if we hit the TeX comment char. */
3051 if (c == TEX_cmt)
3052 while (c != '\n')
3053 c = getc (inf);
3054 else if (c == TEX_LESC || c == TEX_SESC )
3055 break;
3058 if (c == TEX_LESC)
3060 TEX_esc = TEX_LESC;
3061 TEX_opgrp = '{';
3062 TEX_clgrp = '}';
3064 else
3066 TEX_esc = TEX_SESC;
3067 TEX_opgrp = '<';
3068 TEX_clgrp = '>';
3070 rewind (inf);
3073 /* Read environment and prepend it to the default string.
3074 Build token table. */
3075 struct TEX_tabent *
3076 TEX_decode_env (evarname, defenv)
3077 char *evarname;
3078 char *defenv;
3080 register char *env, *p;
3082 struct TEX_tabent *tab;
3083 int size, i;
3085 /* Append default string to environment. */
3086 env = getenv (evarname);
3087 if (!env)
3088 env = defenv;
3089 else
3090 env = concat (env, defenv, "");
3092 /* Allocate a token table */
3093 for (size = 1, p = env; p;)
3094 if ((p = etags_strchr (p, ':')) && *(++p))
3095 size++;
3096 /* Add 1 to leave room for null terminator. */
3097 tab = xnew (size + 1, struct TEX_tabent);
3099 /* Unpack environment string into token table. Be careful about */
3100 /* zero-length strings (leading ':', "::" and trailing ':') */
3101 for (i = 0; *env;)
3103 p = etags_strchr (env, ':');
3104 if (!p) /* End of environment string. */
3105 p = env + strlen (env);
3106 if (p - env > 0)
3107 { /* Only non-zero strings. */
3108 tab[i].name = savenstr (env, p - env);
3109 tab[i].len = strlen (tab[i].name);
3110 i++;
3112 if (*p)
3113 env = p + 1;
3114 else
3116 tab[i].name = NULL; /* Mark end of table. */
3117 tab[i].len = 0;
3118 break;
3121 return tab;
3124 /* Record a tag defined by a TeX command of length LEN and starting at NAME.
3125 The name being defined actually starts at (NAME + LEN + 1).
3126 But we seem to include the TeX command in the tag name. */
3127 void
3128 TEX_getit (name, len)
3129 char *name;
3130 int len;
3132 char *p = name + len;
3134 if (*name == 0)
3135 return;
3137 /* Let tag name extend to next group close (or end of line) */
3138 while (*p && *p != TEX_clgrp)
3139 p++;
3140 pfnote (savenstr (name, p-name), TRUE, FALSE, lb.buffer,
3141 strlen (lb.buffer), lineno, linecharno);
3144 /* If the text at CP matches one of the tag-defining TeX command names,
3145 return the pointer to the first occurrence of that command in TEX_toktab.
3146 Otherwise return -1.
3147 Keep the capital `T' in `Token' for dumb truncating compilers
3148 (this distinguishes it from `TEX_toktab' */
3150 TEX_Token (cp)
3151 char *cp;
3153 int i;
3155 for (i = 0; TEX_toktab[i].len > 0; i++)
3156 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
3157 return i;
3158 return -1;
3161 /* Support for Prolog. */
3163 /* Whole head (not only functor, but also arguments)
3164 is gotten in compound term. */
3165 void
3166 prolog_getit (s)
3167 char *s;
3169 char *save_s;
3170 int insquote, npar;
3172 save_s = s;
3173 insquote = FALSE;
3174 npar = 0;
3175 while (1)
3177 if (s[0] == '\0') /* syntax error. */
3178 return;
3179 else if (insquote && s[0] == '\'' && s[1] == '\'')
3180 s += 2;
3181 else if (s[0] == '\'')
3183 insquote = !insquote;
3184 s++;
3186 else if (!insquote && s[0] == '(')
3188 npar++;
3189 s++;
3191 else if (!insquote && s[0] == ')')
3193 npar--;
3194 s++;
3195 if (npar == 0)
3196 break;
3197 else if (npar < 0) /* syntax error. */
3198 return;
3200 else if (!insquote && s[0] == '.'
3201 && (isspace (s[1]) || s[1] == '\0'))
3202 { /* fullstop. */
3203 if (npar != 0) /* syntax error. */
3204 return;
3205 s++;
3206 break;
3208 else
3209 s++;
3211 pfnote (savenstr (save_s, s-save_s), TRUE, FALSE,
3212 save_s, s-save_s, lineno, linecharno);
3215 /* It is assumed that prolog predicate starts from column 0. */
3216 void
3217 Prolog_functions (inf)
3218 FILE *inf;
3220 void skip_comment (), prolog_getit ();
3222 lineno = linecharno = charno = 0;
3223 while (!feof (inf))
3225 lineno++;
3226 linecharno += charno;
3227 charno = readline (&lb, inf) + 1; /* 1 for newline. */
3228 dbp = lb.buffer;
3229 if (isspace (dbp[0])) /* not predicate header. */
3230 continue;
3231 else if (dbp[0] == '%') /* comment. */
3232 continue;
3233 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
3234 skip_comment (&lb, inf, &lineno, &linecharno);
3235 else /* found. */
3236 prolog_getit (dbp);
3240 void
3241 skip_comment (plb, inf, plineno, plinecharno)
3242 struct linebuffer *plb;
3243 FILE *inf;
3244 int *plineno; /* result */
3245 long *plinecharno; /* result */
3247 char *cp;
3251 for (cp = plb->buffer; *cp != '\0'; cp++)
3252 if (cp[0] == '*' && cp[1] == '/')
3253 return;
3254 (*plineno)++;
3255 *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
3257 while (!feof(inf));
3260 #ifdef ETAGS_REGEXPS
3261 /* Take a string like "/blah/" and turn it into "blah", making sure
3262 that the first and last characters are the same, and handling
3263 quoted separator characters. Actually, stops on the occurence of
3264 an unquoted separator. Also turns "\t" into a Tab character.
3265 Returns pointer to terminating separator. Works in place. Null
3266 terminates name string. */
3267 char *
3268 scan_separators (name)
3269 char *name;
3271 char sep = name[0];
3272 char *copyto = name;
3273 logical quoted = FALSE;
3275 for (++name; *name != '\0'; ++name)
3277 if (quoted)
3279 if (*name == 't')
3280 *copyto++ = '\t';
3281 else if (*name == sep)
3282 *copyto++ = sep;
3283 else
3285 /* Something else is quoted, so preserve the quote. */
3286 *copyto++ = '\\';
3287 *copyto++ = *name;
3289 quoted = FALSE;
3291 else if (*name == '\\')
3292 quoted = TRUE;
3293 else if (*name == sep)
3294 break;
3295 else
3296 *copyto++ = *name;
3299 /* Terminate copied string. */
3300 *copyto = '\0';
3301 return name;
3304 /* Turn a name, which is an ed-style (but Emacs syntax) regular
3305 expression, into a real regular expression by compiling it. */
3306 void
3307 add_regex (regexp_pattern)
3308 char *regexp_pattern;
3310 char *name;
3311 const char *err;
3312 struct re_pattern_buffer *patbuf;
3314 if (regexp_pattern == NULL)
3316 /* Remove existing regexps. */
3317 num_patterns = 0;
3318 patterns = NULL;
3319 return;
3322 if (regexp_pattern[0] == '\0')
3324 error ("missing regexp", 0);
3325 return;
3327 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
3329 error ("%s: unterminated regexp", regexp_pattern);
3330 return;
3332 name = scan_separators (regexp_pattern);
3333 if (regexp_pattern[0] == '\0')
3335 error ("null regexp", 0);
3336 return;
3338 (void) scan_separators (name);
3340 patbuf = xnew (1, struct re_pattern_buffer);
3341 patbuf->translate = NULL;
3342 patbuf->fastmap = NULL;
3343 patbuf->buffer = NULL;
3344 patbuf->allocated = 0;
3346 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
3347 if (err != NULL)
3349 error ("%s while compiling pattern", err);
3350 return;
3353 num_patterns += 1;
3354 if (num_patterns == 1)
3355 patterns = xnew (1, struct pattern);
3356 else
3357 patterns = ((struct pattern *)
3358 xrealloc (patterns,
3359 (num_patterns * sizeof (struct pattern))));
3360 patterns[num_patterns - 1].pattern = patbuf;
3361 patterns[num_patterns - 1].name_pattern = savestr (name);
3362 patterns[num_patterns - 1].error_signaled = FALSE;
3366 * Do the subtitutions indicated by the regular expression and
3367 * arguments.
3369 char *
3370 substitute (in, out, regs)
3371 char *in, *out;
3372 struct re_registers *regs;
3374 char *result = NULL, *t;
3375 int size = 0;
3377 /* Pass 1: figure out how much size to allocate. */
3378 for (t = out; *t; ++t)
3380 if (*t == '\\')
3382 ++t;
3383 if (!*t)
3385 fprintf (stderr, "%s: pattern subtitution ends prematurely\n",
3386 progname);
3387 return NULL;
3389 if (isdigit (*t))
3391 int dig = *t - '0';
3392 size += regs->end[dig] - regs->start[dig];
3397 /* Allocate space and do the substitutions. */
3398 result = xnew (size + 1, char);
3399 size = 0;
3400 for (; *out; ++out)
3402 if (*out == '\\')
3404 ++out;
3405 if (isdigit (*out))
3407 /* Using "dig2" satisfies my debugger. Bleah. */
3408 int dig2 = *out - '0';
3409 strncpy (result + size, in + regs->start[dig2],
3410 regs->end[dig2] - regs->start[dig2]);
3411 size += regs->end[dig2] - regs->start[dig2];
3413 else
3415 switch (*out)
3417 case '\t':
3418 result[size++] = '\t';
3419 break;
3420 case '\\':
3421 *out = '\\';
3422 break;
3423 default:
3424 result[size++] = *out;
3425 break;
3429 else
3430 result[size++] = *out;
3432 result[size] = '\0';
3434 return result;
3437 #endif /* ETAGS_REGEXPS */
3438 /* Initialize a linebuffer for use */
3439 void
3440 initbuffer (linebuffer)
3441 struct linebuffer *linebuffer;
3443 linebuffer->size = 200;
3444 linebuffer->buffer = xnew (200, char);
3448 * Read a line of text from `stream' into `linebuffer'.
3449 * Return the number of characters read from `stream',
3450 * which is the length of the line including the newline, if any.
3452 long
3453 readline_internal (linebuffer, stream)
3454 struct linebuffer *linebuffer;
3455 register FILE *stream;
3457 char *buffer = linebuffer->buffer;
3458 register char *p = linebuffer->buffer;
3459 register char *pend;
3460 int chars_deleted;
3462 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
3464 while (1)
3466 register int c = getc (stream);
3467 if (p == pend)
3469 linebuffer->size *= 2;
3470 buffer = (char *) xrealloc (buffer, linebuffer->size);
3471 p += buffer - linebuffer->buffer;
3472 pend = buffer + linebuffer->size;
3473 linebuffer->buffer = buffer;
3475 if (c == EOF)
3477 chars_deleted = 0;
3478 break;
3480 if (c == '\n')
3482 if (p > buffer && p[-1] == '\r')
3484 *--p = '\0';
3485 chars_deleted = 2;
3487 else
3489 *p = '\0';
3490 chars_deleted = 1;
3492 break;
3494 *p++ = c;
3497 return p - buffer + chars_deleted;
3501 * Like readline_internal, above, but try to match the input
3502 * line against any existing regular expressions.
3504 long
3505 readline (linebuffer, stream)
3506 struct linebuffer *linebuffer;
3507 FILE *stream;
3509 /* Read new line. */
3510 int i;
3511 long result = readline_internal (linebuffer, stream);
3513 #ifdef ETAGS_REGEXPS
3514 /* Match against all listed patterns. */
3515 for (i = 0; i < num_patterns; ++i)
3517 int match = re_match (patterns[i].pattern, linebuffer->buffer,
3518 (int)result, 0, &patterns[i].regs);
3519 switch (match)
3521 case -2:
3522 /* Some error. */
3523 if (!patterns[i].error_signaled)
3525 error ("error while matching pattern %d", i);
3526 patterns[i].error_signaled = TRUE;
3528 break;
3529 case -1:
3530 /* No match. */
3531 break;
3532 default:
3533 /* Match occurred. Construct a tag. */
3534 if (patterns[i].name_pattern[0] != '\0')
3536 /* Make a named tag. */
3537 char *name = substitute (linebuffer->buffer,
3538 patterns[i].name_pattern,
3539 &patterns[i].regs);
3540 if (name != NULL)
3541 pfnote (name, TRUE, TRUE, linebuffer->buffer,
3542 match, lineno, linecharno);
3544 else
3546 /* Make an unnamed tag. */
3547 pfnote (NULL, TRUE, FALSE, linebuffer->buffer,
3548 match, lineno, linecharno);
3550 break;
3553 #endif /* ETAGS_REGEXPS */
3555 return result;
3559 * Read a file, but do no processing. This is used to do regexp
3560 * matching on files that have no language defined.
3562 void
3563 just_read_file (inf)
3564 FILE *inf;
3566 while (!feof (inf))
3568 ++lineno;
3569 linecharno = charno;
3570 charno += readline (&lb, inf) + 1;
3576 * Return a pointer to a space of size strlen(cp)+1 allocated
3577 * with xnew where the string CP has been copied.
3579 char *
3580 savestr (cp)
3581 char *cp;
3583 return savenstr (cp, strlen (cp));
3587 * Return a pointer to a space of size LEN+1 allocated with xnew where
3588 * the string CP has been copied for at most the first LEN characters.
3590 char *
3591 savenstr (cp, len)
3592 char *cp;
3593 int len;
3595 register char *dp;
3597 dp = xnew (len + 1, char);
3598 strncpy (dp, cp, len);
3599 dp[len] = '\0';
3600 return dp;
3604 * Return the ptr in sp at which the character c last
3605 * appears; NULL if not found
3607 * Identical to System V strrchr, included for portability.
3609 char *
3610 etags_strrchr (sp, c)
3611 register char *sp, c;
3613 register char *r;
3615 r = NULL;
3618 if (*sp == c)
3619 r = sp;
3620 } while (*sp++);
3621 return r;
3626 * Return the ptr in sp at which the character c first
3627 * appears; NULL if not found
3629 * Identical to System V strchr, included for portability.
3631 char *
3632 etags_strchr (sp, c)
3633 register char *sp, c;
3637 if (*sp == c)
3638 return sp;
3639 } while (*sp++);
3640 return NULL;
3643 /* Print error message and exit. */
3644 void
3645 fatal (s1, s2)
3646 char *s1, *s2;
3648 error (s1, s2);
3649 exit (BAD);
3652 void
3653 pfatal (s1)
3654 char *s1;
3656 perror (s1);
3657 exit (BAD);
3660 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
3661 void
3662 error (s1, s2)
3663 char *s1, *s2;
3665 fprintf (stderr, "%s: ", progname);
3666 fprintf (stderr, s1, s2);
3667 fprintf (stderr, "\n");
3670 /* Return a newly-allocated string whose contents
3671 concatenate those of s1, s2, s3. */
3672 char *
3673 concat (s1, s2, s3)
3674 char *s1, *s2, *s3;
3676 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3677 char *result = xnew (len1 + len2 + len3 + 1, char);
3679 strcpy (result, s1);
3680 strcpy (result + len1, s2);
3681 strcpy (result + len1 + len2, s3);
3682 result[len1 + len2 + len3] = '\0';
3684 return result;
3687 /* Does the same work as the system V getcwd, but does not need to
3688 guess buffer size in advance. */
3689 char *
3690 etags_getcwd ()
3692 #ifdef DOS_NT
3693 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
3695 getwd (path);
3696 p = path;
3697 while (*p)
3698 if (*p == '\\')
3699 *p++ = '/';
3700 else
3701 *p++ = tolower (*p);
3703 return strdup (path);
3704 #else /* not DOS_NT */
3705 #if HAVE_GETCWD
3706 int bufsize = 200;
3707 char *path = xnew (bufsize, char);
3709 while (getcwd (path, bufsize) == NULL)
3711 if (errno != ERANGE)
3712 pfatal ("getcwd");
3713 bufsize *= 2;
3714 path = xnew (bufsize, char);
3717 return path;
3718 #else /* not DOS_NT and not HAVE_GETCWD */
3719 struct linebuffer path;
3720 FILE *pipe;
3722 initbuffer (&path);
3723 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
3724 if (pipe == NULL || readline_internal (&path, pipe) == 0)
3725 pfatal ("pwd");
3726 pclose (pipe);
3728 return path.buffer;
3729 #endif /* not HAVE_GETCWD */
3730 #endif /* not DOS_NT */
3733 /* Return a newly allocated string containing the filename
3734 of FILE relative to the absolute directory DIR (which
3735 should end with a slash). */
3736 char *
3737 relative_filename (file, dir)
3738 char *file, *dir;
3740 char *fp, *dp, *res;
3742 /* Find the common root of file and dir. */
3743 fp = absolute_filename (file, cwd);
3744 dp = dir;
3745 while (*fp++ == *dp++)
3746 continue;
3749 fp--;
3750 dp--;
3752 while (*fp != '/');
3754 /* Build a sequence of "../" strings for the resulting relative filename. */
3755 for (dp = etags_strchr (dp + 1, '/'), res = "";
3756 dp != NULL;
3757 dp = etags_strchr (dp + 1, '/'))
3759 res = concat (res, "../", "");
3762 /* Add the filename relative to the common root of file and dir. */
3763 res = concat (res, fp + 1, "");
3765 return res; /* temporary stub */
3768 /* Return a newly allocated string containing the
3769 absolute filename of FILE given CWD (which should
3770 end with a slash). */
3771 char *
3772 absolute_filename (file, cwd)
3773 char *file, *cwd;
3775 char *slashp, *cp, *res;
3777 if (absolutefn (file))
3778 res = concat (file, "", "");
3779 else
3780 res = concat (cwd, file, "");
3782 /* Delete the "/dirname/.." and "/." substrings. */
3783 slashp = etags_strchr (res, '/');
3784 while (slashp != NULL && slashp[0] != '\0')
3786 if (slashp[1] == '.')
3788 if (slashp[2] == '.'
3789 && (slashp[3] == '/' || slashp[3] == '\0'))
3791 cp = slashp;
3793 cp--;
3794 while (cp >= res && *cp != '/');
3795 if (*cp == '/')
3797 strcpy (cp, slashp + 3);
3799 else /* else (cp == res) */
3801 if (slashp[3] != '\0')
3802 strcpy (cp, slashp + 4);
3803 else
3804 return ".";
3806 slashp = cp;
3807 continue;
3809 else if (slashp[2] == '/' || slashp[2] == '\0')
3811 strcpy (slashp, slashp + 2);
3812 continue;
3816 slashp = etags_strchr (slashp + 1, '/');
3819 return res;
3822 /* Return a newly allocated string containing the absolute
3823 filename of dir where FILE resides given CWD (which should
3824 end with a slash). */
3825 char *
3826 absolute_dirname (file, cwd)
3827 char *file, *cwd;
3829 char *slashp, *res;
3830 char save;
3832 slashp = etags_strrchr (file, '/');
3833 if (slashp == NULL)
3834 return cwd;
3835 save = slashp[1];
3836 slashp[1] = '\0';
3837 res = absolute_filename (file, cwd);
3838 slashp[1] = save;
3840 return res;
3843 /* Like malloc but get fatal error if memory is exhausted. */
3844 long *
3845 xmalloc (size)
3846 unsigned int size;
3848 long *result = (long *) malloc (size);
3849 if (result == NULL)
3850 fatal ("virtual memory exhausted", 0);
3851 return result;
3854 long *
3855 xrealloc (ptr, size)
3856 char *ptr;
3857 unsigned int size;
3859 long *result = (long *) realloc (ptr, size);
3860 if (result == NULL)
3861 fatal ("virtual memory exhausted");
3862 return result;