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