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