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