Mon Sep 20 18:06:12 1993 Francesco Potorti` (pot at fly)
[bpt/emacs.git] / lib-src / etags.c
CommitLineData
c6d46f5f 1/* Tags file maker to go with GNU Emacs
13fde0cd 2 Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
c6d46f5f 3
ea6cd314 4This file is not considered part of GNU Emacs.
c6d46f5f 5
ea6cd314 6This program is free software; you can redistribute it and/or modify
c6d46f5f 7it under the terms of the GNU General Public License as published by
ea6cd314
RS
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
c6d46f5f 10
ea6cd314 11This program is distributed in the hope that it will be useful,
c6d46f5f
JB
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
ea6cd314
RS
17along with this program; if not, write to the Free Software
18Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
c6d46f5f
JB
19
20/*
21 * Authors:
22 * Ctags originally by Ken Arnold.
23 * FORTRAN added by Jim Kleckner.
24 * Ed Pelegri-Llopart added C typedefs.
25 * Gnu Emacs TAGS format and modifications by RMS?
26 * Sam Kendall added C++.
31d4b314 27 *
fe0b3356 28 * Francesco Potorti` is the current maintainer. 8.3
c6d46f5f
JB
29 */
30
72a339d7 31#ifdef HAVE_CONFIG_H
18160b98 32#include <../src/config.h>
1e134a5f
RM
33#endif
34
918f9ad1
JB
35#include <stdio.h>
36#include <ctype.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39
40#include "getopt.h"
41
c6d46f5f
JB
42extern char *malloc (), *realloc ();
43extern char *getenv ();
c6d46f5f
JB
44extern char *strcpy (), *strncpy ();
45extern int strcmp ();
46
8a6c8bcf
RS
47char *etags_index (), *etags_rindex ();
48char *savenstr ();
c6d46f5f
JB
49
50/* Define the symbol ETAGS to make the program "etags",
51 which makes emacs-style tag tables by default.
52 Define CTAGS to make the program "ctags" compatible with the usual one.
53 Define neither one to get behavior that depends
54 on the name with which the program is invoked
55 (but we don't normally compile it that way). */
56
57#if !defined(ETAGS) && !defined(CTAGS)
58/* If neither is defined, program can be run as either. */
59#define ETAGS
60#define CTAGS
61#endif
62
63/* On VMS, CTAGS is not useful, so always do ETAGS. */
64#ifdef VMS
65#ifndef ETAGS
66#define ETAGS
67#endif
68#endif
69
70/* Exit codes for success and failure. */
71#ifdef VMS
72#define GOOD (1)
73#define BAD (0)
74#else
75#define GOOD (0)
76#define BAD (1)
77#endif
78
79/*
80 * The FILEPOS abstract type, which represents a position in a file,
81 * plus the following accessor functions:
82 *
83 * long GET_CHARNO (pos)
84 * returns absolute char number.
c6d46f5f
JB
85 * void SET_FILEPOS (pos, fp, charno)
86 * FILE *fp; long charno;
87 * sets `pos' from the current file
88 * position of `fp' and from `charno',
89 * which must be the absolute character
90 * number corresponding to the current
91 * position of `fp'.
92 *
93 * The `pos' parameter is an lvalue expression of type FILEPOS.
94 * Parameters to the accessor functions are evaluated 0 or more times,
95 * and so must have no side effects.
96 *
97 * FILEPOS objects can also be assigned and passed to and from
98 * functions in the normal C manner.
99 *
100 * Implementation notes: the `+ 0' is to enforce rvalue-ness.
101 */
c6d46f5f 102
c6d46f5f 103#ifndef DEBUG
13fde0cd 104 /* real implementation */
c6d46f5f
JB
105typedef long FILEPOS;
106#define GET_CHARNO(pos) ((pos) + 0)
c6d46f5f
JB
107#define SET_FILEPOS(pos, fp, cno) ((void) ((pos) = (cno)))
108#else
13fde0cd 109 /* debugging implementation */
c6d46f5f
JB
110typedef struct
111{
112 long charno;
113} FILEPOS;
114
115#define GET_CHARNO(pos) ((pos).charno + 0)
c6d46f5f
JB
116#define SET_FILEPOS(pos, fp, cno) \
117 ((void) ((pos).charno = (cno), \
118 (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
119 : 0))
120#endif
c6d46f5f
JB
121
122#define streq(s, t) (strcmp (s, t) == 0)
123#define strneq(s, t, n) (strncmp (s, t, n) == 0)
13fde0cd 124#define logical int
c6d46f5f
JB
125
126#define TRUE 1
127#define FALSE 0
128
129#define iswhite(arg) (_wht[arg]) /* T if char is white */
130#define begtoken(arg) (_btk[arg]) /* T if char can start token */
131#define intoken(arg) (_itk[arg]) /* T if char can be in token */
132#define endtoken(arg) (_etk[arg]) /* T if char ends tokens */
c6d46f5f
JB
133
134#define max(I1,I2) ((I1) > (I2) ? (I1) : (I2))
135
136struct nd_st
137{ /* sorting structure */
138 char *name; /* function or type name */
139 char *file; /* file name */
140 logical is_func; /* use pattern or line no */
fe0b3356 141 logical named; /* list name separately */
c6d46f5f
JB
142 logical been_warned; /* set if noticed dup */
143 int lno; /* line number tag is on */
144 long cno; /* character number line starts on */
145 char *pat; /* search pattern */
146 struct nd_st *left, *right; /* left and right sons */
147};
148
149long ftell ();
150typedef struct nd_st NODE;
151
13fde0cd
RS
152logical header_file; /* TRUE if .h file, FALSE o.w. */
153/* boolean "functions" (see init) */
154logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
c6d46f5f
JB
155
156
157char *concat ();
158char *savenstr ();
159char *savestr ();
160char *xmalloc ();
161char *xrealloc ();
31d4b314 162int L_isdef (), L_isquote ();
c6d46f5f
JB
163int PF_funcs ();
164int total_size_of_entries ();
165logical consider_token ();
166logical tail ();
167long readline ();
168void Asm_funcs ();
169void C_entries ();
170void L_funcs ();
171void L_getit ();
172void PAS_funcs ();
173void Scheme_funcs ();
174void TEX_funcs ();
175void add_node ();
176void error ();
177void fatal ();
178void find_entries ();
179void free_tree ();
180void getit ();
181void getline ();
182void init ();
183void initbuffer ();
184void initbuffer ();
185void pfnote ();
186void process_file ();
187void put_entries ();
188void takeprec ();
189
190/*
191 * MACRO
192 * xnew -- allocate storage
193 *
194 * SYNOPSIS
195 * Type *xnew (int n, Type);
196 */
197#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
198\f
199
200
201/*
202 * Symbol table stuff.
203 *
204 * Should probably be implemented with hash table; linked list for now.
205 */
206
207enum sym_type
208{
209 st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
210};
211
212struct stab_entry
213{
214 char *sym;
215 int symlen;
216 enum sym_type type;
217 struct stab_entry *next;
218};
219
220typedef struct stab_entry Stab_entry;
221typedef Stab_entry *Stab;
222
223/*
224 * NAME
225 * Stab, Stab_entry, stab_create, stab_search, stab_find -- symbol table
226 *
227 * SYNOPSIS
228 * Types: Stab, Stab_entry, enum sym_type
229 *
230 * Stab * stab_create ()
231 *
232 * Stab_entry * stab_find (stab, sym)
233 * Stab *stab;
234 * char *sym;
235 *
236 * Stab_entry * stab_search (stab, sym)
237 * Stab *stab;
238 * char *sym;
239 *
240 * DESCRIPTION
241 * stab_create creates a Stab, a symbol table object, and returns a
242 * pointer to it. stab_find finds a symbol in a Stab; it returns a
243 * pointer to the Stab_entry if found, otherwise NULL. stab_search
244 * is like stab_find, except that it creates a new Stab_entry,
245 * initialized with type = st_none, if one did not exist already
246 * (it never returns NULL).
247 *
248 * A Stab_entry is a structure that contains at least the following
249 * members:
250 *
251 * char *name; // must not be modified
252 * enum sym_type type; // should be set
253 *
254 * The type field is initially set to st_none; it should be set to
255 * something else by the caller of stab_search. Other possible values
256 * of an enum sym_type can be added.
257 */
258
259Stab *
260stab_create ()
261{
262 Stab *sp;
263 sp = xnew (1, Stab);
264 *sp = NULL; /* a Stab starts out as a null Stab_entry* */
265 return sp;
266}
267
268Stab_entry *
269stab_find (stab, sym, symlen)
270 Stab *stab;
271 register char *sym;
272 register int symlen;
273{
274 register Stab_entry *se;
275 for (se = *stab; se != NULL; se = se->next)
276 {
277 if (se->symlen == symlen && strneq (se->sym, sym, symlen))
278 return se;
279 }
280
281 return NULL;
282}
283
284Stab_entry *
285stab_search (stab, sym, symlen)
286 register Stab *stab;
287 char *sym;
288 int symlen;
289{
290 register Stab_entry *se;
291 se = stab_find (stab, sym, symlen);
292
293 if (se == NULL)
294 {
295 /* make a new one */
296 se = xnew (1, Stab_entry);
297 se->sym = savenstr (sym, symlen);
298 se->symlen = symlen;
299 se->type = st_none;
300 se->next = *stab;
301 *stab = se;
302 }
303
304 return se;
305}
306
307/*
308 * NAME
309 * stab_type -- type of a symbol table entry
310 *
311 * SYNOPSIS
312 * enum sym_type stab_type (Stab_entry *se);
313 *
314 * WARNING
315 * May evaluate its argument more than once.
316 */
317
318#define stab_type(se) ((se)==NULL ? st_none : (se)->type)
319\f
320
321
322typedef int LINENO;
323
324typedef struct
325{
326 char *p;
327 int len;
c6d46f5f 328 LINENO lineno;
fe0b3356 329 logical named;
c6d46f5f 330} TOKEN;
c6d46f5f 331
13fde0cd 332/* C extensions.
c6d46f5f 333 */
13fde0cd
RS
334#define C_PLPL 0x00001 /* C++ */
335#define C_STAR 0x00003 /* C* */
336#define YACC 0x10000 /* yacc file */
c6d46f5f
JB
337
338char searchar = '/'; /* use /.../ searches */
339
340LINENO lineno; /* line number of current line */
341long charno; /* current character number */
c6d46f5f
JB
342
343long linecharno; /* charno of start of line; not used by C, but
344 * by every other language.
345 */
346
347char *curfile, /* current input file name */
348 *outfile, /* output file */
349 *white = " \f\t\n", /* white chars */
13fde0cd
RS
350 *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
351 /* token starting chars */
352 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
353 /* valid in-token chars */
354 *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
c6d46f5f 355
c6d46f5f
JB
356int append_to_tagfile; /* -a: append to tags */
357int emacs_tags_format; /* emacs style output (no -e option any more) */
358/* The following three default to 1 for etags, but to 0 for ctags. */
359int typedefs; /* -t: create tags for typedefs */
360int typedefs_and_cplusplus; /* -T: create tags for typedefs, level */
361 /* 0 struct/enum/union decls, and C++ */
362 /* member functions */
363int constantypedefs; /* -d: create tags for C #define and enum */
364 /* constants. Default under etags. Enum */
365 /* constants not implemented. */
366 /* -D: opposite of -d. Default under ctags. */
367int update; /* -u: update tags */
368int vgrind_style; /* -v: create vgrind style index output */
369int no_warnings; /* -w: suppress warnings */
370int cxref_style; /* -x: create cxref style output */
371int cplusplus; /* .[hc] means C++, not C */
372int noindentypedefs; /* -S: ignore indentation in C */
c6d46f5f
JB
373
374/* Name this program was invoked with. */
375char *progname;
376
4746118a
JB
377struct option longopts[] = {
378 { "append", no_argument, NULL, 'a' },
379 { "backward-search", no_argument, NULL, 'B' },
380 { "c++", no_argument, NULL, 'C' },
381 { "cxref", no_argument, NULL, 'x' },
382 { "defines", no_argument, NULL, 'd' },
383 { "forward-search", no_argument, NULL, 'F' },
384 { "help", no_argument, NULL, 'H' },
385 { "ignore-indentation", no_argument, NULL, 'S' },
386 { "include", required_argument, NULL, 'i' },
387 { "no-defines", no_argument, NULL, 'D' },
388 { "no-warn", no_argument, NULL, 'w' },
389 { "output", required_argument, NULL, 'o' },
390 { "typedefs", no_argument, NULL, 't' },
391 { "typedefs-and-c++", no_argument, NULL, 'T' },
392 { "update", no_argument, NULL, 'u' },
393 { "version", no_argument, NULL, 'V' },
394 { "vgrind", no_argument, NULL, 'v' },
395 { 0 }
396};
397
c6d46f5f
JB
398FILE *inf, /* ioptr for current input file */
399 *outf; /* ioptr for tags file */
400
401NODE *head; /* the head of the binary tree of tags */
402
403int permit_duplicates = 1; /* Nonzero means allow duplicate tags. */
404
405/* A `struct linebuffer' is a structure which holds a line of text.
406 `readline' reads a line from a stream into a linebuffer
407 and works regardless of the length of the line. */
408
409struct linebuffer
410{
411 long size;
412 char *buffer;
413};
414
415struct linebuffer lb; /* the current line */
c6d46f5f 416struct linebuffer filename_lb; /* used to read in filenames */
13fde0cd
RS
417struct
418{
419 FILEPOS linepos;
420 struct linebuffer lb; /* used by C_entries instead of lb */
421} lbs[2];
c6d46f5f 422\f
4746118a
JB
423void
424print_version ()
425{
426#ifdef CTAGS
427 printf ("CTAGS ");
428#ifdef ETAGS
429 printf ("and ");
430#endif
431#endif
432#ifdef ETAGS
433 printf ("ETAGS ");
434#endif
435 printf ("for Emacs version 19.0.\n");
436
437 exit (0);
438}
439
440void
441print_help ()
442{
443 printf ("These are the options accepted by %s. You may use unambiguous\n\
444abbreviations for the long option names.\n\n", progname);
445
52cc7c59
JB
446 puts ("-a, --append\n\
447 Append tag entries to existing tags file.");
448 puts ("-C, --c++\n\
4746118a
JB
449 Treat files with `.c' and `.h' extensions as C++ code, not C\n\
450 code. Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
52cc7c59
JB
451 extensions are always assumed to be C++ code.");
452 fputs ("-d, --defines\n\
4746118a
JB
453 Create tag entries for #defines, too.", stdout);
454
455#ifdef ETAGS
456 fputs (" This is the default\n\
457 behavior.", stdout);
458#endif
459
460 fputs ("\n\
461-D, --no-defines\n\
462 Don't create tag entries for #defines.", stdout);
463
464#ifdef CTAGS
465 fputs (" This is the default\n\
466 behavior.", stdout);
467#endif
468
469 puts ("\n\
470-o FILE, --output=FILE\n\
471 Write the tags to FILE.\n\
472-S, --ignore-indentation\n\
473 Don't rely on indentation quite as much as normal. Currently,\n\
474 this means not to assume that a closing brace in the first\n\
475 column is the final brace of a function or structure\n\
52cc7c59
JB
476 definition.");
477 puts ("-t, --typedefs\n\
4746118a 478 Generate tag entries for typedefs. This is the default\n\
52cc7c59
JB
479 behavior.");
480 puts ("-T, --typedefs-and-c++\n\
4746118a
JB
481 Generate tag entries for typedefs, struct/enum/union tags, and\n\
482 C++ member functions.");
483
484#ifdef ETAGS
485 puts ("-i FILE, --include=FILE\n\
486 Include a note in tag file indicating that, when searching for\n\
487 a tag, one should also consult the tags file FILE after\n\
488 checking the current file.");
489#endif
490
491#ifdef CTAGS
492 puts ("-B, --backward-search\n\
493 Write the search commands for the tag entries using '?', the\n\
52cc7c59
JB
494 backward-search command.");
495 puts ("-F, --forward-search\n\
4746118a 496 Write the search commands for the tag entries using '/', the\n\
52cc7c59
JB
497 forward-search command.");
498 puts ("-u, --update\n\
4746118a
JB
499 Update the tag entries for the given files, leaving tag\n\
500 entries for other files in place. Currently, this is\n\
501 implemented by deleting the existing entries for the given\n\
502 files and then rewriting the new entries at the end of the\n\
503 tags file. It is often faster to simply rebuild the entire\n\
52cc7c59
JB
504 tag file than to use this.");
505 puts ("-v, --vgrind\n\
4746118a
JB
506 Generates an index of items intended for human consumption,\n\
507 similar to the output of vgrind. The index is sorted, and\n\
52cc7c59
JB
508 gives the page number of each item.");
509 puts ("-x, --cxref\n\
4746118a
JB
510 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
511 The output uses line numbers instead of page numbers, but\n\
512 beyond that the differences are cosmetic; try both to see\n\
52cc7c59
JB
513 which you like.");
514 puts ("-w, --no-warn\n\
4746118a
JB
515 Suppress warning messages about entries defined in multiple\n\
516 files.");
517#endif
518
519 puts ("-V, --version\n\
520 Print the version of the program.\n\
521-H, --help\n\
522 Print this help message.");
523
524 exit (0);
525}
526
527\f
c6d46f5f
JB
528void
529main (argc, argv)
530 int argc;
531 char *argv[];
532{
533 char cmd[100];
534 int i;
1e134a5f 535 unsigned int nincluded_files = 0;
72a339d7 536 char **included_files = xnew (argc, char *);
c6d46f5f
JB
537 char *this_file;
538#ifdef VMS
539 char got_err;
540
541 extern char *gfnames ();
542 extern char *massage_name ();
543#endif
544
545 progname = argv[0];
546
547#ifndef CTAGS
548 emacs_tags_format = 1;
549#else
550 emacs_tags_format = 0;
551#endif
552
553 /*
554 * If etags, always find typedefs and structure tags. Why not?
555 * Also default is to find macro constants.
556 */
557 if (emacs_tags_format)
558 typedefs = typedefs_and_cplusplus = constantypedefs = 1;
559
4746118a 560 for (;;)
c6d46f5f 561 {
4746118a 562 int opt;
3ed79319 563 opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0);
4746118a
JB
564
565 if (opt == EOF)
566 break;
567
568 switch (opt)
c6d46f5f 569 {
4746118a
JB
570 case '\0':
571 /* If getopt returns '\0', then it has already processed a
572 long-named option. We should do nothing. */
573 break;
574
575 /* Common options. */
576 case 'a':
577 append_to_tagfile++;
578 break;
579 case 'C':
580 cplusplus = 1;
581 break;
582 case 'd':
583 constantypedefs = 1;
584 break;
585 case 'D':
586 constantypedefs = 0;
587 break;
3ed79319 588 case 'f':
4746118a
JB
589 case 'o':
590 if (outfile)
c6d46f5f 591 {
4746118a 592 fprintf (stderr,
3ed79319 593 "%s: -%c flag may only be given once\n", progname, opt);
c6d46f5f
JB
594 goto usage;
595 }
4746118a
JB
596 outfile = optarg;
597 break;
598 case 'S':
599 noindentypedefs++;
600 break;
601 case 't':
602 typedefs++;
603 break;
604 case 'T':
605 typedefs++;
606 typedefs_and_cplusplus++;
607 break;
608 case 'V':
609 print_version ();
610 break;
611 case 'H':
612 print_help ();
613 break;
614
615 /* Etags options */
616 case 'i':
617 if (!emacs_tags_format)
618 goto usage;
619 included_files[nincluded_files++] = optarg;
620 break;
621
622 /* Ctags options. */
623 case 'B':
624 searchar = '?';
625 if (emacs_tags_format)
626 goto usage;
627 break;
628 case 'F':
629 searchar = '/';
630 if (emacs_tags_format)
631 goto usage;
632 break;
633 case 'u':
634 update++;
635 if (emacs_tags_format)
636 goto usage;
637 break;
638 case 'v':
639 vgrind_style++;
640 /*FALLTHRU*/
641 case 'x':
642 cxref_style++;
643 if (emacs_tags_format)
644 goto usage;
645 break;
646 case 'w':
647 no_warnings++;
648 if (emacs_tags_format)
649 goto usage;
650 break;
651
652 default:
653 goto usage;
c6d46f5f 654 }
c6d46f5f
JB
655 }
656
0e5ad25f 657 if (optind == argc && nincluded_files == 0)
c6d46f5f 658 {
4746118a
JB
659 fprintf (stderr, "%s: No input files specified.\n", progname);
660
c6d46f5f 661 usage:
0e5ad25f 662 fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
4746118a 663 progname, progname);
c6d46f5f
JB
664 exit (BAD);
665 }
666
667 if (outfile == 0)
668 {
669 outfile = emacs_tags_format ? "TAGS" : "tags";
670 }
671
672 init (); /* set up boolean "functions" */
673
674 initbuffer (&lb);
13fde0cd
RS
675 initbuffer (&lbs[0].lb);
676 initbuffer (&lbs[1].lb);
c6d46f5f
JB
677 initbuffer (&filename_lb);
678 /*
679 * loop through files finding functions
680 */
681 if (emacs_tags_format)
682 {
683 if (streq (outfile, "-"))
684 outf = stdout;
685 else
686 outf = fopen (outfile, append_to_tagfile ? "a" : "w");
687 if (!outf)
688 {
689 perror (outfile);
690 exit (1);
691 }
692 }
693
c6d46f5f 694#ifdef VMS
4746118a
JB
695 argc -= optind;
696 argv += optind;
697 while (gfnames (&argc, &argv, &got_err) != NULL)
c6d46f5f
JB
698 {
699 if (got_err)
700 {
701 error ("Can't find file %s\n", this_file);
702 argc--, argv++;
703 }
704 else
705 {
706 this_file = massage_name (this_file);
707#if 0
708 }
13fde0cd 709 } /* solely to balance out the ifdef'd parens above */
c6d46f5f
JB
710#endif
711#else
4746118a 712 for (; optind < argc; optind++)
c6d46f5f 713 {
4746118a 714 this_file = argv[optind];
c6d46f5f
JB
715 if (1)
716 {
717#endif
718 /* Input file named "-" means read file names from stdin
719 and use them. */
720 if (streq (this_file, "-"))
721 {
722 while (!feof (stdin))
723 {
724 (void) readline (&filename_lb, stdin);
725 if (strlen (filename_lb.buffer) > 0)
726 process_file (filename_lb.buffer);
727 }
728 }
729 else
730 process_file (this_file);
731 }
732 }
733
734 if (emacs_tags_format)
735 {
1e134a5f
RM
736 while (nincluded_files-- > 0)
737 fprintf (outf, "\f\n%s,include\n", *included_files++);
738
c6d46f5f
JB
739 (void) fclose (outf);
740 exit (0);
741 }
742
743 if (cxref_style)
744 {
745 put_entries (head);
746 exit (GOOD);
747 }
4746118a 748 if (update)
c6d46f5f 749 {
4746118a
JB
750 /* update cannot be set under VMS, so we may assume that argc
751 and argv have not been munged. */
752 for (i = optind; i < argc; i++)
c6d46f5f
JB
753 {
754 sprintf (cmd,
755 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
756 outfile, argv[i], outfile);
757 (void) system (cmd);
758 }
759 append_to_tagfile++;
760 }
761 outf = fopen (outfile, append_to_tagfile ? "a" : "w");
762 if (outf == NULL)
763 {
764 perror (outfile);
765 exit (GOOD);
766 }
767 put_entries (head);
768 (void) fclose (outf);
769 if (update)
770 {
771 sprintf (cmd, "sort %s -o %s", outfile, outfile);
772 (void) system (cmd);
773 }
774 exit (GOOD);
775}
776
777
778/*
779 * This routine is called on each file argument.
780 */
781void
782process_file (file)
783 char *file;
784{
785 struct stat stat_buf;
786
787 stat (file, &stat_buf);
8a6c8bcf
RS
788 if (!(stat_buf.st_mode & S_IFREG)
789#ifdef S_IFLNK
790 || !(stat_buf.st_mode & S_IFLNK)
791#endif
792 )
c6d46f5f
JB
793 {
794 fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
795 return;
796 }
797
798 if (streq (file, outfile) && !streq (outfile, "-"))
799 {
800 fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
801 return;
802 }
c6d46f5f
JB
803 if (emacs_tags_format)
804 {
8a6c8bcf 805 char *cp = etags_rindex (file, '/');
c6d46f5f
JB
806 if (cp)
807 ++cp;
808 else
809 cp = file;
c6d46f5f
JB
810 }
811 find_entries (file);
812 if (emacs_tags_format)
813 {
814 fprintf (outf, "\f\n%s,%d\n",
815 file, total_size_of_entries (head));
816 put_entries (head);
817 free_tree (head);
818 head = NULL;
819 }
820}
821
822/*
eb8c3be9 823 * This routine sets up the boolean pseudo-functions which work
99e0a2e0 824 * by setting boolean flags dependent upon the corresponding character
c6d46f5f
JB
825 * Every char which is NOT in that string is not a white char. Therefore,
826 * all of the array "_wht" is set to FALSE, and then the elements
827 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
828 * of a char is TRUE if it is the string "white", else FALSE.
829 */
830void
831init ()
832{
13fde0cd
RS
833 register char *sp;
834 register int i;
c6d46f5f
JB
835
836 for (i = 0; i < 0177; i++)
13fde0cd 837 _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
c6d46f5f
JB
838 for (sp = white; *sp; sp++)
839 _wht[*sp] = TRUE;
840 for (sp = endtk; *sp; sp++)
841 _etk[*sp] = TRUE;
842 for (sp = intk; *sp; sp++)
843 _itk[*sp] = TRUE;
844 for (sp = begtk; *sp; sp++)
845 _btk[*sp] = TRUE;
c6d46f5f
JB
846 _wht[0] = _wht['\n'];
847 _etk[0] = _etk['\n'];
848 _btk[0] = _btk['\n'];
849 _itk[0] = _itk['\n'];
c6d46f5f
JB
850}
851
852/*
853 * This routine opens the specified file and calls the function
854 * which finds the function and type definitions.
855 */
856void
857find_entries (file)
858 char *file;
859{
860 char *cp;
861 void prolog_funcs ();
862
863 inf = fopen (file, "r");
864 if (inf == NULL)
865 {
866 perror (file);
867 return;
868 }
869 curfile = savestr (file);
8a6c8bcf 870 cp = etags_rindex (file, '.');
c6d46f5f
JB
871
872 header_file = (cp && (streq (cp + 1, "h")));
873
874 /* .tex, .aux or .bbl implies LaTeX source code */
875 if (cp && (streq (cp + 1, "tex") || streq (cp + 1, "aux")
876 || streq (cp + 1, "bbl")))
877 {
878 TEX_funcs (inf);
879 goto close_and_return;
880 }
881 /* .l or .el or .lisp (or .cl or .clisp or ...) implies lisp source code */
882 if (cp && (streq (cp + 1, "l")
883 || streq (cp + 1, "el")
884 || streq (cp + 1, "lsp")
885 || streq (cp + 1, "lisp")
886 || streq (cp + 1, "cl")
887 || streq (cp + 1, "clisp")))
888 {
889 L_funcs (inf);
890 goto close_and_return;
891 }
892 /* .scm or .sm or .scheme or ... implies scheme source code */
893 if (cp && (streq (cp + 1, "sm")
894 || streq (cp + 1, "scm")
895 || streq (cp + 1, "scheme")
896 || streq (cp + 1, "t")
897 || streq (cp + 1, "sch")
898 || streq (cp + 1, "SM")
899 || streq (cp + 1, "SCM")
900 /* The `SCM' or `scm' prefix with a version number */
901 || (cp[-1] == 'm' && cp[-2] == 'c' && cp[-3] == 's'
902 && string_numeric_p (cp + 1))
903 || (cp[-1] == 'M' && cp[-2] == 'C' && cp[-3] == 'S'
904 && string_numeric_p (cp + 1))))
905 {
906 Scheme_funcs (inf);
907 fclose (inf);
908 return;
909 }
13fde0cd
RS
910 /* Assume that ".s" or ".a" is assembly code. -wolfgang.
911 Or even ".sa". */
912 if (cp && (streq (cp + 1, "s")
913 || streq (cp + 1, "a")
914 || streq (cp + 1, "sa")))
c6d46f5f
JB
915 {
916 Asm_funcs (inf);
917 fclose (inf);
918 return;
919 }
920 /* .C or .H or .cxx or .hxx or .cc: a C++ file */
921 if (cp && (streq (cp + 1, "C")
922 || streq (cp + 1, "H")
923 || streq (cp + 1, "cxx")
924 || streq (cp + 1, "hxx")
925 || streq (cp + 1, "cc")))
926 {
927 C_entries (C_PLPL); /* C++ */
928 goto close_and_return;
929 }
930 /* .cs or .hs: a C* file */
13fde0cd
RS
931 if (cp && (streq (cp + 1, "cs")
932 || streq (cp + 1, "hs")))
c6d46f5f
JB
933 {
934 C_entries (C_STAR);
935 goto close_and_return;
936 }
13fde0cd
RS
937 /* .y: a yacc file */
938 if (cp && (streq (cp + 1, "y")))
939 {
940 C_entries (YACC);
941 goto close_and_return;
942 }
c6d46f5f 943 /* .pl implies prolog source code */
13fde0cd 944 if (cp && streq (cp + 1, "pl"))
c6d46f5f
JB
945 {
946 prolog_funcs (inf);
947 goto close_and_return;
948 }
949 /* .p or .pas: a Pascal file */
950 if (cp && (streq (cp + 1, "p")
951 || streq (cp + 1, "pas")))
952 {
953 PAS_funcs (inf);
954 goto close_and_return;
955 }
1e8e1162 956 /* If .f or .for, assume it is fortran or nothing. */
13fde0cd
RS
957 if (cp && (streq (cp + 1, "f")
958 || streq (cp + 1, "for")))
1e8e1162
RS
959 {
960 PF_funcs (inf);
961 goto close_and_return;
962 }
c6d46f5f 963 /* if not a .c or .h or .y file, try fortran */
1e8e1162
RS
964 if (cp && ((cp[1] != 'c'
965 && cp[1] != 'h'
966 && cp[1] != 'y')
967 || (cp[1] != 0 && cp[2] != 0)))
c6d46f5f
JB
968 {
969 if (PF_funcs (inf) != 0)
970 goto close_and_return;
971 rewind (inf); /* no fortran tags found, try C */
972 }
973 C_entries (cplusplus ? C_PLPL : 0);
974
975close_and_return:
976 (void) fclose (inf);
977}
978
979/* Nonzero if string STR is composed of digits. */
980
981int
982string_numeric_p (str)
983 char *str;
984{
985 while (*str)
986 {
987 if (*str < '0' || *str > '9')
988 return 0;
989 }
990 return 1;
991}
992\f
993/* Record a tag. */
994/* Should take a TOKEN* instead!! */
c6d46f5f 995void
fe0b3356 996pfnote (name, is_func, named, linestart, linelen, lno, cno)
c6d46f5f
JB
997 char *name; /* tag name */
998 logical is_func; /* function or type name? */
fe0b3356 999 logical named; /* tag different from text of definition? */
c6d46f5f
JB
1000 char *linestart;
1001 int linelen;
1002 int lno;
1003 long cno;
1004{
1005 register char *fp;
1006 register NODE *np;
1007 char tem[51];
1008 char c;
1009
1010 np = (NODE *) malloc (sizeof (NODE));
1011 if (np == NULL)
1012 {
1013 if (!emacs_tags_format)
1014 {
1015 /* It's okay to output early in etags -- it only disrupts the
1016 * character count of the tag entries, which is no longer used
1017 * by tags.el anyway.
1018 */
1019 error ("too many entries to sort");
1020 }
1021 put_entries (head);
1022 free_tree (head);
1023 head = NULL;
1024 np = xnew (1, NODE);
1025 }
1026 /* If ctags mode, change name "main" to M<thisfilename>. */
1027 if (!emacs_tags_format && !cxref_style && streq (name, "main"))
1028 {
8a6c8bcf 1029 fp = etags_rindex (curfile, '/');
c6d46f5f 1030 name = concat ("M", fp == 0 ? curfile : fp + 1, "");
8a6c8bcf 1031 fp = etags_rindex (name, '.');
c6d46f5f
JB
1032 if (fp && fp[1] != '\0' && fp[2] == '\0')
1033 *fp = 0;
fe0b3356 1034 named = TRUE;
c6d46f5f
JB
1035 }
1036 np->name = savestr (name);
1037 np->file = curfile;
1038 np->is_func = is_func;
fe0b3356 1039 np->named = named;
c6d46f5f
JB
1040 np->lno = lno;
1041 /* UNCOMMENT THE +1 HERE: */
1042 np->cno = cno /* + 1 */ ; /* our char numbers are 0-base; emacs's are 1-base */
1043 np->left = np->right = 0;
1044 if (emacs_tags_format)
1045 {
1046 c = linestart[linelen];
1047 linestart[linelen] = 0;
1048 }
1049 else if (cxref_style == 0)
1050 {
1051 sprintf (tem, strlen (linestart) < 50 ? "%s$" : "%.50s", linestart);
1052 linestart = tem;
1053 }
1054 np->pat = savestr (linestart);
1055 if (emacs_tags_format)
1056 {
1057 linestart[linelen] = c;
1058 }
1059
1060 add_node (np, &head);
1061}
1062
1063/*
1064 * free_tree ()
1065 * recurse on left children, iterate on right children.
1066 */
1067void
1068free_tree (node)
1069 register NODE *node;
1070{
1071 while (node)
1072 {
1073 register NODE *node_right = node->right;
1074 free_tree (node->left);
1075 free (node->name);
1076 free (node->pat);
1077 free ((char *) node);
1078 node = node_right;
1079 }
1080}
1081
1082/*
1083 * add_node ()
1084 * Adds a node to the tree of nodes. In etags mode, we don't keep
1085 * it sorted; we just keep a linear list. In ctags mode, maintain
1086 * an ordered tree, with no attempt at balancing.
1087 *
1088 * add_node is the only function allowed to add nodes, so it can
1089 * maintain state.
1090 */
8f53e1ee
RS
1091/* Must avoid static vars within functions since some systems
1092 #define static as nothing. */
1093static NODE *last_node = NULL;
1094
c6d46f5f
JB
1095void
1096add_node (node, cur_node_p)
1097 NODE *node, **cur_node_p;
1098{
1099 register int dif;
1100 register NODE *cur_node = *cur_node_p;
c6d46f5f
JB
1101
1102 if (cur_node == NULL)
1103 {
1104 *cur_node_p = node;
1105 last_node = node;
1106 return;
1107 }
1108
1109 if (emacs_tags_format)
1110 {
1111 /* Etags Mode */
1112 if (!last_node)
1113 fatal ("internal error in add_node");
1114 last_node->right = node;
1115 last_node = node;
1116 }
1117 else
1118 {
1119 /* Ctags Mode */
1120 dif = strcmp (node->name, cur_node->name);
1121
1122 /*
1123 * If this tag name matches an existing one, then
1124 * do not add the node, but maybe print a warning.
1125 */
1126 if (!dif)
1127 {
1128 if (node->file == cur_node->file)
1129 {
1130 if (!no_warnings)
1131 {
1132 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1133 node->file, lineno, node->name);
1134 fprintf (stderr, "Second entry ignored\n");
1135 }
1136 return;
1137 }
1138 if (!cur_node->been_warned && !no_warnings)
1139 {
1140 fprintf (stderr,
1141 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1142 node->file, cur_node->file, node->name);
1143 }
1144 cur_node->been_warned = TRUE;
1145 return;
1146 }
1147
1148 /* Maybe refuse to add duplicate nodes. */
1149 if (!permit_duplicates)
1150 {
1151 if (!strcmp (node->name, cur_node->name)
1152 && !strcmp (node->file, cur_node->file))
1153 return;
1154 }
1155
1156 /* Actually add the node */
1157 add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
1158 }
1159}
1160\f
1161void
1162put_entries (node)
13fde0cd 1163 register NODE *node;
c6d46f5f 1164{
13fde0cd 1165 register char *sp;
c6d46f5f
JB
1166
1167 if (node == NULL)
1168 return;
1169
1170 /* Output subentries that precede this one */
1171 put_entries (node->left);
1172
1173 /* Output this entry */
1174
1175 if (emacs_tags_format)
1176 {
fe0b3356 1177 if (node->named)
c6d46f5f
JB
1178 {
1179 fprintf (outf, "%s\177%s\001%d,%d\n",
cc6d6e58
RM
1180 node->pat, node->name,
1181 node->lno, node->cno);
c6d46f5f
JB
1182 }
1183 else
1184 {
1185 fprintf (outf, "%s\177%d,%d\n",
cc6d6e58
RM
1186 node->pat,
1187 node->lno, node->cno);
c6d46f5f
JB
1188 }
1189 }
1190 else if (!cxref_style)
1191 {
1192 fprintf (outf, "%s\t%s\t",
1193 node->name, node->file);
1194
1195 if (node->is_func)
1196 { /* a function */
1197 putc (searchar, outf);
1198 putc ('^', outf);
1199
1200 for (sp = node->pat; *sp; sp++)
1201 {
1202 if (*sp == '\\' || *sp == searchar)
1203 putc ('\\', outf);
1204 putc (*sp, outf);
1205 }
1206 putc (searchar, outf);
1207 }
1208 else
1209 { /* a typedef; text pattern inadequate */
1210 fprintf (outf, "%d", node->lno);
1211 }
1212 putc ('\n', outf);
1213 }
1214 else if (vgrind_style)
1215 fprintf (stdout, "%s %s %d\n",
1216 node->name, node->file, (node->lno + 63) / 64);
1217 else
daa37602 1218 fprintf (stdout, "%-16s %3d %-16s %s\n",
c6d46f5f
JB
1219 node->name, node->lno, node->file, node->pat);
1220
1221 /* Output subentries that follow this one */
1222 put_entries (node->right);
1223}
1224
1225/* Length of a number's decimal representation. */
1226int
1227number_len (num)
1228 long num;
1229{
1230 int len = 0;
1231 if (!num)
1232 return 1;
1233 for (; num; num /= 10)
1234 ++len;
1235 return len;
1236}
1237
1238/*
1239 * Return total number of characters that put_entries will output for
1240 * the nodes in the subtree of the specified node. Works only if emacs_tags_format
1241 * is set, but called only in that case. This count is irrelevant with
1242 * the new tags.el, but is still supplied for backward compatibility.
1243 */
1244int
1245total_size_of_entries (node)
13fde0cd 1246 register NODE *node;
c6d46f5f 1247{
13fde0cd 1248 register int total;
c6d46f5f
JB
1249
1250 if (node == NULL)
1251 return 0;
1252
1253 total = 0;
1254 for (; node; node = node->right)
1255 {
1256 /* Count left subentries. */
1257 total += total_size_of_entries (node->left);
1258
1259 /* Count this entry */
1260 total += strlen (node->pat) + 1;
1261 total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
fe0b3356 1262 if (node->named)
c6d46f5f
JB
1263 total += 1 + strlen (node->name); /* \001name */
1264 }
1265
1266 return total;
1267}
1268\f
1269/*
1270 * The C symbol tables.
1271 */
1272
1273Stab *C_stab, *C_PLPL_stab, *C_STAR_stab;
1274
1275/*
1276 * SYNOPSIS
1277 * Stab *get_C_stab (int c_ext);
1278 */
13fde0cd
RS
1279#define get_C_stab(c_ext) ((c_ext & C_STAR) ? C_STAR_stab : \
1280 (c_ext & C_PLPL) ? C_PLPL_stab : \
c6d46f5f
JB
1281 C_stab)
1282
1283void
1284add_keyword (stab, sym, type)
1285 Stab *stab;
1286 char *sym;
1287 enum sym_type type;
1288{
1289 stab_search (stab, sym, strlen (sym))->type = type;
1290}
1291
1292Stab *
1293C_create_stab (c_ext)
1294 int c_ext;
1295{
1296 Stab *stab;
1297
1298 stab = stab_create ();
1299
1300 /* C, C++ and C* */
1301 if (c_ext & C_PLPL)
1302 add_keyword (stab, "class", st_C_struct);
1303 if (c_ext & C_STAR)
1304 add_keyword (stab, "domain", st_C_struct);
1305 add_keyword (stab, "union", st_C_struct);
1306 add_keyword (stab, "struct", st_C_struct);
1307 add_keyword (stab, "enum", st_C_enum);
1308 add_keyword (stab, "typedef", st_C_typedef);
1309 add_keyword (stab, "define", st_C_define);
1310 add_keyword (stab, "long", st_C_typespec);
1311 add_keyword (stab, "short", st_C_typespec);
1312 add_keyword (stab, "int", st_C_typespec);
1313 add_keyword (stab, "char", st_C_typespec);
1314 add_keyword (stab, "float", st_C_typespec);
1315 add_keyword (stab, "double", st_C_typespec);
1316 add_keyword (stab, "signed", st_C_typespec);
1317 add_keyword (stab, "unsigned", st_C_typespec);
13fde0cd
RS
1318 add_keyword (stab, "auto", st_C_typespec);
1319 add_keyword (stab, "void", st_C_typespec);
1320 add_keyword (stab, "extern", st_C_typespec);
1321 add_keyword (stab, "static", st_C_typespec);
c6d46f5f
JB
1322 add_keyword (stab, "const", st_C_typespec);
1323 add_keyword (stab, "volatile", st_C_typespec);
1324
1325 return stab;
1326}
1327
1328void
1329C_create_stabs ()
1330{
1331 C_stab = C_create_stab (0);
1332 C_PLPL_stab = C_create_stab (C_PLPL);
1333 C_STAR_stab = C_create_stab (C_STAR | C_PLPL);
1334}
1335\f
13fde0cd 1336 /*
13fde0cd
RS
1337 * C functions are recognized using a simple finite automaton.
1338 * funcdef is its state variable.
1339 */
1340typedef enum
1341{
31d4b314
FP
1342 fnone, /* nothing seen */
1343 ftagseen, /* function-like tag seen */
1344 finlist, /* in parameter list */
1345 flistseen, /* after parameter list */
1346 fignore, /* before open brace */
13fde0cd
RS
1347} FUNCST;
1348FUNCST funcdef;
1349
1350
1351 /* typedefs are recognized using a simple finite automaton.
1352 * typeddef is its state variable.
1353 */
1354typedef enum
1355{
31d4b314
FP
1356 tnone, /* nothing seen */
1357 ttypedseen, /* typedef keyword seen */
1358 tinbody, /* inside typedef body */
1359 tend, /* just before typedef tag */
13fde0cd
RS
1360} TYPEDST;
1361TYPEDST typdef;
1362
1363
1364 /* struct tags for C++ are recognized using another simple
1365 * finite automaton. `structdef' is its state variable.
1366 * This machinery is only invoked for C++; otherwise structdef
1367 * should remain snone. However, this machinery can easily be
1368 * adapted to find structure tags in normal C code.
1369 */
1370typedef enum
1371{
1372 snone, /* nothing seen yet */
1373 skeyseen, /* struct-like keyword seen */
1374 stagseen, /* struct-like tag seen */
1375 scolonseen, /* colon seen after struct-like tag */
31d4b314 1376 sinbody, /* in struct body: recognize member func defs*/
13fde0cd
RS
1377} STRUCTST;
1378STRUCTST structdef;
1379/*
1380 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
1381 * struct tag, and structkey is the preceding struct-like keyword.
1382 */
1383char structtag[BUFSIZ];
1384Stab_entry *structkey;
1385
1386/*
1387 * Yet another little state machine to deal with preprocessor lines.
1388 */
1389typedef enum
1390{
1391 dnone, /* nothing seen */
1392 dsharpseen, /* '#' seen as first char on line */
1393 ddefineseen, /* '#' and 'define' seen */
31d4b314 1394 dignorerest, /* ignore rest of line */
13fde0cd
RS
1395} DEFINEST;
1396DEFINEST definedef;
1397
1398/*
1399 * Set this to TRUE, and the next token considered is called a function.
1400 * Used only for GNUmacs's function-defining macros.
1401 */
1402logical next_token_is_func;
1403
1404/*
1405 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
1406 */
1407logical yacc_rules;
1408
c6d46f5f
JB
1409/*
1410 * C_entries ()
13fde0cd
RS
1411 * This routine finds functions, typedefs, #define's and
1412 * struct/union/enum definitions in C syntax and adds them
c6d46f5f
JB
1413 * to the list.
1414 */
1415
13fde0cd
RS
1416#define curlb (lbs[curndx].lb)
1417#define othlb (lbs[1-curndx].lb)
1418#define newlb (lbs[newndx].lb)
1419#define curlinepos (lbs[curndx].linepos)
1420#define othlinepos (lbs[1-curndx].linepos)
1421#define newlinepos (lbs[newndx].linepos)
1422
c6d46f5f 1423#define CNL_SAVE_DEFINEDEF \
13fde0cd
RS
1424do { \
1425 SET_FILEPOS (curlinepos, inf, charno); \
c6d46f5f 1426 lineno++; \
13fde0cd
RS
1427 charno += readline (&curlb, inf); \
1428 lp = curlb.buffer; \
1429 quotednl = FALSE; \
1430 newndx = curndx; \
1431} while (FALSE)
c6d46f5f
JB
1432
1433#define CNL \
13fde0cd 1434do { \
c6d46f5f
JB
1435 CNL_SAVE_DEFINEDEF; \
1436 definedef = dnone; \
13fde0cd
RS
1437} while (FALSE)
1438
fe0b3356 1439#define MAKE_TAG_FROM_NEW_LB(isfun) pfnote (nameb, isfun, tok.named, \
13fde0cd 1440 newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
fe0b3356 1441#define MAKE_TAG_FROM_OTH_LB(isfun) pfnote (nameb, isfun, tok.named, \
13fde0cd 1442 othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
c6d46f5f
JB
1443
1444void
1445C_entries (c_ext)
1446 int c_ext; /* extension of C? */
1447{
13fde0cd 1448 register char c; /* latest char read; '\0' for end of line */
c6d46f5f 1449 register char *lp; /* pointer one beyond the character `c' */
13fde0cd
RS
1450 int curndx, newndx; /* indices for current and new lb */
1451 TOKEN tok; /* latest token read for funcdef & structdef */
fe0b3356 1452 char nameb[BUFSIZ]; /* latest token name for funcdef & structdef */
13fde0cd
RS
1453 register int tokoff; /* offset in line of start of latest token */
1454 register int toklen; /* length of latest token */
591fa824 1455 int cblev; /* current curly brace level */
13fde0cd
RS
1456 logical incomm, inquote, inchar, quotednl, midtoken;
1457 logical cplpl;
c6d46f5f 1458
13fde0cd 1459 curndx = newndx = 0;
c6d46f5f
JB
1460 lineno = 0;
1461 charno = 0;
13fde0cd 1462 lp = curlb.buffer;
c6d46f5f
JB
1463 *lp = 0;
1464
13fde0cd
RS
1465 definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
1466 next_token_is_func = yacc_rules = FALSE;
1467 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1468 cblev = 0;
13fde0cd 1469 cplpl = c_ext & C_PLPL;
c6d46f5f
JB
1470
1471 C_create_stabs ();
1472
1473 while (!feof (inf))
1474 {
1475 c = *lp++;
c6d46f5f
JB
1476 if (c == '\\')
1477 {
4746118a
JB
1478 /* If we're at the end of the line, the next character is a
1479 '\0'; don't skip it, because it's the thing that tells us
1480 to read the next line. */
13fde0cd 1481 if (*lp == '\0')
99e0a2e0 1482 {
13fde0cd 1483 quotednl = TRUE;
99e0a2e0
RS
1484 continue;
1485 }
1e134a5f 1486 lp++;
c6d46f5f
JB
1487 c = ' ';
1488 }
1489 else if (incomm)
1490 {
13fde0cd 1491 switch (c)
c6d46f5f 1492 {
13fde0cd
RS
1493 case '*':
1494 if (*lp == '/')
1495 {
1496 c = *lp++;
1497 incomm = FALSE;
1498 }
1499 break;
1500 case '\0':
1501 /* Newlines inside comments do not end macro definitions in
1502 traditional cpp. */
1503 CNL_SAVE_DEFINEDEF;
1504 break;
c6d46f5f 1505 }
13fde0cd 1506 continue;
c6d46f5f
JB
1507 }
1508 else if (inquote)
1509 {
13fde0cd
RS
1510 switch (c)
1511 {
1512 case '"':
1513 inquote = FALSE;
1514 break;
1515 case '\0':
1516 /* Newlines inside strings, do not end macro definitions
1517 in traditional cpp, even though compilers don't
1518 usually accept them. */
1519 CNL_SAVE_DEFINEDEF;
1520 break;
1521 }
1522 continue;
c6d46f5f
JB
1523 }
1524 else if (inchar)
1525 {
1526 if (c == '\'')
1527 inchar = FALSE;
1528 continue;
1529 }
13fde0cd 1530 else
c6d46f5f
JB
1531 switch (c)
1532 {
1533 case '"':
1534 inquote = TRUE;
1535 continue;
1536 case '\'':
1537 inchar = TRUE;
1538 continue;
1539 case '/':
1540 if (*lp == '*')
1541 {
1542 lp++;
1543 incomm = TRUE;
13fde0cd 1544 continue;
c6d46f5f 1545 }
13fde0cd 1546 else if (cplpl && *lp == '/')
c6d46f5f 1547 {
daa37602
JB
1548 c = 0;
1549 break;
c6d46f5f
JB
1550 }
1551 continue;
13fde0cd
RS
1552 case '%':
1553 if ((c_ext & YACC) && *lp == '%')
1554 {
1555 /* entering or exiting rules section in yacc file */
1556 lp++;
1557 definedef = dnone; funcdef = fnone;
1558 typdef= tnone; structdef= snone;
1559 next_token_is_func = FALSE;
1560 midtoken = inquote = inchar = incomm = quotednl = FALSE;
591fa824 1561 cblev = 0;
13fde0cd
RS
1562 yacc_rules = !yacc_rules;
1563 continue;
591fa824 1564 }
c6d46f5f 1565 case '#':
13fde0cd 1566 if (lp == newlb.buffer + 1 && definedef == dnone)
c6d46f5f
JB
1567 definedef = dsharpseen;
1568 continue;
13fde0cd 1569 } /* switch (c) */
c6d46f5f 1570
c6d46f5f 1571
591fa824
RS
1572 /* Consider token only if some complicated conditions are satisfied. */
1573 if (((cblev == 0 && structdef != scolonseen)
1574 || (cblev == 1 && cplpl && structdef == sinbody))
13fde0cd 1575 && definedef != dignorerest
13fde0cd 1576 && funcdef != finlist)
c6d46f5f
JB
1577 {
1578 if (midtoken)
1579 {
1580 if (endtoken (c))
1581 {
13fde0cd 1582 if (cplpl && c == ':' && *lp == ':' && intoken (*(lp + 1)))
c6d46f5f
JB
1583 {
1584 /*
1585 * This handles :: in the middle, but not at beginning
1586 * of an identifier.
1587 */
1588 lp += 2;
1589 toklen += 3;
1590 }
1591 else
1592 {
fe0b3356 1593 logical is_func = FALSE;
c6d46f5f 1594
13fde0cd
RS
1595 tok.lineno = lineno;
1596 tok.p = newlb.buffer + tokoff;
c6d46f5f 1597 tok.len = toklen;
fe0b3356 1598 tok.named = FALSE;
13fde0cd
RS
1599 if (yacc_rules
1600 || consider_token (c, lp, &tok,
591fa824 1601 c_ext, cblev, &is_func))
c6d46f5f 1602 {
99e0a2e0 1603 if (structdef == sinbody
fe0b3356
FP
1604 && definedef == dnone
1605 && is_func)
1606 /* function defined in C++ class body */
1607 {
1608 tok.named = TRUE;
1609 sprintf (nameb, "%s::%.*s",
13fde0cd
RS
1610 ((structtag[0] == '\0')
1611 ? "_anonymous_" : structtag),
c6d46f5f 1612 tok.len, tok.p);
c6d46f5f
JB
1613 }
1614 else
1615 {
fe0b3356 1616 sprintf (nameb, "%.*s", tok.len, tok.p);
c6d46f5f 1617 }
13fde0cd 1618
fe0b3356
FP
1619 if (structdef == stagseen
1620 || typdef == tend)
1621 tok.named = TRUE;
1622
591fa824
RS
1623 if (funcdef == ftagseen
1624 || structdef == stagseen
1625 || typdef == tend)
13fde0cd
RS
1626 {
1627 if (newndx == curndx)
1628 curndx = 1 - curndx; /* switch line buffers */
1629 }
1630 else
1631 MAKE_TAG_FROM_NEW_LB (is_func);
c6d46f5f
JB
1632 }
1633 midtoken = FALSE;
1634 }
13fde0cd 1635 } /* if (endtoken (c)) */
c6d46f5f 1636 else if (intoken (c))
13fde0cd
RS
1637 {
1638 toklen++;
1639 continue;
1640 }
1641 } /* if (midtoken) */
c6d46f5f
JB
1642 else if (begtoken (c))
1643 {
13fde0cd
RS
1644 switch (funcdef)
1645 {
1646 case flistseen:
1647 MAKE_TAG_FROM_OTH_LB (TRUE);
31d4b314
FP
1648 funcdef = fignore;
1649 break;
13fde0cd
RS
1650 case ftagseen:
1651 funcdef = fnone;
1652 break;
1653 }
1654 if (structdef == stagseen)
1655 structdef = snone;
1656 if (!yacc_rules || lp == newlb.buffer + 1)
1657 {
1658 tokoff = lp - 1 - newlb.buffer;
1659 toklen = 1;
1660 midtoken = TRUE;
1661 }
1662 continue;
c6d46f5f 1663 }
13fde0cd
RS
1664 } /* if must look at token */
1665
1666
1667 /* Detect end of line, colon, comma, semicolon and various braces
1668 after having handled the last token on the line.*/
1669 switch (c)
1e134a5f 1670 {
13fde0cd
RS
1671 case ':':
1672 if (structdef == stagseen)
1673 structdef = scolonseen;
1674 else if (yacc_rules && funcdef == ftagseen)
57e83cfe 1675 {
13fde0cd 1676 MAKE_TAG_FROM_OTH_LB (FALSE);
31d4b314 1677 funcdef = fignore;
57e83cfe 1678 }
13fde0cd
RS
1679 break;
1680 case ';':
591fa824
RS
1681 if (cblev == 0 && typdef == tend)
1682 {
1683 typdef = tnone;
1684 MAKE_TAG_FROM_OTH_LB (FALSE);
1685 }
31d4b314
FP
1686 if (funcdef != fignore)
1687 funcdef = fnone;
13fde0cd
RS
1688 /* FALLTHRU */
1689 case ',':
13fde0cd
RS
1690 /* FALLTHRU */
1691 case '[':
31d4b314 1692 if (funcdef != finlist && funcdef != fignore)
13fde0cd
RS
1693 funcdef = fnone;
1694 if (structdef == stagseen)
1695 structdef = snone;
1696 break;
1697 case '(':
1698 switch (funcdef)
57e83cfe 1699 {
13fde0cd
RS
1700 case ftagseen:
1701 funcdef = finlist;
1702 break;
1703 case finlist:
1704 case flistseen:
1705 funcdef = fnone;
1706 break;
57e83cfe 1707 }
13fde0cd
RS
1708 break;
1709 case ')':
1710 if (funcdef == finlist)
1711 funcdef = flistseen;
1712 break;
1713 case '{':
1714 if (typdef == ttypedseen)
1715 typdef = tinbody;
1716 switch (structdef)
1717 {
1718 case skeyseen: /* unnamed struct */
1719 structtag[0] = '\0';
1720 structdef = sinbody;
1721 break;
1722 case stagseen:
1723 case scolonseen: /* named struct */
1724 structdef = sinbody;
1725 MAKE_TAG_FROM_OTH_LB (FALSE);
1726 break;
1727 }
31d4b314
FP
1728 switch (funcdef)
1729 {
1730 case flistseen:
1731 MAKE_TAG_FROM_OTH_LB (TRUE);
1732 /* FALLTHRU */
1733 case fignore:
1734 funcdef = fnone;
1735 }
591fa824 1736 cblev++;
31d4b314 1737 break;
13fde0cd
RS
1738 case '*':
1739 if (funcdef == flistseen)
1740 {
1741 MAKE_TAG_FROM_OTH_LB (TRUE);
31d4b314 1742 funcdef = fignore;
13fde0cd
RS
1743 }
1744 break;
1745 case '}':
1746 if (!noindentypedefs && lp == newlb.buffer + 1)
591fa824
RS
1747 cblev = 0; /* reset curly brace level if first column */
1748 else if (cblev > 0)
1749 cblev--;
1750 if (cblev == 0)
13fde0cd
RS
1751 {
1752 if (typdef == tinbody)
1753 typdef = tend;
1754 structdef = snone;
1755 (void) strcpy (structtag, "<error 2>");
1756 }
1757 break;
1758 case '\0':
1759 /* If a macro spans multiple lines don't reset its state. */
1760 if (quotednl)
1761 CNL_SAVE_DEFINEDEF;
1762 else
1763 CNL;
1764 break;
1765 } /* switch (c) */
1766
1767 } /* while not eof */
c6d46f5f
JB
1768}
1769
1770/*
1771 * consider_token ()
1772 * checks to see if the current token is at the start of a
13fde0cd
RS
1773 * function, or corresponds to a typedef, or is a struct/union/enum
1774 * tag.
c6d46f5f 1775 *
13fde0cd 1776 * *IS_FUNC gets TRUE iff the token is a function or macro with args.
c6d46f5f
JB
1777 * C_EXT is which language we are looking at.
1778 *
1779 * In the future we will need some way to adjust where the end of
1780 * the token is; for instance, implementing the C++ keyword
1781 * `operator' properly will adjust the end of the token to be after
1782 * whatever follows `operator'.
1783 *
1784 * Globals
13fde0cd
RS
1785 * funcdef IN OUT
1786 * structdef IN OUT
1787 * definedef IN OUT
1788 * typdef IN OUT
1789 * next_token_is_func IN OUT
c6d46f5f
JB
1790 */
1791
1792logical
591fa824 1793consider_token (c, lp, tokp, c_ext, cblev, is_func)
13fde0cd
RS
1794 register char c; /* IN: first char after the token */
1795 register char *lp; /* IN: lp points to 2nd char after the token */
591fa824
RS
1796 register TOKEN *tokp; /* IN: token pointer */
1797 int c_ext; /* IN: C extensions mask */
1798 int cblev; /* IN: curly brace level */
13fde0cd 1799 logical *is_func; /* OUT */
c6d46f5f 1800{
c6d46f5f
JB
1801 logical firsttok; /* TRUE if have seen first token in ()'s */
1802 Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
1803 enum sym_type toktype = stab_type (tokse);
1804
c6d46f5f 1805 /*
13fde0cd 1806 * Advance the definedef state machine.
c6d46f5f
JB
1807 */
1808 switch (definedef)
1809 {
1810 case dnone:
1811 /* We're not on a preprocessor line. */
1812 break;
1813 case dsharpseen:
1814 if (toktype == st_C_define)
1815 {
1816 definedef = ddefineseen;
c6d46f5f
JB
1817 }
1818 else
1819 {
1820 definedef = dignorerest;
c6d46f5f 1821 }
13fde0cd 1822 return (FALSE);
c6d46f5f
JB
1823 case ddefineseen:
1824 /*
1825 * Make a tag for any macro.
c6d46f5f 1826 */
c6d46f5f 1827 definedef = dignorerest;
13fde0cd 1828 *is_func = (c == '(');
c6d46f5f 1829 if (!*is_func && !constantypedefs)
13fde0cd
RS
1830 return (FALSE);
1831 else
1832 return (TRUE);
c6d46f5f 1833 case dignorerest:
13fde0cd 1834 return (FALSE);
c6d46f5f
JB
1835 default:
1836 error ("internal error: definedef value");
1837 }
1838
1839 /*
13fde0cd 1840 * Now typedefs
c6d46f5f 1841 */
13fde0cd 1842 switch (typdef)
c6d46f5f 1843 {
13fde0cd
RS
1844 case tnone:
1845 if (toktype == st_C_typedef)
c6d46f5f 1846 {
13fde0cd
RS
1847 if (typedefs)
1848 typdef = ttypedseen;
1849 return (FALSE);
c6d46f5f 1850 }
13fde0cd
RS
1851 break;
1852 case ttypedseen:
1853 switch (toktype)
c6d46f5f 1854 {
13fde0cd
RS
1855 case st_none:
1856 case st_C_typespec:
1857 typdef = tend;
1858 break;
1859 case st_C_struct:
1860 case st_C_enum:
1e134a5f 1861 break;
c6d46f5f 1862 }
13fde0cd 1863 /* Do not return here, so the structdef stuff has a chance. */
c6d46f5f 1864 break;
13fde0cd
RS
1865 case tend:
1866 switch (toktype)
c6d46f5f 1867 {
13fde0cd
RS
1868 case st_C_typespec:
1869 case st_C_struct:
1870 case st_C_enum:
1871 return (FALSE);
c6d46f5f 1872 }
13fde0cd 1873 return (TRUE);
c6d46f5f
JB
1874 }
1875
1876 /*
591fa824
RS
1877 * This structdef business is currently only invoked when cblev==0.
1878 * It should be recursively invoked whatever the curly brace level,
1879 * and a stack of states kept, to allow for definitions of structs
1880 * within structs.
c6d46f5f
JB
1881 *
1882 * This structdef business is NOT invoked when we are ctags and the
1883 * file is plain C. This is because a struct tag may have the same
1884 * name as another tag, and this loses with ctags.
1885 *
13fde0cd
RS
1886 * This if statement deals with the typdef state machine as
1887 * follows: if typdef==ttypedseen and token is struct/union/class/enum,
1888 * return (FALSE). All the other code here is for the structdef
1889 * state machine.
c6d46f5f
JB
1890 */
1891 switch (toktype)
1892 {
1893 case st_C_struct:
1894 case st_C_enum:
13fde0cd 1895 if (typdef == ttypedseen
591fa824 1896 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
c6d46f5f
JB
1897 {
1898 structdef = skeyseen;
1899 structkey = tokse;
1900 }
13fde0cd 1901 return (FALSE);
c6d46f5f 1902 }
c6d46f5f
JB
1903 if (structdef == skeyseen)
1904 {
13fde0cd 1905 if (stab_type (structkey) == st_C_struct)
c6d46f5f 1906 {
13fde0cd
RS
1907 (void) strncpy (structtag, tokp->p, tokp->len);
1908 structtag[tokp->len] = '\0'; /* for struct/union/class */
c6d46f5f
JB
1909 }
1910 else
1911 {
13fde0cd 1912 structtag[0] = '\0'; /* for enum (why is it treated differently?) */
c6d46f5f 1913 }
13fde0cd
RS
1914 structdef = stagseen;
1915 return (TRUE);
c6d46f5f 1916 }
13fde0cd
RS
1917
1918 /* Avoid entering funcdef stuff if typdef is going on. */
1919 if (typdef != tnone)
c6d46f5f 1920 {
13fde0cd
RS
1921 definedef = dnone;
1922 return (FALSE);
c6d46f5f 1923 }
13fde0cd 1924
c6d46f5f 1925 /* Detect GNUmacs's function-defining macros. */
4746118a 1926 if (definedef == dnone)
c6d46f5f 1927 {
daa37602
JB
1928 if (strneq (tokp->p, "DEF", 3)
1929 || strneq (tokp->p, "ENTRY", 5)
1930 || strneq (tokp->p, "SYSCALL", 7)
1931 || strneq (tokp->p, "PSEUDO", 6))
4746118a
JB
1932 {
1933 next_token_is_func = TRUE;
13fde0cd 1934 return (FALSE);
4746118a 1935 }
13fde0cd 1936 if (strneq (tokp->p, "EXFUN", 5))
4746118a
JB
1937 {
1938 next_token_is_func = FALSE;
13fde0cd 1939 return (FALSE);
4746118a 1940 }
c6d46f5f
JB
1941 }
1942 if (next_token_is_func)
1943 {
1944 next_token_is_func = FALSE;
31d4b314
FP
1945 funcdef = fnone;
1946 *is_func = TRUE; /* to force search string in ctags */
13fde0cd 1947 return (TRUE);
c6d46f5f 1948 }
13fde0cd
RS
1949
1950 /* A function? */
1951 switch (toktype)
c6d46f5f 1952 {
13fde0cd 1953 case st_C_typespec:
591fa824 1954 funcdef = fnone; /* should be useless */
13fde0cd
RS
1955 return (FALSE);
1956 default:
31d4b314
FP
1957 if (funcdef == fnone)
1958 {
1959 funcdef = ftagseen;
1960 *is_func = TRUE;
1961 return (TRUE);
1962 }
c6d46f5f 1963 }
31d4b314
FP
1964
1965 return (FALSE);
c6d46f5f
JB
1966}
1967\f
1968/* Fortran parsing */
1969
1970char *dbp;
1971int pfcnt;
1972
1973int
1974PF_funcs (fi)
1975 FILE *fi;
1976{
1977 lineno = 0;
1978 charno = 0;
1979 pfcnt = 0;
1980
1981 while (!feof (fi))
1982 {
1983 lineno++;
1984 linecharno = charno;
1985 charno += readline (&lb, fi);
1986 dbp = lb.buffer;
1987 if (*dbp == '%')
1988 dbp++; /* Ratfor escape to fortran */
1989 while (isspace (*dbp))
1990 dbp++;
1991 if (*dbp == 0)
1992 continue;
1993 switch (*dbp | ' ')
1994 {
1995 case 'i':
1996 if (tail ("integer"))
1997 takeprec ();
1998 break;
1999 case 'r':
2000 if (tail ("real"))
2001 takeprec ();
2002 break;
2003 case 'l':
2004 if (tail ("logical"))
2005 takeprec ();
2006 break;
2007 case 'c':
2008 if (tail ("complex") || tail ("character"))
2009 takeprec ();
2010 break;
2011 case 'd':
2012 if (tail ("double"))
2013 {
2014 while (isspace (*dbp))
2015 dbp++;
2016 if (*dbp == 0)
2017 continue;
2018 if (tail ("precision"))
2019 break;
2020 continue;
2021 }
2022 break;
2023 }
2024 while (isspace (*dbp))
2025 dbp++;
2026 if (*dbp == 0)
2027 continue;
2028 switch (*dbp | ' ')
2029 {
2030 case 'f':
2031 if (tail ("function"))
2032 getit ();
2033 continue;
2034 case 's':
2035 if (tail ("subroutine"))
2036 getit ();
2037 continue;
8a6c8bcf
RS
2038 case 'e':
2039 if (tail ("entry"))
2040 getit ();
2041 continue;
c6d46f5f
JB
2042 case 'p':
2043 if (tail ("program"))
2044 {
2045 getit ();
2046 continue;
2047 }
2048 if (tail ("procedure"))
2049 getit ();
2050 continue;
2051 }
2052 }
2053 return (pfcnt);
2054}
2055
2056logical
2057tail (cp)
2058 char *cp;
2059{
2060 register int len = 0;
2061
2062 while (*cp && (*cp & ~' ') == ((*(dbp + len)) & ~' '))
2063 cp++, len++;
2064 if (*cp == 0)
2065 {
2066 dbp += len;
2067 return (1);
2068 }
2069 return (0);
2070}
2071
2072void
2073takeprec ()
2074{
2075 while (isspace (*dbp))
2076 dbp++;
2077 if (*dbp != '*')
2078 return;
2079 dbp++;
2080 while (isspace (*dbp))
2081 dbp++;
2082 if (!isdigit (*dbp))
2083 {
2084 --dbp; /* force failure */
2085 return;
2086 }
2087 do
2088 dbp++;
2089 while (isdigit (*dbp));
2090}
2091
2092void
2093getit ()
2094{
2095 register char *cp;
2096 char c;
2097 char nambuf[BUFSIZ];
2098
2099 while (isspace (*dbp))
2100 dbp++;
daa37602
JB
2101 if (*dbp == 0
2102 || (!isalpha (*dbp)
2103 && *dbp != '_'
2104 && *dbp != '$'))
c6d46f5f
JB
2105 return;
2106 for (cp = dbp + 1; *cp && (isalpha (*cp) || isdigit (*cp)
2107 || (*cp == '_') || (*cp == '$')); cp++)
2108 continue;
2109 c = cp[0];
2110 cp[0] = 0;
2111 (void) strcpy (nambuf, dbp);
2112 cp[0] = c;
2113 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2114 pfcnt++;
2115}
2116
2117/* Handle a file of assembler code. */
2118
2119void
2120Asm_funcs (fi)
2121 FILE *fi;
2122{
2123 int i;
2124 register char c;
2125
2126 lineno = 0;
2127 charno = 0;
2128 pfcnt = 0;
2129
2130 while (!feof (fi))
2131 {
2132 lineno++;
2133 linecharno = charno;
2134 charno += readline (&lb, fi);
2135 dbp = lb.buffer;
2136
2137 for (i = 0; ((c = dbp[i]) && !isspace (c)) && (c != ':'); i++)
2138 ;
2139
2140 if ((i > 0) && (c == ':'))
2141 getit ();
2142 }
2143}
2144\f
2145/* Added by Mosur Mohan, 4/22/88 */
2146/* Pascal parsing */
2147
2148#define GET_NEW_LINE \
2149{ \
2150 linecharno = charno; lineno++; \
2151 charno += 1 + readline (&lb, inf); \
2152 dbp = lb.buffer; \
2153}
2154
2155/* Locates tags for procedures & functions.
2156 * Doesn't do any type- or var-definitions.
2157 * It does look for the keyword "extern" or "forward"
2158 * immediately following the procedure statement;
2159 * if found, the tag is skipped.
2160 */
2161
2162void
2163PAS_funcs (fi)
2164 FILE *fi;
2165{
2166 struct linebuffer tline; /* mostly copied from C_entries */
2167 long save_lcno;
2168 int save_lineno;
2169 char c, *cp;
2170 char nambuf[BUFSIZ];
2171
2172 logical /* each of these flags is TRUE iff: */
2173 incomm1, /* point is inside {..} comment */
2174 incomm2, /* point is inside (*..*) comment */
2175 inquote, /* point is inside '..' string */
2176 get_tagname, /* point is after PROCEDURE/FUNCTION */
2177 /* keyword, so next item = potential tag */
2178 found_tag, /* point is after a potential tag */
2179 inparms, /* point is within parameter-list */
2180 verify_tag; /* point has passed the parm-list, so the */
2181 /* next token will determine whether */
2182 /* this is a FORWARD/EXTERN to be */
2183 /* ignored, or whether it is a real tag */
2184
2185 lineno = 0;
2186 charno = 0;
2187 dbp = lb.buffer;
2188 *dbp = 0;
2189 initbuffer (&tline);
2190
2191 incomm1 = incomm2 = inquote = FALSE;
2192 found_tag = FALSE; /* have a proc name; check if extern */
2193 get_tagname = FALSE; /* have found "procedure" keyword */
2194 inparms = FALSE; /* found '(' after "proc" */
2195 verify_tag = FALSE; /* check if "extern" is ahead */
2196
2197 /* long main loop to get next char */
2198 while (!feof (fi))
2199 {
2200 c = *dbp++;
2201 if (c == 0) /* if end of line */
2202 {
2203 GET_NEW_LINE;
2204 if (*dbp == 0)
2205 continue;
2206 if (!((found_tag && verify_tag) ||
2207 get_tagname))
2208 c = *dbp++; /* only if don't need *dbp pointing */
2209 /* to the beginning of the name of */
2210 /* the procedure or function */
2211 }
2212 if (incomm1) /* within { - } comments */
2213 {
2214 if (c == '}')
2215 incomm1 = FALSE;
2216 continue;
2217 }
2218 else if (incomm2) /* within (* - *) comments */
2219 {
2220 if (c == '*')
2221 {
2222 while ((c = *dbp++) == '*')
2223 continue;
2224 if (c == 0)
2225 GET_NEW_LINE;
2226 if (c == ')')
2227 incomm2 = FALSE;
2228 }
2229 continue;
2230 }
2231 else if (inquote)
2232 {
2233 if (c == '\'')
2234 inquote = FALSE;
2235 continue;
2236 }
2237 else
2238 switch (c)
2239 {
2240 case '\'':
2241 inquote = TRUE; /* found first quote */
2242 continue;
2243 case '{': /* found open-{-comment */
2244 incomm1 = TRUE;
2245 continue;
2246 case '(':
2247 if (*dbp == '*') /* found open-(*-comment */
2248 {
2249 incomm2 = TRUE;
2250 dbp++;
2251 }
2252 else if (found_tag) /* found '(' after tag, i.e., parm-list */
2253 inparms = TRUE;
2254 continue;
2255 case ')': /* end of parms list */
2256 if (inparms)
2257 inparms = FALSE;
2258 continue;
2259 case ';':
2260 if ((found_tag) && (!inparms)) /* end of proc or fn stmt */
2261 {
2262 verify_tag = TRUE;
2263 break;
2264 }
2265 continue;
2266 }
2267 if ((found_tag) && (verify_tag) && (*dbp != ' '))
2268 {
2269 /* check if this is an "extern" declaration */
2270 if (*dbp == 0)
2271 continue;
2272 if ((*dbp == 'e') || (*dbp == 'E'))
2273 {
2274 if (tail ("extern")) /* superfluous, really! */
2275 {
2276 found_tag = FALSE;
2277 verify_tag = FALSE;
2278 }
2279 }
2280 else if ((*dbp == 'f') || (*dbp == 'F'))
2281 {
2282 if (tail ("forward")) /* check for forward reference */
2283 {
2284 found_tag = FALSE;
2285 verify_tag = FALSE;
2286 }
2287 }
2288 if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
2289 {
2290 found_tag = FALSE;
2291 verify_tag = FALSE;
2292 pfnote (nambuf, TRUE, FALSE,
2293 tline.buffer, cp - tline.buffer + 1,
2294 save_lineno, save_lcno);
2295 continue;
2296 }
2297 }
2298 if (get_tagname) /* grab name of proc or fn */
2299 {
2300 if (*dbp == 0)
2301 continue;
2302
2303 /* save all values for later tagging */
2304 tline.size = lb.size;
2305 strcpy (tline.buffer, lb.buffer);
2306 save_lineno = lineno;
2307 save_lcno = linecharno;
2308
2309 /* grab block name */
2310 for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
2311 continue;
2312 c = cp[0];
2313 cp[0] = 0;
2314 strcpy (nambuf, dbp);
2315 cp[0] = c;
2316 dbp = cp; /* restore dbp to e-o-token */
2317 get_tagname = FALSE;
2318 found_tag = TRUE;
2319 continue;
2320
2321 /* and proceed to check for "extern" */
2322 }
2323 if ((!incomm1) && (!incomm2) && (!inquote) &&
2324 (!found_tag) && (!get_tagname))
2325 {
2326 /* check for proc/fn keywords */
2327 switch (c | ' ')
2328 {
2329 case 'p':
2330 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
2331 get_tagname = TRUE;
2332 continue;
2333 case 'f':
2334 if (tail ("unction"))
2335 get_tagname = TRUE;
2336 continue;
2337 }
2338 }
2339 } /* while not e-o-f */
2340}
2341\f
2342/*
2343 * lisp tag functions
2344 * just look for (def or (DEF
2345 */
2346
2347void
2348L_funcs (fi)
2349 FILE *fi;
2350{
2351 lineno = 0;
2352 charno = 0;
2353 pfcnt = 0;
2354
2355 while (!feof (fi))
2356 {
2357 lineno++;
2358 linecharno = charno;
2359 charno += readline (&lb, fi);
2360 dbp = lb.buffer;
2361 if (dbp[0] == '(')
2362 {
2363 if (L_isdef (dbp))
2364 {
2365 while (!isspace (*dbp))
2366 dbp++;
2367 while (isspace (*dbp))
2368 dbp++;
2369 L_getit ();
2370 }
2371 else
2372 {
2373 /* Check for (foo::defmumble name-defined ... */
31d4b314 2374 do
c6d46f5f 2375 dbp++;
31d4b314
FP
2376 while (*dbp && !isspace (*dbp)
2377 && *dbp != ':' && *dbp != '(' && *dbp != ')');
c6d46f5f
JB
2378 if (*dbp == ':')
2379 {
31d4b314 2380 do
c6d46f5f 2381 dbp++;
31d4b314 2382 while (*dbp == ':');
c6d46f5f 2383
31d4b314 2384 if (L_isdef (dbp - 1))
c6d46f5f
JB
2385 {
2386 while (!isspace (*dbp))
2387 dbp++;
2388 while (isspace (*dbp))
2389 dbp++;
2390 L_getit ();
2391 }
2392 }
2393 }
2394 }
2395 }
2396}
2397
2398int
2399L_isdef (dbp)
31d4b314 2400 register char *dbp;
c6d46f5f 2401{
31d4b314
FP
2402 return ((dbp[1] == 'd' || dbp[1] == 'D')
2403 && (dbp[2] == 'e' || dbp[2] == 'E')
2404 && (dbp[3] == 'f' || dbp[3] == 'F'));
2405}
2406
2407int
2408L_isquote (dbp)
2409 register char *dbp;
2410{
2411 return ((*(++dbp) == 'q' || *dbp == 'Q')
2412 && (*(++dbp) == 'u' || *dbp == 'U')
2413 && (*(++dbp) == 'o' || *dbp == 'O')
2414 && (*(++dbp) == 't' || *dbp == 'T')
2415 && (*(++dbp) == 'e' || *dbp == 'E')
2416 && isspace(*(++dbp)));
c6d46f5f
JB
2417}
2418
2419void
2420L_getit ()
2421{
2422 register char *cp;
2423 char c;
2424 char nambuf[BUFSIZ];
2425
31d4b314
FP
2426 if (*dbp == '\'') /* Skip prefix quote */
2427 dbp++;
2428 else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
2429 {
2430 dbp += 7;
2431 while (isspace(*dbp))
2432 dbp++;
2433 }
2434 for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
c6d46f5f 2435 continue;
31d4b314
FP
2436 if (cp == dbp)
2437 return;
2438
c6d46f5f
JB
2439 c = cp[0];
2440 cp[0] = 0;
2441 (void) strcpy (nambuf, dbp);
2442 cp[0] = c;
591fa824
RS
2443 pfnote (nambuf, TRUE, FALSE, lb.buffer,
2444 cp - lb.buffer + 1, lineno, linecharno);
c6d46f5f
JB
2445 pfcnt++;
2446}
2447\f
2448/*
2449 * Scheme tag functions
2450 * look for (def... xyzzy
2451 * look for (def... (xyzzy
2452 * look for (def ... ((...(xyzzy ....
2453 * look for (set! xyzzy
2454 */
2455
2456static void get_scheme ();
2457
2458void
2459Scheme_funcs (fi)
2460 FILE *fi;
2461{
2462 lineno = 0;
2463 charno = 0;
2464 pfcnt = 0;
2465
2466 while (!feof (fi))
2467 {
2468 lineno++;
2469 linecharno = charno;
2470 charno += readline (&lb, fi);
2471 dbp = lb.buffer;
2472 if (dbp[0] == '(' &&
2473 (dbp[1] == 'D' || dbp[1] == 'd') &&
2474 (dbp[2] == 'E' || dbp[2] == 'e') &&
2475 (dbp[3] == 'F' || dbp[3] == 'f'))
2476 {
2477 while (!isspace (*dbp))
2478 dbp++;
2479 /* Skip over open parens and white space */
2480 while (*dbp && (isspace (*dbp) || *dbp == '('))
2481 dbp++;
2482 get_scheme ();
2483 }
2484 if (dbp[0] == '(' &&
2485 (dbp[1] == 'S' || dbp[1] == 's') &&
2486 (dbp[2] == 'E' || dbp[2] == 'e') &&
2487 (dbp[3] == 'T' || dbp[3] == 't') &&
2488 (dbp[4] == '!' || dbp[4] == '!') &&
2489 (isspace (dbp[5])))
2490 {
2491 while (!isspace (*dbp))
2492 dbp++;
2493 /* Skip over white space */
2494 while (isspace (*dbp))
2495 dbp++;
2496 get_scheme ();
2497 }
2498 }
2499}
2500
2501static void
2502get_scheme ()
2503{
2504 register char *cp;
2505 char c;
2506 char nambuf[BUFSIZ];
2507
2508 if (*dbp == 0)
2509 return;
2510 /* Go till you get to white space or a syntactic break */
2511 for (cp = dbp + 1; *cp && *cp != '(' && *cp != ')' && !isspace (*cp); cp++)
2512 continue;
2513 /* Null terminate the string there. */
2514 c = cp[0];
2515 cp[0] = 0;
2516 /* Copy the string */
2517 strcpy (nambuf, dbp);
2518 /* Unterminate the string */
2519 cp[0] = c;
2520 /* Announce the change */
2521 pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
2522 pfcnt++;
2523}
2524\f
2525/* Find tags in TeX and LaTeX input files. */
2526
2527/* TEX_toktab is a table of TeX control sequences that define tags.
2528 Each TEX_tabent records one such control sequence.
2529 CONVERT THIS TO USE THE Stab TYPE!! */
2530
2531struct TEX_tabent
2532{
2533 char *name;
2534 int len;
2535};
2536
2537struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
2538
2539/* Default set of control sequences to put into TEX_toktab.
2540 The value of environment var TEXTAGS is prepended to this. */
2541
2542static char *TEX_defenv =
2543":chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem:typeout";
2544
2545void TEX_mode ();
2546struct TEX_tabent *TEX_decode_env ();
2547void TEX_getit ();
2548int TEX_Token ();
2549
2550static char TEX_esc = '\\';
2551static char TEX_opgrp = '{';
2552static char TEX_clgrp = '}';
2553
2554/*
2555 * TeX/LaTeX scanning loop.
2556 */
2557
2558void
2559TEX_funcs (fi)
2560 FILE *fi;
2561{
2562 char *lasthit;
2563
2564 lineno = 0;
2565 charno = 0;
2566 pfcnt = 0;
2567
2568 /* Select either \ or ! as escape character. */
2569 TEX_mode (fi);
2570
2571 /* Initialize token table once from environment. */
2572 if (!TEX_toktab)
2573 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
2574
2575 while (!feof (fi))
d2729198 2576 { /* Scan each line in file */
c6d46f5f
JB
2577 lineno++;
2578 linecharno = charno;
2579 charno += readline (&lb, fi);
2580 dbp = lb.buffer;
2581 lasthit = dbp;
d2729198 2582 while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
8a6c8bcf
RS
2583 {
2584 register int i;
c6d46f5f 2585
8a6c8bcf
RS
2586 if (!*(++dbp))
2587 break;
2588 linecharno += dbp - lasthit;
c6d46f5f 2589 lasthit = dbp;
8a6c8bcf
RS
2590 i = TEX_Token (lasthit);
2591 if (0 <= i)
c6d46f5f 2592 {
8a6c8bcf 2593 TEX_getit (lasthit, TEX_toktab[i].len);
d2729198 2594 break; /* We only save a line once */
c6d46f5f
JB
2595 }
2596 }
2597 }
2598}
2599
2600#define TEX_LESC '\\'
2601#define TEX_SESC '!'
2602#define TEX_cmt '%'
2603
2604/* Figure out whether TeX's escapechar is '\\' or '!' and set grouping */
2605/* chars accordingly. */
2606
2607void
2608TEX_mode (f)
2609 FILE *f;
2610{
2611 int c;
2612
2613 while ((c = getc (f)) != EOF)
2614 {
2615 /* Skip to next line if we hit the TeX comment char. */
2616 if (c == TEX_cmt)
2617 while (c != '\n')
2618 c = getc (f);
2619 else if (c == TEX_LESC || c == TEX_SESC )
2620 break;
2621 }
2622
2623 if (c == TEX_LESC)
2624 {
2625 TEX_esc = TEX_LESC;
2626 TEX_opgrp = '{';
2627 TEX_clgrp = '}';
2628 }
2629 else
2630 {
2631 TEX_esc = TEX_SESC;
2632 TEX_opgrp = '<';
2633 TEX_clgrp = '>';
2634 }
2635 rewind (f);
2636}
2637
2638/* Read environment and prepend it to the default string. */
2639/* Build token table. */
2640
2641struct TEX_tabent *
2642TEX_decode_env (evarname, defenv)
2643 char *evarname;
2644 char *defenv;
2645{
2646 register char *env, *p;
c6d46f5f
JB
2647
2648 struct TEX_tabent *tab;
2649 int size, i;
2650
2651 /* Append default string to environment. */
2652 env = getenv (evarname);
2653 if (!env)
2654 env = defenv;
2655 else
2656 env = concat (env, defenv, "");
2657
2658 /* Allocate a token table */
2659 for (size = 1, p = env; p;)
8a6c8bcf 2660 if ((p = etags_index (p, ':')) && *(++p))
c6d46f5f 2661 size++;
8a6c8bcf
RS
2662 /* Add 1 to leave room for null terminator. */
2663 tab = xnew (size + 1, struct TEX_tabent);
c6d46f5f
JB
2664
2665 /* Unpack environment string into token table. Be careful about */
2666 /* zero-length strings (leading ':', "::" and trailing ':') */
2667 for (i = 0; *env;)
2668 {
8a6c8bcf 2669 p = etags_index (env, ':');
c6d46f5f
JB
2670 if (!p) /* End of environment string. */
2671 p = env + strlen (env);
2672 if (p - env > 0)
2673 { /* Only non-zero strings. */
2674 tab[i].name = savenstr (env, p - env);
2675 tab[i].len = strlen (tab[i].name);
2676 i++;
2677 }
2678 if (*p)
2679 env = p + 1;
2680 else
2681 {
2682 tab[i].name = NULL; /* Mark end of table. */
2683 tab[i].len = 0;
2684 break;
2685 }
2686 }
2687 return tab;
2688}
2689
2690/* Record a tag defined by a TeX command of length LEN and starting at NAME.
2691 The name being defined actually starts at (NAME + LEN + 1).
2692 But we seem to include the TeX command in the tag name. */
2693
2694void
2695TEX_getit (name, len)
2696 char *name;
2697 int len;
2698{
2699 char *p = name + len;
2700 char nambuf[BUFSIZ];
2701
2702 if (*name == 0)
2703 return;
2704
2705 /* Let tag name extend to next group close (or end of line) */
2706 while (*p && *p != TEX_clgrp)
2707 p++;
2708 (void) strncpy (nambuf, name, p - name);
2709 nambuf[p - name] = 0;
2710
2711 pfnote (nambuf, TRUE, FALSE, lb.buffer, strlen (lb.buffer), lineno, linecharno);
2712 pfcnt++;
2713}
2714
2715/* If the text at CP matches one of the tag-defining TeX command names,
8a6c8bcf 2716 return the etags_index of that command in TEX_toktab.
c6d46f5f
JB
2717 Otherwise return -1. */
2718
2719/* Keep the capital `T' in `Token' for dumb truncating compilers
2720 (this distinguishes it from `TEX_toktab' */
2721int
2722TEX_Token (cp)
2723 char *cp;
2724{
2725 int i;
2726
2727 for (i = 0; TEX_toktab[i].len > 0; i++)
2728 if (strncmp (TEX_toktab[i].name, cp, TEX_toktab[i].len) == 0)
2729 return i;
2730 return -1;
2731}
2732\f
2733/* Support for Prolog. */
2734
2735/* whole head (not only functor, but also arguments)
2736 is gotten in compound term. */
2737
2738void
2739prolog_getit (s, lineno, linecharno)
2740 char *s;
2741 int lineno;
2742 long linecharno;
2743{
2744 char nambuf[BUFSIZ], *save_s, tmpc;
2745 int insquote, npar;
2746
2747 save_s = s;
2748 insquote = FALSE;
2749 npar = 0;
2750 while (1)
2751 {
2752 if (*s == '\0') /* syntax error. */
2753 return;
2754 else if (insquote && *s == '\'' && *(s + 1) == '\'')
2755 s += 2;
2756 else if (*s == '\'')
2757 {
2758 insquote = !insquote;
2759 s++;
2760 }
2761 else if (!insquote && *s == '(')
2762 {
2763 npar++;
2764 s++;
2765 }
2766 else if (!insquote && *s == ')')
2767 {
2768 npar--;
2769 s++;
2770 if (npar == 0)
2771 break;
2772 else if (npar < 0) /* syntax error. */
2773 return;
2774 }
2775 else if (!insquote && *s == '.' && (isspace (*(s + 1)) || *(s + 1) == '\0'))
2776 { /* fullstop. */
2777 if (npar != 0) /* syntax error. */
2778 return;
2779 s++;
2780 break;
2781 }
2782 else
2783 s++;
2784 }
2785 tmpc = *s;
2786 *s = '\0';
2787 strcpy (nambuf, save_s);
2788 *s = tmpc;
2789 pfnote (nambuf, TRUE, save_s, strlen (nambuf), lineno, linecharno);
2790}
2791
2792/* It is assumed that prolog predicate starts from column 0. */
2793
2794void
2795prolog_funcs (fi)
2796 FILE *fi;
2797{
2798 void skip_comment (), prolog_getit ();
2799
2800 lineno = linecharno = charno = 0;
2801 while (!feof (fi))
2802 {
2803 lineno++;
2804 linecharno += charno;
2805 charno = readline (&lb, fi) + 1; /* 1 for newline. */
2806 dbp = lb.buffer;
2807 if (isspace (dbp[0])) /* not predicate header. */
2808 continue;
2809 else if (dbp[0] == '%') /* comment. */
2810 continue;
2811 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
2812 skip_comment (&lb, fi, &lineno, &linecharno);
2813 else /* found. */
2814 prolog_getit (dbp, lineno, linecharno);
2815 }
2816}
2817
2818void
2819skip_comment (plb, fi, plineno, plinecharno)
2820 struct linebuffer *plb;
2821 FILE *fi;
2822 int *plineno; /* result */
2823 long *plinecharno; /* result */
2824{
2825 while (!substr ("*/", plb->buffer))
2826 {
2827 (*plineno)++;
2828 *plinecharno += readline (plb, fi) + 1;
2829 } /* 1 for newline. */
2830}
2831
2832/* Return TRUE if 'sub' exists somewhere in 's'. */
2833
2834int
2835substr (sub, s)
2836 char *sub;
2837 char *s;
2838{
8a6c8bcf 2839 while (*s && (s = etags_index (s, *sub)))
c6d46f5f
JB
2840 if (prestr (sub, s))
2841 return (TRUE);
2842 else
2843 s++;
2844 return (FALSE);
2845}
2846
2847/* Return TRUE if 'pre' is prefix of string 's'. */
2848
2849int
2850prestr (pre, s)
2851 char *pre;
2852 char *s;
2853{
2854 if (*pre == '\0')
2855 return (TRUE);
2856 else if (*pre == *s)
2857 return (prestr (pre + 1, s + 1));
2858 else
2859 return (FALSE);
2860}
2861\f
2862/* Initialize a linebuffer for use */
2863
2864void
2865initbuffer (linebuffer)
2866 struct linebuffer *linebuffer;
2867{
2868 linebuffer->size = 200;
2869 linebuffer->buffer = xnew (200, char);
2870}
2871
2872/*
2873 * Read a line of text from `stream' into `linebuffer'.
2874 * Return the number of characters read from `stream',
2875 * which is the length of the line including the newline, if any.
2876 */
2877long
2878readline (linebuffer, stream)
2879 struct linebuffer *linebuffer;
2880 register FILE *stream;
2881{
2882 char *buffer = linebuffer->buffer;
2883 register char *p = linebuffer->buffer;
2884 register char *pend;
2885 int newline; /* 1 if ended with newline, 0 if ended with EOF */
2886
eb8c3be9 2887 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */
c6d46f5f
JB
2888
2889 while (1)
2890 {
2891 register int c = getc (stream);
2892 if (p == pend)
2893 {
2894 linebuffer->size *= 2;
2895 buffer = (char *) xrealloc (buffer, linebuffer->size);
2896 p += buffer - linebuffer->buffer;
2897 pend = buffer + linebuffer->size;
2898 linebuffer->buffer = buffer;
2899 }
2900 if (c < 0 || c == '\n')
2901 {
2902 *p = 0;
2903 newline = (c == '\n' ? 1 : 0);
2904 break;
2905 }
2906 *p++ = c;
2907 }
2908
2909 return p - buffer + newline;
2910}
2911\f
2912char *
2913savestr (cp)
2914 char *cp;
2915{
2916 return savenstr (cp, strlen (cp));
2917}
2918
2919char *
2920savenstr (cp, len)
2921 char *cp;
2922 int len;
2923{
2924 register char *dp;
2925
2926 dp = xnew (len + 1, char);
2927 (void) strncpy (dp, cp, len);
2928 dp[len] = '\0';
2929 return dp;
2930}
2931
c6d46f5f
JB
2932/*
2933 * Return the ptr in sp at which the character c last
2934 * appears; NULL if not found
2935 *
2936 * Identical to v7 rindex, included for portability.
2937 */
2938
2939char *
8a6c8bcf 2940etags_rindex (sp, c)
c6d46f5f
JB
2941 register char *sp, c;
2942{
2943 register char *r;
2944
2945 r = NULL;
2946 do
2947 {
2948 if (*sp == c)
2949 r = sp;
2950 } while (*sp++);
2951 return (r);
2952}
2953
9d7ad1b3 2954
c6d46f5f
JB
2955/*
2956 * Return the ptr in sp at which the character c first
2957 * appears; NULL if not found
2958 *
2959 * Identical to v7 index, included for portability.
2960 */
2961
2962char *
8a6c8bcf 2963etags_index (sp, c)
c6d46f5f
JB
2964 register char *sp, c;
2965{
2966 do
2967 {
2968 if (*sp == c)
2969 return (sp);
2970 } while (*sp++);
2971 return (NULL);
2972}
2973
c6d46f5f
JB
2974/* Print error message and exit. */
2975
2976/* VARARGS1 */
2977void
2978fatal (s1, s2)
2979 char *s1, *s2;
2980{
2981 error (s1, s2);
2982 exit (1);
2983}
2984
2985/* Print error message. `s1' is printf control string, `s2' is arg for it. */
2986
2987/* VARARGS1 */
2988void
2989error (s1, s2)
2990 char *s1, *s2;
2991{
2992 fprintf (stderr, "%s: ", progname);
2993 fprintf (stderr, s1, s2);
2994 fprintf (stderr, "\n");
2995}
2996
2997/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
2998
2999char *
3000concat (s1, s2, s3)
3001 char *s1, *s2, *s3;
3002{
3003 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
3004 char *result = xnew (len1 + len2 + len3 + 1, char);
3005
3006 (void) strcpy (result, s1);
3007 (void) strcpy (result + len1, s2);
3008 (void) strcpy (result + len1 + len2, s3);
3009 *(result + len1 + len2 + len3) = 0;
3010
3011 return result;
3012}
3013
3014/* Like malloc but get fatal error if memory is exhausted. */
3015
3016char *
3017xmalloc (size)
3018 int size;
3019{
3020 char *result = malloc (size);
3021 if (!result)
3022 fatal ("virtual memory exhausted", 0);
3023 return result;
3024}
3025
3026char *
3027xrealloc (ptr, size)
3028 char *ptr;
3029 int size;
3030{
3031 char *result = realloc (ptr, size);
3032 if (!result)
3033 fatal ("virtual memory exhausted");
3034 return result;
3035}