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