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