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