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