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