comparison lib-src/ootags.c @ 282:c42ec1d1cded r21-0b39

Import from CVS: tag r21-0b39
author cvs
date Mon, 13 Aug 2007 10:33:18 +0200
parents
children 57709be46d1b
comparison
equal deleted inserted replaced
281:090b52736db2 282:c42ec1d1cded
1 /* Tags file maker to go with GNU Emacs
2 Copyright (C) 1984, 87, 88, 89, 93, 94, 95
3 Free Software Foundation, Inc. and Ken Arnold
4
5 This file is not considered part of GNU Emacs.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 /*
22 * Authors:
23 * Ctags originally by Ken Arnold.
24 * Fortran added by Jim Kleckner.
25 * Ed Pelegri-Llopart added C typedefs.
26 * Gnu Emacs TAGS format and modifications by RMS?
27 * Sam Kendall added C++.
28 * Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
29 * Regexp tags by Tom Tromey.
30 *
31 * Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer.
32 */
33
34 char pot_etags_version[] = "@(#) pot revision number is 12.28";
35
36 /* Prototyping magic snarfed from gmalloc.c */
37 #if defined (__cplusplus) || defined (__STDC__)
38 #undef PP
39 #define PP(args) args
40 #undef __ptr_t
41 #define __ptr_t void *
42 #else /* Not C++ or ANSI C. */
43 #undef PP
44 #define PP(args) ()
45 #undef const
46 #define const
47 #undef __ptr_t
48 #define __ptr_t char *
49 #endif /* C++ or ANSI C. */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 /* On some systems, Emacs defines static as nothing for the sake
54 of unexec. We don't want that here since we don't use unexec. */
55 # undef static
56 # define ETAGS_REGEXPS /* use the regexp features */
57 # define LONG_OPTIONS /* accept long options */
58 #endif /* HAVE_CONFIG_H */
59
60 #define TRUE 1
61 #define FALSE 0
62
63 #ifndef DEBUG
64 # define DEBUG FALSE
65 #endif
66
67 #ifdef MSDOS
68 # include <fcntl.h>
69 # include <sys/param.h>
70 # include <io.h>
71 # ifndef HAVE_CONFIG_H
72 # define DOS_NT
73 # include <sys/config.h>
74 # endif
75 #endif /* MSDOS */
76
77 #ifdef WINDOWSNT
78 # include <stdlib.h>
79 # include <fcntl.h>
80 # include <string.h>
81 # include <io.h>
82 # define MAXPATHLEN _MAX_PATH
83 # ifdef HAVE_CONFIG_H
84 # undef HAVE_NTGUI
85 # else
86 # define DOS_NT
87 # define HAVE_GETCWD
88 # endif /* not HAVE_CONFIG_H */
89 #endif /* WINDOWSNT */
90
91 #if !defined (WINDOWSNT) && defined (STDC_HEADERS)
92 #include <stdlib.h>
93 #include <string.h>
94 #endif
95
96 #ifdef HAVE_UNISTD_H
97 # include <unistd.h>
98 #else
99 # ifdef HAVE_GETCWD
100 extern char *getcwd ();
101 # endif
102 #endif /* HAVE_UNISTD_H */
103
104 #include <stdio.h>
105 #include <ctype.h>
106 #include <errno.h>
107 #ifndef errno
108 extern int errno;
109 #endif
110 #include <sys/types.h>
111 #include <sys/stat.h>
112
113 #if !defined (S_ISREG) && defined (S_IFREG)
114 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
115 #endif
116
117 #ifdef LONG_OPTIONS
118 # include <getopt.h>
119 #else
120 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
121 extern char *optarg;
122 extern int optind, opterr;
123 #endif /* LONG_OPTIONS */
124
125 #ifdef ETAGS_REGEXPS
126 # include <regex.h>
127 #endif /* ETAGS_REGEXPS */
128
129 /* Define CTAGS to make the program "ctags" compatible with the usual one.
130 Leave it undefined to make the program "etags", which makes emacs-style
131 tag tables and tags typedefs, #defines and struct/union/enum by default. */
132 #ifdef CTAGS
133 # undef CTAGS
134 # define CTAGS TRUE
135 #else
136 # define CTAGS FALSE
137 #endif
138
139 /* Exit codes for success and failure. */
140 #ifdef VMS
141 # define GOOD 1
142 # define BAD 0
143 #else
144 # define GOOD 0
145 # define BAD 1
146 #endif
147
148 /* C extensions. */
149 #define C_PLPL 0x00001 /* C++ */
150 #define C_STAR 0x00003 /* C* */
151 #define C_JAVA 0x00005 /* JAVA */
152 #define YACC 0x10000 /* yacc file */
153
154 #define streq(s,t) ((DEBUG && (s) == NULL && (t) == NULL \
155 && (abort (), 1)) || !strcmp (s, t))
156 #define strneq(s,t,n) ((DEBUG && (s) == NULL && (t) == NULL \
157 && (abort (), 1)) || !strncmp (s, t, n))
158
159 #define lowcase(c) tolower ((char)c)
160
161 #define CHARS 256 /* 2^sizeof(char) */
162 #define CHAR(x) ((unsigned int)x & (CHARS - 1))
163 #define iswhite(c) (_wht[CHAR(c)]) /* c is white */
164 #define notinname(c) (_nin[CHAR(c)]) /* c is not in a name */
165 #define begtoken(c) (_btk[CHAR(c)]) /* c can start token */
166 #define intoken(c) (_itk[CHAR(c)]) /* c can be in token */
167 #define endtoken(c) (_etk[CHAR(c)]) /* c ends tokens */
168
169 /*#ifdef INFODOCK*/
170 /*#undef OO_BROWSER*/
171 /* Due to the way this file is constructed, this unfortunately doesn't */
172 /* work except for documentation purposes. -slb */
173 #define OO_BROWSER 1
174 /*#endif*/
175
176 #ifdef OO_BROWSER
177 #define set_construct(construct) \
178 if (!oo_browser_construct) oo_browser_construct = construct
179 void oo_browser_clear_all_globals();
180 void oo_browser_clear_some_globals();
181 void oo_browser_check_and_clear_structtype();
182 #endif
183
184 /*
185 * xnew, xrnew -- allocate, reallocate storage
186 *
187 * SYNOPSIS: Type *xnew (int n, Type);
188 * Type *xrnew (OldPointer, int n, Type);
189 */
190 #ifdef chkmalloc
191 # include "chkmalloc.h"
192 # define xnew(n,Type) ((Type *) trace_malloc (__FILE__, __LINE__, \
193 (n) * sizeof (Type)))
194 # define xrnew(op,n,Type) ((Type *) trace_realloc (__FILE__, __LINE__, \
195 (op), (n) * sizeof (Type)))
196 #else
197 # define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
198 # define xrnew(op,n,Type) ((Type *) xrealloc ((op), (n) * sizeof (Type)))
199 #endif
200
201 typedef int bool;
202
203 typedef void Lang_function ();
204
205 typedef struct
206 {
207 char *name;
208 Lang_function *function;
209 char **suffixes;
210 char **interpreters;
211 } language;
212
213 typedef struct node_st
214 { /* sorting structure */
215 char *name; /* function or type name */
216 #ifdef OO_BROWSER
217 short int construct; /* Construct type for the OO-Browser */
218 #endif
219 char *file; /* file name */
220 bool is_func; /* use pattern or line no */
221 bool been_warned; /* set if noticed dup */
222 int lno; /* line number tag is on */
223 long cno; /* character number line starts on */
224 char *pat; /* search pattern */
225 struct node_st *left, *right; /* left and right sons */
226 } node;
227
228 #ifdef OO_BROWSER
229 /* If you add to this array, you must add a corresponding entry to the
230 following enum. */
231 static char *oo_browser_default_classes[] =
232 /* Lack of square brackets around some of these entries are intentional. */
233 {"null", "class", "method", "[constant]", "[enumeration]", "[enum_label]",
234 "extern", "[function]", "[macro]", "objc", "[structure]", "[type]",
235 "[union]", "[variable]"};
236
237 /* If you add to this enum, you must add a corresponding entry to the
238 preceding array. */
239 enum oo_browser_constructs {C_NULL, C_CLASS, C_METHOD, C_CONSTANT, C_ENUMERATION,
240 C_ENUM_LABEL, C_EXTERN, C_FUNCTION, C_MACRO,
241 C_OBJC, C_STRUCTURE, C_TYPE, C_UNION, C_VARIABLE};
242
243 enum oo_browser_constructs oo_browser_construct = C_NULL;
244 #endif
245
246 /*
247 * A `linebuffer' is a structure which holds a line of text.
248 * `readline_internal' reads a line from a stream into a linebuffer
249 * and works regardless of the length of the line.
250 * SIZE is the size of BUFFER, LEN is the length of the string in
251 * BUFFER after readline reads it.
252 */
253 typedef struct
254 {
255 long size;
256 int len;
257 char *buffer;
258 } linebuffer;
259
260 extern char *getenv PP ((const char *envvar));
261
262 /* Many compilers barf on this:
263 Lang_function Asm_labels;
264 so let's write it this way */
265 void Asm_labels PP ((FILE *inf));
266 void C_entries PP ((int c_ext, FILE *inf));
267 void default_C_entries PP ((FILE *inf));
268 void plain_C_entries PP ((FILE *inf));
269 void Cjava_entries PP ((FILE *inf));
270 void Cplusplus_entries PP ((FILE *inf));
271 void Yacc_entries PP ((FILE *inf));
272 void Cobol_paragraphs PP ((FILE *inf));
273 void Cstar_entries PP ((FILE *inf));
274 void Erlang_functions PP ((FILE *inf));
275 void Fortran_functions PP ((FILE *inf));
276 void Lisp_functions PP ((FILE *inf));
277 void Pascal_functions PP ((FILE *inf));
278 void Perl_functions PP ((FILE *inf));
279 void Postscript_functions PP ((FILE *inf));
280 void Prolog_functions PP ((FILE *inf));
281 void Python_functions PP ((FILE *inf));
282 void Scheme_functions PP ((FILE *inf));
283 void TeX_functions PP ((FILE *inf));
284 void just_read_file PP ((FILE *inf));
285
286 void print_language_names PP ((void));
287 void print_version PP ((void));
288 void print_help PP ((void));
289
290 language *get_language_from_name PP ((char *name));
291 language *get_language_from_interpreter PP ((char *interpreter));
292 language *get_language_from_suffix PP ((char *suffix));
293 int total_size_of_entries PP ((node *np));
294 long readline PP ((linebuffer *lbp, FILE *stream));
295 long readline_internal PP ((linebuffer *lbp, FILE *stream));
296 #ifdef ETAGS_REGEXPS
297 void analyse_regex PP ((char *regex_arg));
298 void add_regex PP ((char *regexp_pattern, language *lang));
299 void free_patterns PP ((void));
300 #endif /* ETAGS_REGEXPS */
301 void error PP ((const char *s1, const char *s2));
302 void suggest_asking_for_help PP ((void));
303 void fatal PP ((char *s1, char *s2));
304 void pfatal PP ((char *s1));
305 void add_node PP ((node *np, node **cur_node_p));
306
307 void init PP ((void));
308 void initbuffer PP ((linebuffer *lbp));
309 void find_entries PP ((char *file, FILE *inf));
310 void free_tree PP ((node *np));
311 void pfnote PP ((char *name, bool is_func, char *linestart, int linelen, int lno, long cno));
312 void new_pfnote PP ((char *name, int namelen, bool is_func, char *linestart, int linelen, int lno, long cno));
313 void process_file PP ((char *file));
314 void put_entries PP ((node *np));
315 void takeprec PP ((void));
316
317 char *concat PP ((char *s1, char *s2, char *s3));
318 char *skip_spaces PP ((char *cp));
319 char *skip_non_spaces PP ((char *cp));
320 char *savenstr PP ((char *cp, int len));
321 char *savestr PP ((char *cp));
322 char *etags_strchr PP ((char *sp, int c));
323 char *etags_strrchr PP ((char *sp, int c));
324 char *etags_getcwd PP ((void));
325 char *relative_filename PP ((char *file, char *dir));
326 char *absolute_filename PP ((char *file, char *dir));
327 char *absolute_dirname PP ((char *file, char *dir));
328 bool filename_is_absolute PP ((char *fn));
329 void canonicalize_filename PP ((char *fn));
330 void grow_linebuffer PP ((linebuffer *lbp, int toksize));
331 long *xmalloc PP ((unsigned int size));
332 long *xrealloc PP ((char *ptr, unsigned int size));
333
334
335 char searchar = '/'; /* use /.../ searches */
336
337 char *tagfile; /* output file */
338 char *progname; /* name this program was invoked with */
339 char *cwd; /* current working directory */
340 char *tagfiledir; /* directory of tagfile */
341 FILE *tagf; /* ioptr for tags file */
342
343 char *curfile; /* current input file name */
344 language *curlang; /* current language */
345
346 int lineno; /* line number of current line */
347 long charno; /* current character number */
348 long linecharno; /* charno of start of current line */
349 char *dbp; /* pointer to start of current tag */
350 node *head; /* the head of the binary tree of tags */
351
352 linebuffer lb; /* the current line */
353 linebuffer token_name; /* used by C_entries as a temporary area */
354 struct
355 {
356 long linepos;
357 linebuffer lb; /* used by C_entries instead of lb */
358 } lbs[2];
359
360 /* boolean "functions" (see init) */
361 bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
362 char
363 /* white chars */
364 *white = " \f\t\n\r",
365 /* not in a name */
366 *nonam = " \f\t\n\r(=,[;",
367 /* token ending chars */
368 *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
369 /* token starting chars */
370 *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
371 /* valid in-token chars */
372 *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
373
374 bool append_to_tagfile; /* -a: append to tags */
375 /* The following four default to TRUE for etags, but to FALSE for ctags. */
376 bool typedefs; /* -t: create tags for C typedefs */
377 bool typedefs_and_cplusplus; /* -T: create tags for C typedefs, level */
378 /* 0 struct/enum/union decls, and C++ */
379 /* member functions. */
380 bool constantypedefs; /* -d: create tags for C #define, enum */
381 /* constants and variables. */
382 /* -D: opposite of -d. Default under ctags. */
383 bool globals; /* create tags for global variables */
384 bool members; /* create tags for C member variables */
385 bool update; /* -u: update tags */
386 bool vgrind_style; /* -v: create vgrind style index output */
387 bool no_warnings; /* -w: suppress warnings */
388 bool cxref_style; /* -x: create cxref style output */
389 bool cplusplus; /* .[hc] means C++, not C */
390 bool noindentypedefs; /* -I: ignore indentation in C */
391 #ifdef OO_BROWSER
392 bool oo_browser_format; /* -O: OO-Browser tags format */
393 #endif
394
395 #ifdef LONG_OPTIONS
396 struct option longopts[] =
397 {
398 { "append", no_argument, NULL, 'a' },
399 { "backward-search", no_argument, NULL, 'B' },
400 { "c++", no_argument, NULL, 'C' },
401 { "cxref", no_argument, NULL, 'x' },
402 { "defines", no_argument, NULL, 'd' },
403 { "no-defines", no_argument, NULL, 'D' },
404 { "globals", no_argument, &globals, TRUE },
405 { "no-globals", no_argument, &globals, FALSE },
406 { "help", no_argument, NULL, 'h' },
407 { "help", no_argument, NULL, 'H' },
408 { "ignore-indentation", no_argument, NULL, 'I' },
409 { "include", required_argument, NULL, 'i' },
410 { "language", required_argument, NULL, 'l' },
411 { "members", no_argument, &members, TRUE },
412 { "no-members", no_argument, &members, FALSE },
413 { "no-warn", no_argument, NULL, 'w' },
414 { "output", required_argument, NULL, 'o' },
415 #ifdef OO_BROWSER
416 { "oo-browser", no_argument, NULL, 'O' },
417 #endif
418 #ifdef ETAGS_REGEXPS
419 { "regex", required_argument, NULL, 'r' },
420 { "no-regex", no_argument, NULL, 'R' },
421 #endif /* ETAGS_REGEXPS */
422 { "typedefs", no_argument, NULL, 't' },
423 { "typedefs-and-c++", no_argument, NULL, 'T' },
424 { "update", no_argument, NULL, 'u' },
425 { "version", no_argument, NULL, 'V' },
426 { "vgrind", no_argument, NULL, 'v' },
427 { 0 }
428 };
429 #endif /* LONG_OPTIONS */
430
431 #ifdef ETAGS_REGEXPS
432 /* Structure defining a regular expression. Elements are
433 the compiled pattern, and the name string. */
434 typedef struct pattern
435 {
436 struct pattern *p_next;
437 language *language;
438 char *regex;
439 struct re_pattern_buffer *pattern;
440 struct re_registers regs;
441 char *name_pattern;
442 bool error_signaled;
443 } pattern;
444
445 /* Array of all regexps. */
446 pattern *p_head = NULL;
447 #endif /* ETAGS_REGEXPS */
448
449 /*
450 * Language stuff.
451 */
452
453 /* Non-NULL if language fixed. */
454 language *forced_lang = NULL;
455
456 /* Assembly code */
457 char *Asm_suffixes [] = { "a", /* Unix assembler */
458 "asm", /* Microcontroller assembly */
459 "def", /* BSO/Tasking definition includes */
460 "inc", /* Microcontroller include files */
461 "ins", /* Microcontroller include files */
462 "s", "sa", /* Unix assembler */
463 "src", /* BSO/Tasking C compiler output */
464 NULL
465 };
466
467 /* Note that .c and .h can be considered C++, if the --c++ flag was
468 given. That is why default_C_entries is called here. */
469 char *default_C_suffixes [] =
470 { "c", "h", NULL };
471
472 char *Cplusplus_suffixes [] =
473 { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
474 "M", /* Objective C++ */
475 "pdb", /* Postscript with C syntax */
476 NULL };
477
478 char *Cjava_suffixes [] =
479 { "java", NULL };
480
481 char *Cobol_suffixes [] =
482 { "COB", "cob", NULL };
483
484 char *Cstar_suffixes [] =
485 { "cs", "hs", NULL };
486
487 char *Erlang_suffixes [] =
488 { "erl", "hrl", NULL };
489
490 char *Fortran_suffixes [] =
491 { "F", "f", "f90", "for", NULL };
492
493 char *Lisp_suffixes [] =
494 { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
495
496 char *Pascal_suffixes [] =
497 { "p", "pas", NULL };
498
499 char *Perl_suffixes [] =
500 { "pl", "pm", NULL };
501 char *Perl_interpreters [] =
502 { "perl", "@PERL@", NULL };
503
504 char *plain_C_suffixes [] =
505 { "pc", /* Pro*C file */
506 "m", /* Objective C file */
507 "lm", /* Objective lex file */
508 NULL };
509
510 char *Postscript_suffixes [] =
511 { "ps", NULL };
512
513 char *Prolog_suffixes [] =
514 { "prolog", NULL };
515
516 char *Python_suffixes [] =
517 { "py", NULL };
518
519 /* Can't do the `SCM' or `scm' prefix with a version number. */
520 char *Scheme_suffixes [] =
521 { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "ss", "t", NULL };
522
523 char *TeX_suffixes [] =
524 { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
525
526 char *Yacc_suffixes [] =
527 { "y", "ym", NULL }; /* .ym is Objective yacc file */
528
529 /*
530 * Table of languages.
531 *
532 * It is ok for a given function to be listed under more than one
533 * name. I just didn't.
534 */
535
536 language lang_names [] =
537 {
538 { "asm", Asm_labels, Asm_suffixes, NULL },
539 { "c", default_C_entries, default_C_suffixes, NULL },
540 { "c++", Cplusplus_entries, Cplusplus_suffixes, NULL },
541 { "c*", Cstar_entries, Cstar_suffixes, NULL },
542 { "cobol", Cobol_paragraphs, Cobol_suffixes, NULL },
543 { "erlang", Erlang_functions, Erlang_suffixes, NULL },
544 { "fortran", Fortran_functions, Fortran_suffixes, NULL },
545 { "java", Cjava_entries, Cjava_suffixes, NULL },
546 { "lisp", Lisp_functions, Lisp_suffixes, NULL },
547 { "pascal", Pascal_functions, Pascal_suffixes, NULL },
548 { "perl", Perl_functions, Perl_suffixes, Perl_interpreters },
549 { "postscript", Postscript_functions, Postscript_suffixes, NULL },
550 { "proc", plain_C_entries, plain_C_suffixes, NULL },
551 { "prolog", Prolog_functions, Prolog_suffixes, NULL },
552 { "python", Python_functions, Python_suffixes, NULL },
553 { "scheme", Scheme_functions, Scheme_suffixes, NULL },
554 { "tex", TeX_functions, TeX_suffixes, NULL },
555 { "yacc", Yacc_entries, Yacc_suffixes, NULL },
556 { "auto", NULL }, /* default guessing scheme */
557 { "none", just_read_file }, /* regexp matching only */
558 { NULL, NULL } /* end of list */
559 };
560
561
562 void
563 print_language_names ()
564 {
565 language *lang;
566 char **ext;
567
568 puts ("\nThese are the currently supported languages, along with the\n\
569 default file name suffixes:");
570 for (lang = lang_names; lang->name != NULL; lang++)
571 {
572 printf ("\t%s\t", lang->name);
573 if (lang->suffixes != NULL)
574 for (ext = lang->suffixes; *ext != NULL; ext++)
575 printf (" .%s", *ext);
576 puts ("");
577 }
578 puts ("Where `auto' means use default language for files based on file\n\
579 name suffix, and `none' means only do regexp processing on files.\n\
580 If no language is specified and no matching suffix is found,\n\
581 the first line of the file is read for a sharp-bang (#!) sequence\n\
582 followed by the name of an interpreter. If no such sequence is found,\n\
583 Fortran is tried first; if no tags are found, C is tried next.");
584 }
585
586 #ifndef VERSION
587 # define VERSION "20"
588 #endif
589 void
590 print_version ()
591 {
592 printf ("%s (GNU Emacs %s)\n", (CTAGS) ? "ctags" : "etags", VERSION);
593 puts ("Copyright (C) 1996 Free Software Foundation, Inc. and Ken Arnold");
594 puts ("This program is distributed under the same terms as Emacs");
595
596 exit (GOOD);
597 }
598
599 void
600 print_help ()
601 {
602 printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
603 \n\
604 These are the options accepted by %s.\n", progname, progname);
605 #ifdef LONG_OPTIONS
606 puts ("You may use unambiguous abbreviations for the long option names.");
607 #else
608 puts ("Long option names do not work with this executable, as it is not\n\
609 linked with GNU getopt.");
610 #endif /* LONG_OPTIONS */
611 puts ("A - as file name means read names from stdin (one per line).");
612 if (!CTAGS)
613 printf (" Absolute names are stored in the output file as they are.\n\
614 Relative ones are stored relative to the output file's directory.");
615 puts ("\n");
616
617 puts ("-a, --append\n\
618 Append tag entries to existing tags file.");
619
620 if (CTAGS)
621 puts ("-B, --backward-search\n\
622 Write the search commands for the tag entries using '?', the\n\
623 backward-search command instead of '/', the forward-search command.");
624
625 puts ("-C, --c++\n\
626 Treat files whose name suffix defaults to C language as C++ files.");
627
628 if (CTAGS)
629 puts ("-d, --defines\n\
630 Create tag entries for C #define constants and enum constants, too.");
631 else
632 puts ("-D, --no-defines\n\
633 Don't create tag entries for C #define constants and enum constants.\n\
634 This makes the tags file smaller.");
635
636 if (!CTAGS)
637 {
638 puts ("-i FILE, --include=FILE\n\
639 Include a note in tag file indicating that, when searching for\n\
640 a tag, one should also consult the tags file FILE after\n\
641 checking the current file.");
642 puts ("-l LANG, --language=LANG\n\
643 Force the following files to be considered as written in the\n\
644 named language up to the next --language=LANG option.");
645 }
646
647 if (CTAGS)
648 puts ("--globals\n\
649 Create tag entries for global variables in some languages.");
650 else
651 puts ("--no-globals\n\
652 Do not create tag entries for global variables in some\n\
653 languages. This makes the tags file smaller.");
654 puts ("--members\n\
655 Create tag entries for member variables in C and derived languages.");
656
657 #ifdef ETAGS_REGEXPS
658 puts ("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
659 Make a tag for each line matching pattern REGEXP in the\n\
660 following files. regexfile is a file containing one REGEXP\n\
661 per line. REGEXP is anchored (as if preceded by ^).\n\
662 The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
663 named tags can be created with:\n\
664 --regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
665 puts ("-R, --no-regex\n\
666 Don't create tags from regexps for the following files.");
667 #endif /* ETAGS_REGEXPS */
668 puts ("-o FILE, --output=FILE\n\
669 Write the tags to FILE.");
670 #ifdef OO_BROWSER
671 puts ("-O, --oo-browser\n\
672 Generate a specialized tags format used only by the Altrasoft OO-Browser.");
673 #endif
674 puts ("-I, --ignore-indentation\n\
675 Don't rely on indentation quite as much as normal. Currently,\n\
676 this means not to assume that a closing brace in the first\n\
677 column is the final brace of a function or structure\n\
678 definition in C and C++.");
679
680 if (CTAGS)
681 {
682 puts ("-t, --typedefs\n\
683 Generate tag entries for C typedefs.");
684 puts ("-T, --typedefs-and-c++\n\
685 Generate tag entries for C typedefs, C struct/enum/union tags,\n\
686 and C++ member functions.");
687 puts ("-u, --update\n\
688 Update the tag entries for the given files, leaving tag\n\
689 entries for other files in place. Currently, this is\n\
690 implemented by deleting the existing entries for the given\n\
691 files and then rewriting the new entries at the end of the\n\
692 tags file. It is often faster to simply rebuild the entire\n\
693 tag file than to use this.");
694 puts ("-v, --vgrind\n\
695 Generates an index of items intended for human consumption,\n\
696 similar to the output of vgrind. The index is sorted, and\n\
697 gives the page number of each item.");
698 puts ("-w, --no-warn\n\
699 Suppress warning messages about entries defined in multiple\n\
700 files.");
701 puts ("-x, --cxref\n\
702 Like --vgrind, but in the style of cxref, rather than vgrind.\n\
703 The output uses line numbers instead of page numbers, but\n\
704 beyond that the differences are cosmetic; try both to see\n\
705 which you like.");
706 }
707
708 puts ("-V, --version\n\
709 Print the version of the program.\n\
710 -h, --help\n\
711 Print this help message.");
712
713 print_language_names ();
714
715 puts ("");
716 puts ("Report bugs to bug-gnu-emacs@prep.ai.mit.edu");
717
718 exit (GOOD);
719 }
720
721
722 enum argument_type
723 {
724 at_language,
725 at_regexp,
726 at_filename
727 };
728
729 /* This structure helps us allow mixing of --lang and file names. */
730 typedef struct
731 {
732 enum argument_type arg_type;
733 char *what;
734 language *lang;
735 } argument;
736
737 #ifdef VMS /* VMS specific functions */
738
739 #define EOS '\0'
740
741 /* This is a BUG! ANY arbitrary limit is a BUG!
742 Won't someone please fix this? */
743 #define MAX_FILE_SPEC_LEN 255
744 typedef struct {
745 short curlen;
746 char body[MAX_FILE_SPEC_LEN + 1];
747 } vspec;
748
749 /*
750 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
751 returning in each successive call the next file name matching the input
752 spec. The function expects that each in_spec passed
753 to it will be processed to completion; in particular, up to and
754 including the call following that in which the last matching name
755 is returned, the function ignores the value of in_spec, and will
756 only start processing a new spec with the following call.
757 If an error occurs, on return out_spec contains the value
758 of in_spec when the error occurred.
759
760 With each successive file name returned in out_spec, the
761 function's return value is one. When there are no more matching
762 names the function returns zero. If on the first call no file
763 matches in_spec, or there is any other error, -1 is returned.
764 */
765
766 #include <rmsdef.h>
767 #include <descrip.h>
768 #define OUTSIZE MAX_FILE_SPEC_LEN
769 short
770 fn_exp (out, in)
771 vspec *out;
772 char *in;
773 {
774 static long context = 0;
775 static struct dsc$descriptor_s o;
776 static struct dsc$descriptor_s i;
777 static bool pass1 = TRUE;
778 long status;
779 short retval;
780
781 if (pass1)
782 {
783 pass1 = FALSE;
784 o.dsc$a_pointer = (char *) out;
785 o.dsc$w_length = (short)OUTSIZE;
786 i.dsc$a_pointer = in;
787 i.dsc$w_length = (short)strlen(in);
788 i.dsc$b_dtype = DSC$K_DTYPE_T;
789 i.dsc$b_class = DSC$K_CLASS_S;
790 o.dsc$b_dtype = DSC$K_DTYPE_VT;
791 o.dsc$b_class = DSC$K_CLASS_VS;
792 }
793 if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
794 {
795 out->body[out->curlen] = EOS;
796 return 1;
797 }
798 else if (status == RMS$_NMF)
799 retval = 0;
800 else
801 {
802 strcpy(out->body, in);
803 retval = -1;
804 }
805 lib$find_file_end(&context);
806 pass1 = TRUE;
807 return retval;
808 }
809
810 /*
811 v1.01 nmm 19-Aug-85 gfnames - return in successive calls the
812 name of each file specified by the provided arg expanding wildcards.
813 */
814 char *
815 gfnames (arg, p_error)
816 char *arg;
817 bool *p_error;
818 {
819 static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
820
821 switch (fn_exp (&filename, arg))
822 {
823 case 1:
824 *p_error = FALSE;
825 return filename.body;
826 case 0:
827 *p_error = FALSE;
828 return NULL;
829 default:
830 *p_error = TRUE;
831 return filename.body;
832 }
833 }
834
835 #ifndef OLD /* Newer versions of VMS do provide `system'. */
836 system (cmd)
837 char *cmd;
838 {
839 error ("%s", "system() function not implemented under VMS");
840 }
841 #endif
842
843 #define VERSION_DELIM ';'
844 char *massage_name (s)
845 char *s;
846 {
847 char *start = s;
848
849 for ( ; *s; s++)
850 if (*s == VERSION_DELIM)
851 {
852 *s = EOS;
853 break;
854 }
855 else
856 *s = lowcase (*s);
857 return start;
858 }
859 #endif /* VMS */
860
861
862 int
863 main (argc, argv)
864 int argc;
865 char *argv[];
866 {
867 int i;
868 unsigned int nincluded_files;
869 char **included_files;
870 char *this_file;
871 argument *argbuffer;
872 int current_arg, file_count;
873 linebuffer filename_lb;
874 #ifdef VMS
875 bool got_err;
876 #endif
877
878 #ifdef DOS_NT
879 _fmode = O_BINARY; /* all of files are treated as binary files */
880 #endif /* DOS_NT */
881
882 progname = argv[0];
883 nincluded_files = 0;
884 included_files = xnew (argc, char *);
885 current_arg = 0;
886 file_count = 0;
887
888 /* Allocate enough no matter what happens. Overkill, but each one
889 is small. */
890 argbuffer = xnew (argc, argument);
891
892 #ifdef ETAGS_REGEXPS
893 /* Set syntax for regular expression routines. */
894 re_set_syntax (RE_SYNTAX_EMACS | RE_INTERVALS);
895 #endif /* ETAGS_REGEXPS */
896
897 /*
898 * If etags, always find typedefs and structure tags. Why not?
899 * Also default is to find macro constants, enum constants and
900 * global variables.
901 */
902 if (!CTAGS)
903 {
904 typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
905 globals = TRUE;
906 members = FALSE;
907 }
908
909 while (1)
910 {
911 int opt;
912 char *optstring;
913
914 #ifdef ETAGS_REGEXPS
915 #ifndef OO_BROWSER
916 optstring = "-aCdDf:Il:o:r:RStTi:BuvxwVhH";
917 #else
918 optstring = "-aCdDf:Il:o:r:RStTi:BOuvxwVhH";
919 #endif
920 #else
921 #ifndef OO_BROWSER
922 optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
923 #else
924 optstring = "-aCdDf:Il:o:StTi:BOuvxwVhH";
925 #endif
926 #endif /* ETAGS_REGEXPS */
927
928 #ifndef LONG_OPTIONS
929 optstring = optstring + 1;
930 #endif /* LONG_OPTIONS */
931
932 opt = getopt_long (argc, argv, optstring, longopts, 0);
933 if (opt == EOF)
934 break;
935
936 switch (opt)
937 {
938 case 0:
939 /* If getopt returns 0, then it has already processed a
940 long-named option. We should do nothing. */
941 break;
942
943 case 1:
944 /* This means that a file name has been seen. Record it. */
945 argbuffer[current_arg].arg_type = at_filename;
946 argbuffer[current_arg].what = optarg;
947 ++current_arg;
948 ++file_count;
949 break;
950
951 /* Common options. */
952 case 'a': append_to_tagfile = TRUE; break;
953 case 'C': cplusplus = TRUE; break;
954 case 'd': constantypedefs = TRUE; break;
955 case 'D': constantypedefs = FALSE; break;
956 case 'f': /* for compatibility with old makefiles */
957 case 'o':
958 if (tagfile)
959 {
960 /* convert char to string, to call error with */
961 char buf[2];
962 sprintf (buf, "%c", opt);
963 error ("-%s option may only be given once.", buf);
964 suggest_asking_for_help ();
965 }
966 tagfile = optarg;
967 break;
968 #ifdef OO_BROWSER
969 case 'O':
970 oo_browser_format = TRUE;
971 break;
972 #endif
973 case 'I':
974 case 'S': /* for backward compatibility */
975 noindentypedefs = TRUE;
976 break;
977 case 'l':
978 {
979 language *lang = get_language_from_name (optarg);
980 if (lang != NULL)
981 {
982 argbuffer[current_arg].lang = lang;
983 argbuffer[current_arg].arg_type = at_language;
984 ++current_arg;
985 }
986 }
987 break;
988 #ifdef ETAGS_REGEXPS
989 case 'r':
990 argbuffer[current_arg].arg_type = at_regexp;
991 argbuffer[current_arg].what = optarg;
992 ++current_arg;
993 break;
994 case 'R':
995 argbuffer[current_arg].arg_type = at_regexp;
996 argbuffer[current_arg].what = NULL;
997 ++current_arg;
998 break;
999 #endif /* ETAGS_REGEXPS */
1000 case 'V':
1001 print_version ();
1002 break;
1003 case 'h':
1004 case 'H':
1005 print_help ();
1006 break;
1007 case 't':
1008 typedefs = TRUE;
1009 break;
1010 case 'T':
1011 typedefs = typedefs_and_cplusplus = TRUE;
1012 break;
1013 #if (!CTAGS)
1014 /* Etags options */
1015 case 'i':
1016 included_files[nincluded_files++] = optarg;
1017 break;
1018 #else /* CTAGS */
1019 /* Ctags options. */
1020 case 'B': searchar = '?'; break;
1021 case 'u': update = TRUE; break;
1022 case 'v': vgrind_style = TRUE; /*FALLTHRU*/
1023 case 'x': cxref_style = TRUE; break;
1024 case 'w': no_warnings = TRUE; break;
1025 #endif /* CTAGS */
1026 default:
1027 suggest_asking_for_help ();
1028 }
1029 }
1030
1031 for (; optind < argc; ++optind)
1032 {
1033 argbuffer[current_arg].arg_type = at_filename;
1034 argbuffer[current_arg].what = argv[optind];
1035 ++current_arg;
1036 ++file_count;
1037 }
1038
1039 if (nincluded_files == 0 && file_count == 0)
1040 {
1041 error ("no input files specified.", 0);
1042 suggest_asking_for_help ();
1043 }
1044
1045 if (tagfile == NULL)
1046 tagfile = CTAGS ? "tags" : "TAGS";
1047 cwd = etags_getcwd (); /* the current working directory */
1048 if (cwd[strlen (cwd) - 1] != '/')
1049 {
1050 char *oldcwd = cwd;
1051 cwd = concat (oldcwd, "/", "");
1052 free (oldcwd);
1053 }
1054 if (streq (tagfile, "-"))
1055 tagfiledir = cwd;
1056 else
1057 tagfiledir = absolute_dirname (tagfile, cwd);
1058
1059 init (); /* set up boolean "functions" */
1060
1061 initbuffer (&lb);
1062 initbuffer (&token_name);
1063 initbuffer (&lbs[0].lb);
1064 initbuffer (&lbs[1].lb);
1065 initbuffer (&filename_lb);
1066
1067 if (!CTAGS)
1068 {
1069 if (streq (tagfile, "-"))
1070 {
1071 tagf = stdout;
1072 #ifdef DOS_NT
1073 /* Switch redirected `stdout' to binary mode (setting `_fmode'
1074 doesn't take effect until after `stdout' is already open). */
1075 if (!isatty (fileno (stdout)))
1076 setmode (fileno (stdout), O_BINARY);
1077 #endif /* DOS_NT */
1078 }
1079 else
1080 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1081 if (tagf == NULL)
1082 pfatal (tagfile);
1083 }
1084
1085 /*
1086 * Loop through files finding functions.
1087 */
1088 for (i = 0; i < current_arg; ++i)
1089 {
1090 switch (argbuffer[i].arg_type)
1091 {
1092 case at_language:
1093 forced_lang = argbuffer[i].lang;
1094 break;
1095 #ifdef ETAGS_REGEXPS
1096 case at_regexp:
1097 analyse_regex (argbuffer[i].what);
1098 break;
1099 #endif
1100 case at_filename:
1101 #ifdef VMS
1102 while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
1103 {
1104 if (got_err)
1105 {
1106 error ("can't find file %s\n", this_file);
1107 argc--, argv++;
1108 }
1109 else
1110 {
1111 this_file = massage_name (this_file);
1112 }
1113 #else
1114 this_file = argbuffer[i].what;
1115 #endif
1116 #ifdef OO_BROWSER
1117 oo_browser_clear_all_globals();
1118 #endif
1119 /* Input file named "-" means read file names from stdin
1120 (one per line) and use them. */
1121 if (streq (this_file, "-"))
1122 while (readline_internal (&filename_lb, stdin) > 0)
1123 #ifdef OO_BROWSER
1124 {
1125 oo_browser_clear_some_globals();
1126 #endif
1127 process_file (filename_lb.buffer);
1128 #ifdef OO_BROWSER
1129 }
1130 #endif
1131 else
1132 process_file (this_file);
1133 #ifdef VMS
1134 }
1135 #endif
1136 break;
1137 }
1138 }
1139
1140 #ifdef ETAGS_REGEXPS
1141 free_patterns ();
1142 #endif /* ETAGS_REGEXPS */
1143
1144 if (!CTAGS)
1145 {
1146 while (nincluded_files-- > 0)
1147 fprintf (tagf, "\f\n%s,include\n", *included_files++);
1148
1149 fclose (tagf);
1150 exit (GOOD);
1151 }
1152
1153 /* If CTAGS, we are here. process_file did not write the tags yet,
1154 because we want them ordered. Let's do it now. */
1155 if (cxref_style)
1156 {
1157 put_entries (head);
1158 exit (GOOD);
1159 }
1160
1161 if (update)
1162 {
1163 char cmd[BUFSIZ];
1164 for (i = 0; i < current_arg; ++i)
1165 {
1166 if (argbuffer[i].arg_type != at_filename)
1167 continue;
1168 sprintf (cmd,
1169 "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
1170 tagfile, argbuffer[i].what, tagfile);
1171 if (system (cmd) != GOOD)
1172 fatal ("failed to execute shell command", (char *)NULL);
1173 }
1174 append_to_tagfile = TRUE;
1175 }
1176
1177 tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
1178 if (tagf == NULL)
1179 pfatal (tagfile);
1180 put_entries (head);
1181 fclose (tagf);
1182
1183 if (update)
1184 {
1185 char cmd[BUFSIZ];
1186 sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
1187 exit (system (cmd));
1188 }
1189 return GOOD;
1190 }
1191
1192
1193 /*
1194 * Return a language given the name.
1195 */
1196 language *
1197 get_language_from_name (name)
1198 char *name;
1199 {
1200 language *lang;
1201
1202 if (name == NULL)
1203 error ("empty language name", (char *)NULL);
1204 else
1205 {
1206 for (lang = lang_names; lang->name != NULL; lang++)
1207 if (streq (name, lang->name))
1208 return lang;
1209 error ("unknown language \"%s\"", name);
1210 }
1211
1212 return NULL;
1213 }
1214
1215
1216 /*
1217 * Return a language given the interpreter name.
1218 */
1219 language *
1220 get_language_from_interpreter (interpreter)
1221 char *interpreter;
1222 {
1223 language *lang;
1224 char **iname;
1225
1226 if (interpreter == NULL)
1227 return NULL;
1228 for (lang = lang_names; lang->name != NULL; lang++)
1229 if (lang->interpreters != NULL)
1230 for (iname = lang->interpreters; *iname != NULL; iname++)
1231 if (streq (*iname, interpreter))
1232 return lang;
1233
1234 return NULL;
1235 }
1236
1237
1238
1239 /*
1240 * Return a language given the file suffix.
1241 */
1242 language *
1243 get_language_from_suffix (suffix)
1244 char *suffix;
1245 {
1246 language *lang;
1247 char **ext;
1248
1249 if (suffix == NULL)
1250 return NULL;
1251 for (lang = lang_names; lang->name != NULL; lang++)
1252 if (lang->suffixes != NULL)
1253 for (ext = lang->suffixes; *ext != NULL; ext++)
1254 if (streq (*ext, suffix))
1255 return lang;
1256
1257 return NULL;
1258 }
1259
1260
1261 /*
1262 * This routine is called on each file argument.
1263 */
1264 void
1265 process_file (file)
1266 char *file;
1267 {
1268 struct stat stat_buf;
1269 FILE *inf;
1270
1271 canonicalize_filename (file);
1272 if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
1273 {
1274 error ("skipping %s: it is not a regular file.", file);
1275 return;
1276 }
1277 if (streq (file, tagfile) && !streq (tagfile, "-"))
1278 {
1279 error ("skipping inclusion of %s in self.", file);
1280 return;
1281 }
1282 inf = fopen (file, "r");
1283 if (inf == NULL)
1284 {
1285 perror (file);
1286 return;
1287 }
1288
1289 find_entries (file, inf);
1290
1291 if (!CTAGS)
1292 {
1293 char *filename;
1294
1295 if (filename_is_absolute (file))
1296 {
1297 /* file is an absolute file name. Canonicalise it. */
1298 filename = absolute_filename (file, cwd);
1299 }
1300 else
1301 {
1302 /* file is a file name relative to cwd. Make it relative
1303 to the directory of the tags file. */
1304 filename = relative_filename (file, tagfiledir);
1305 }
1306 #ifdef OO_BROWSER
1307 if (oo_browser_format)
1308 fprintf (tagf, "\f\n%s\n", filename);
1309 else
1310 #endif
1311 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1312 free (filename);
1313 put_entries (head);
1314 free_tree (head);
1315 head = NULL;
1316 }
1317 }
1318
1319 /*
1320 * This routine sets up the boolean pseudo-functions which work
1321 * by setting boolean flags dependent upon the corresponding character.
1322 * Every char which is NOT in that string is not a white char. Therefore,
1323 * all of the array "_wht" is set to FALSE, and then the elements
1324 * subscripted by the chars in "white" are set to TRUE. Thus "_wht"
1325 * of a char is TRUE if it is the string "white", else FALSE.
1326 */
1327 void
1328 init ()
1329 {
1330 register char *sp;
1331 register int i;
1332
1333 for (i = 0; i < CHARS; i++)
1334 iswhite(i) = notinname(i) = begtoken(i) = intoken(i) = endtoken(i) = FALSE;
1335 for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = TRUE;
1336 for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = TRUE;
1337 for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = TRUE;
1338 for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = TRUE;
1339 for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = TRUE;
1340 iswhite('\0') = iswhite('\n');
1341 notinname('\0') = notinname('\n');
1342 begtoken('\0') = begtoken('\n');
1343 intoken('\0') = intoken('\n');
1344 endtoken('\0') = endtoken('\n');
1345 }
1346
1347 /*
1348 * This routine opens the specified file and calls the function
1349 * which finds the function and type definitions.
1350 */
1351 node *last_node = NULL;
1352
1353 void
1354 find_entries (file, inf)
1355 char *file;
1356 FILE *inf;
1357 {
1358 char *cp;
1359 language *lang;
1360 node *old_last_node;
1361
1362 curfile = savestr (file);
1363
1364 /* If user specified a language, use it. */
1365 lang = forced_lang;
1366 if (lang != NULL && lang->function != NULL)
1367 {
1368 curlang = lang;
1369 lang->function (inf);
1370 free (curfile);
1371 fclose (inf);
1372 return;
1373 }
1374
1375 cp = etags_strrchr (file, '.');
1376 if (cp != NULL)
1377 {
1378 cp += 1;
1379 lang = get_language_from_suffix (cp);
1380 if (lang != NULL && lang->function != NULL)
1381 {
1382 curlang = lang;
1383 lang->function (inf);
1384 free (curfile);
1385 fclose (inf);
1386 return;
1387 }
1388 }
1389
1390 /* Look for sharp-bang as the first two characters. */
1391 if (readline_internal (&lb, inf) > 0
1392 && lb.len >= 2
1393 && lb.buffer[0] == '#'
1394 && lb.buffer[1] == '!')
1395 {
1396 char *lp;
1397
1398 /* Set lp to point at the first char after the last slash in the
1399 line or, if no slashes, at the first nonblank. Then set cp to
1400 the first successive blank and terminate the string. */
1401 lp = etags_strrchr (lb.buffer+2, '/');
1402 if (lp != NULL)
1403 lp += 1;
1404 else
1405 lp = skip_spaces (lb.buffer + 2);
1406 cp = skip_non_spaces (lp);
1407 *cp = '\0';
1408
1409 if (strlen (lp) > 0)
1410 {
1411 lang = get_language_from_interpreter (lp);
1412 if (lang != NULL && lang->function != NULL)
1413 {
1414 curlang = lang;
1415 lang->function (inf);
1416 fclose (inf);
1417 free (curfile);
1418 return;
1419 }
1420 }
1421 }
1422 rewind (inf);
1423
1424 /* Try Fortran. */
1425 old_last_node = last_node;
1426 curlang = get_language_from_name ("fortran");
1427 Fortran_functions (inf);
1428
1429 /* No Fortran entries found. Try C. */
1430 if (old_last_node == last_node)
1431 {
1432 rewind (inf);
1433 curlang = get_language_from_name (cplusplus ? "c++" : "c");
1434 default_C_entries (inf);
1435 }
1436 free (curfile);
1437 fclose (inf);
1438 return;
1439 }
1440
1441 /* Record a tag. */
1442 void
1443 pfnote (name, is_func, linestart, linelen, lno, cno)
1444 char *name; /* tag name, or NULL if unnamed */
1445 bool is_func; /* tag is a function */
1446 char *linestart; /* start of the line where tag is */
1447 int linelen; /* length of the line where tag is */
1448 int lno; /* line number */
1449 long cno; /* character number */
1450 {
1451 register node *np;
1452
1453 if (CTAGS && name == NULL)
1454 return;
1455
1456 np = xnew (1, node);
1457
1458 /* If ctags mode, change name "main" to M<thisfilename>. */
1459 if (CTAGS && !cxref_style && streq (name, "main"))
1460 {
1461 register char *fp = etags_strrchr (curfile, '/');
1462 np->name = concat ("M", fp == 0 ? curfile : fp + 1, "");
1463 fp = etags_strrchr (np->name, '.');
1464 if (fp && fp[1] != '\0' && fp[2] == '\0')
1465 fp[0] = 0;
1466 }
1467 else
1468 np->name = name;
1469 np->been_warned = FALSE;
1470 np->file = curfile;
1471 np->is_func = is_func;
1472 np->lno = lno;
1473 /* Our char numbers are 0-base, because of C language tradition?
1474 ctags compatibility? old versions compatibility? I don't know.
1475 Anyway, since emacs's are 1-base we expect etags.el to take care
1476 of the difference. If we wanted to have 1-based numbers, we would
1477 uncomment the +1 below. */
1478 np->cno = cno /* + 1 */ ;
1479 np->left = np->right = NULL;
1480 if (CTAGS && !cxref_style)
1481 {
1482 if (strlen (linestart) < 50)
1483 np->pat = concat (linestart, "$", "");
1484 else
1485 np->pat = savenstr (linestart, 50);
1486 }
1487 else
1488 np->pat = savenstr (linestart, linelen);
1489
1490 #ifdef OO_BROWSER
1491 if (oo_browser_format)
1492 np->construct = oo_browser_construct;
1493 oo_browser_construct = C_NULL;
1494 oo_browser_check_and_clear_structtype();
1495 #endif
1496
1497 add_node (np, &head);
1498 }
1499
1500 /* Date: Wed, 22 Jan 1997 02:56:31 -0500 [last amended 18 Sep 1997]
1501 * From: Sam Kendall <kendall@mv.mv.com>
1502 * Subject: Proposal for firming up the TAGS format specification
1503 * To: F.Potorti@cnuce.cnr.it
1504 *
1505 * pfnote should emit the optimized form [unnamed tag] only if:
1506 * 1. name does not contain any of the characters " \t\r\n(),;";
1507 * 2. linestart contains name as either a rightmost, or rightmost but
1508 * one character, substring;
1509 * 3. the character, if any, immediately before name in linestart must
1510 * be one of the characters " \t(),;";
1511 * 4. the character, if any, immediately after name in linestart must
1512 * also be one of the characters " \t(),;".
1513 *
1514 * The real implementation uses the notinname() macro, which recognises
1515 * characters slightly different form " \t\r\n(),;". See the variable
1516 * `nonam'.
1517 */
1518 #define traditional_tag_style TRUE
1519 void
1520 new_pfnote (name, namelen, is_func, linestart, linelen, lno, cno)
1521 char *name; /* tag name, or NULL if unnamed */
1522 int namelen; /* tag length */
1523 bool is_func; /* tag is a function */
1524 char *linestart; /* start of the line where tag is */
1525 int linelen; /* length of the line where tag is */
1526 int lno; /* line number */
1527 long cno; /* character number */
1528 {
1529 register char *cp;
1530 bool named;
1531
1532 named = TRUE;
1533 if (!CTAGS)
1534 {
1535 for (cp = name; !notinname (*cp); cp++)
1536 continue;
1537 if (*cp == '\0') /* rule #1 */
1538 {
1539 cp = linestart + linelen - namelen;
1540 if (notinname (linestart[linelen-1]))
1541 cp -= 1; /* rule #4 */
1542 #ifdef OO_BROWSER
1543 if (!oo_browser_format
1544 && cp >= linestart /* rule #2 */
1545 #else
1546 if (cp >= linestart /* rule #2 */
1547 #endif
1548 && (cp == linestart
1549 || notinname (cp[-1])) /* rule #3 */
1550 && strneq (name, cp, namelen)) /* rule #2 */
1551 named = FALSE; /* use unnamed tag */
1552 }
1553 }
1554
1555 if (named)
1556 name = savenstr (name, namelen);
1557 else
1558 name = NULL;
1559 pfnote (name, is_func, linestart, linelen, lno, cno);
1560 }
1561
1562 /*
1563 * free_tree ()
1564 * recurse on left children, iterate on right children.
1565 */
1566 void
1567 free_tree (np)
1568 register node *np;
1569 {
1570 while (np)
1571 {
1572 register node *node_right = np->right;
1573 free_tree (np->left);
1574 if (np->name != NULL)
1575 free (np->name);
1576 free (np->pat);
1577 free (np);
1578 np = node_right;
1579 }
1580 }
1581
1582 /*
1583 * add_node ()
1584 * Adds a node to the tree of nodes. In etags mode, we don't keep
1585 * it sorted; we just keep a linear list. In ctags mode, maintain
1586 * an ordered tree, with no attempt at balancing.
1587 *
1588 * add_node is the only function allowed to add nodes, so it can
1589 * maintain state.
1590 */
1591 void
1592 add_node (np, cur_node_p)
1593 node *np, **cur_node_p;
1594 {
1595 register int dif;
1596 register node *cur_node = *cur_node_p;
1597
1598 if (cur_node == NULL)
1599 {
1600 *cur_node_p = np;
1601 last_node = np;
1602 return;
1603 }
1604
1605 if (!CTAGS)
1606 {
1607 /* Etags Mode */
1608 if (last_node == NULL)
1609 fatal ("internal error in add_node", (char *)NULL);
1610 last_node->right = np;
1611 last_node = np;
1612 }
1613 else
1614 {
1615 /* Ctags Mode */
1616 dif = strcmp (np->name, cur_node->name);
1617
1618 /*
1619 * If this tag name matches an existing one, then
1620 * do not add the node, but maybe print a warning.
1621 */
1622 if (!dif)
1623 {
1624 if (streq (np->file, cur_node->file))
1625 {
1626 if (!no_warnings)
1627 {
1628 fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
1629 np->file, lineno, np->name);
1630 fprintf (stderr, "Second entry ignored\n");
1631 }
1632 }
1633 else if (!cur_node->been_warned && !no_warnings)
1634 {
1635 fprintf
1636 (stderr,
1637 "Duplicate entry in files %s and %s: %s (Warning only)\n",
1638 np->file, cur_node->file, np->name);
1639 cur_node->been_warned = TRUE;
1640 }
1641 return;
1642 }
1643
1644 /* Actually add the node */
1645 add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
1646 }
1647 }
1648
1649 #ifdef OO_BROWSER
1650 /* Default class name for the current OO-Browser tag. */
1651 static char *oo_browser_class;
1652 /* Prefix character to use in OO-Browser listings for the current tag. */
1653 static char oo_browser_prefix;
1654 #endif
1655
1656 void
1657 put_entries (np)
1658 register node *np;
1659 {
1660 register char *sp;
1661
1662 if (np == NULL)
1663 return;
1664
1665 /* Output subentries that precede this one */
1666 put_entries (np->left);
1667
1668 /* Output this entry */
1669
1670 if (!CTAGS)
1671 {
1672 #ifdef OO_BROWSER
1673 if (oo_browser_format)
1674 {
1675 /* Omit C++ `class' and `method' entries as well as Objective-C
1676 entries from this OO-Browser tags file since the browser handles
1677 them independently of this file. Omit `extern' variable declarations
1678 as they are unused by the OO-Browser. */
1679 if (np->construct != C_CLASS
1680 && np->construct != C_METHOD
1681 && np->construct != C_EXTERN
1682 && np->construct != C_OBJC)
1683 {
1684 oo_browser_class = oo_browser_default_classes[np->construct];
1685 switch (np->construct)
1686 {
1687 case C_CONSTANT:
1688 case C_ENUMERATION:
1689 case C_ENUM_LABEL:
1690 case C_STRUCTURE:
1691 case C_TYPE:
1692 case C_UNION:
1693 case C_VARIABLE:
1694 oo_browser_prefix = '=';
1695 break;
1696 case C_FUNCTION:
1697 case C_MACRO:
1698 oo_browser_prefix = '-';
1699 break;
1700 }
1701 if (np->name != NULL)
1702 fprintf (tagf, "%s@%c %s@%s\n",
1703 oo_browser_class, oo_browser_prefix,
1704 np->name, np->pat);
1705 else
1706 fprintf (tagf, "%s@%c ???@%s\n",
1707 oo_browser_class, oo_browser_prefix, np->pat);
1708 }
1709 }
1710 else
1711 {
1712 #endif
1713 if (np->name != NULL)
1714 fprintf (tagf, "%s\177%s\001%d,%ld\n",
1715 np->pat, np->name, np->lno, np->cno);
1716 else
1717 fprintf (tagf, "%s\177%d,%ld\n",
1718 np->pat, np->lno, np->cno);
1719 #ifdef OO_BROWSER
1720 }
1721 #endif
1722 }
1723 else
1724 {
1725 if (np->name == NULL)
1726 error ("internal error: NULL name in ctags mode.", (char *)NULL);
1727
1728 if (cxref_style)
1729 {
1730 if (vgrind_style)
1731 fprintf (stdout, "%s %s %d\n",
1732 np->name, np->file, (np->lno + 63) / 64);
1733 else
1734 fprintf (stdout, "%-16s %3d %-16s %s\n",
1735 np->name, np->lno, np->file, np->pat);
1736 }
1737 else
1738 {
1739 fprintf (tagf, "%s\t%s\t", np->name, np->file);
1740
1741 if (np->is_func)
1742 { /* a function */
1743 putc (searchar, tagf);
1744 putc ('^', tagf);
1745
1746 for (sp = np->pat; *sp; sp++)
1747 {
1748 if (*sp == '\\' || *sp == searchar)
1749 putc ('\\', tagf);
1750 putc (*sp, tagf);
1751 }
1752 putc (searchar, tagf);
1753 }
1754 else
1755 { /* a typedef; text pattern inadequate */
1756 fprintf (tagf, "%d", np->lno);
1757 }
1758 putc ('\n', tagf);
1759 }
1760 }
1761
1762 /* Output subentries that follow this one */
1763 put_entries (np->right);
1764 }
1765
1766 /* Length of a number's decimal representation. */
1767 int number_len PP ((long num));
1768 int
1769 number_len (num)
1770 long num;
1771 {
1772 int len = 1;
1773 while ((num /= 10) > 0)
1774 len += 1;
1775 return len;
1776 }
1777
1778 /*
1779 * Return total number of characters that put_entries will output for
1780 * the nodes in the subtree of the specified node. Works only if
1781 * we are not ctags, but called only in that case. This count
1782 * is irrelevant with the new tags.el, but is still supplied for
1783 * backward compatibility.
1784 */
1785 int
1786 total_size_of_entries (np)
1787 register node *np;
1788 {
1789 register int total;
1790
1791 if (np == NULL)
1792 return 0;
1793
1794 for (total = 0; np != NULL; np = np->right)
1795 {
1796 /* Count left subentries. */
1797 total += total_size_of_entries (np->left);
1798
1799 /* Count this entry */
1800 total += strlen (np->pat) + 1;
1801 total += number_len ((long) np->lno) + 1 + number_len (np->cno) + 1;
1802 if (np->name != NULL)
1803 total += 1 + strlen (np->name); /* \001name */
1804 }
1805
1806 return total;
1807 }
1808
1809 /*
1810 * The C symbol tables.
1811 */
1812 enum sym_type
1813 {
1814 st_none,
1815 st_C_objprot, st_C_objimpl, st_C_objend,
1816 st_C_gnumacro,
1817 st_C_ignore,
1818 st_C_javastruct,
1819 st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec,
1820 st_C_const
1821 #ifdef OO_BROWSER
1822 , st_C_union, st_C_class, st_C_extern, st_C_inline
1823 #endif
1824 };
1825
1826 /* Feed stuff between (but not including) %[ and %] lines to:
1827 gperf -c -k 1,3 -o -p -r -t
1828 %[
1829 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
1830 %%
1831 @interface, 0, st_C_objprot
1832 @protocol, 0, st_C_objprot
1833 @implementation,0, st_C_objimpl
1834 @end, 0, st_C_objend
1835 import, C_JAVA, st_C_ignore
1836 package, C_JAVA, st_C_ignore
1837 friend, C_PLPL, st_C_ignore
1838 extends, C_JAVA, st_C_javastruct
1839 implements, C_JAVA, st_C_javastruct
1840 interface, C_JAVA, st_C_struct
1841 class, C_PLPL, st_C_class
1842 namespace, C_PLPL, st_C_struct
1843 domain, C_STAR, st_C_struct
1844 union, 0, st_C_union
1845 struct, 0, st_C_struct
1846 enum, 0, st_C_enum
1847 typedef, 0, st_C_typedef
1848 define, 0, st_C_define
1849 inline, 0, st_C_inline
1850 bool, C_PLPL, st_C_typespec
1851 long, 0, st_C_typespec
1852 short, 0, st_C_typespec
1853 int, 0, st_C_typespec
1854 char, 0, st_C_typespec
1855 float, 0, st_C_typespec
1856 double, 0, st_C_typespec
1857 signed, 0, st_C_typespec
1858 unsigned, 0, st_C_typespec
1859 auto, 0, st_C_typespec
1860 void, 0, st_C_typespec
1861 extern, 0, st_C_extern
1862 static, 0, st_C_typespec
1863 const, 0, st_C_const
1864 volatile, 0, st_C_typespec
1865 explicit, C_PLPL, st_C_typespec
1866 mutable, C_PLPL, st_C_typespec
1867 typename, C_PLPL, st_C_typespec
1868 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
1869 DEFUN, 0, st_C_gnumacro
1870 SYSCALL, 0, st_C_gnumacro
1871 ENTRY, 0, st_C_gnumacro
1872 PSEUDO, 0, st_C_gnumacro
1873 # These are defined inside C functions, so currently they are not met.
1874 # EXFUN used in glibc, DEFVAR_* in emacs.
1875 #EXFUN, 0, st_C_gnumacro
1876 #DEFVAR_, 0, st_C_gnumacro
1877 %]
1878 and replace lines between %< and %> with its output. */
1879 /*%<*/
1880 /* C code produced by gperf version 2.5 (GNU C++ version) */
1881 /* Command-line: gperf -c -k 1,3 -o -p -r -t */
1882 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
1883
1884 #define TOTAL_KEYWORDS 41
1885 #define MIN_WORD_LENGTH 3
1886 #define MAX_WORD_LENGTH 15
1887 #define MIN_HASH_VALUE 13
1888 #define MAX_HASH_VALUE 129
1889 /* maximum key range = 117, duplicates = 0 */
1890
1891 static unsigned int
1892 hash (str, len)
1893 register char *str;
1894 register int unsigned len;
1895 {
1896 static unsigned char asso_values[] =
1897 {
1898 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1899 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1900 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1901 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1902 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1903 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1904 130, 130, 130, 130, 13, 130, 130, 130, 33, 32,
1905 47, 130, 130, 130, 130, 130, 130, 130, 130, 130,
1906 5, 130, 130, 20, 32, 130, 130, 130, 130, 130,
1907 130, 130, 130, 130, 130, 130, 130, 47, 55, 8,
1908 15, 33, 61, 38, 130, 60, 130, 130, 2, 9,
1909 10, 62, 59, 130, 28, 27, 50, 19, 3, 130,
1910 130, 130, 130, 130, 130, 130, 130, 130,
1911 };
1912 return len + asso_values[str[2]] + asso_values[str[0]];
1913 }
1914
1915 struct C_stab_entry *
1916 in_word_set (str, len)
1917 register char *str;
1918 register unsigned int len;
1919 {
1920 static struct C_stab_entry wordlist[] =
1921 {
1922 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1923 {"",}, {"",}, {"",}, {"",},
1924 {"volatile", 0, st_C_typespec},
1925 {"",}, {"",},
1926 {"long", 0, st_C_typespec},
1927 {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1928 {"const", 0, st_C_const},
1929 {"",}, {"",}, {"",},
1930 {"@end", 0, st_C_objend},
1931 {"namespace", C_PLPL, st_C_struct},
1932 {"",},
1933 {"domain", C_STAR, st_C_struct},
1934 {"",}, {"",},
1935 {"@interface", 0, st_C_objprot},
1936 {"",}, {"",}, {"",},
1937 {"@implementation", 0, st_C_objimpl},
1938 {"",}, {"",},
1939 {"double", 0, st_C_typespec},
1940 {"",}, {"",},
1941 {"PSEUDO", 0, st_C_gnumacro},
1942 {"",}, {"",}, {"",},
1943 {"SYSCALL", 0, st_C_gnumacro},
1944 {"",}, {"",},
1945 {"@protocol", 0, st_C_objprot},
1946 {"",}, {"",}, {"",},
1947 {"unsigned", 0, st_C_typespec},
1948 {"",},
1949 {"enum", 0, st_C_enum},
1950 {"",}, {"",},
1951 {"char", 0, st_C_typespec},
1952 {"class", C_PLPL, st_C_class},
1953 {"struct", 0, st_C_struct},
1954 {"",}, {"",}, {"",}, {"",},
1955 {"mutable", C_PLPL, st_C_typespec},
1956 {"void", 0, st_C_typespec},
1957 {"inline", 0, st_C_inline},
1958 {"ENTRY", 0, st_C_gnumacro},
1959 {"",},
1960 {"signed", 0, st_C_typespec},
1961 {"",}, {"",},
1962 {"package", C_JAVA, st_C_ignore},
1963 {"",}, {"",}, {"",}, {"",}, {"",},
1964 {"static", 0, st_C_typespec},
1965 {"",},
1966 {"define", 0, st_C_define},
1967 {"",},
1968 {"union", 0, st_C_union},
1969 {"DEFUN", 0, st_C_gnumacro},
1970 {"",}, {"",}, {"",},
1971 {"extern", 0, st_C_extern},
1972 {"extends", C_JAVA, st_C_javastruct},
1973 {"",}, {"",}, {"",},
1974 {"short", 0, st_C_typespec},
1975 {"",}, {"",}, {"",}, {"",}, {"",},
1976 {"explicit", C_PLPL, st_C_typespec},
1977 {"auto", 0, st_C_typespec},
1978 {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
1979 {"",}, {"",},
1980 {"int", 0, st_C_typespec},
1981 {"",}, {"",},
1982 {"typedef", 0, st_C_typedef},
1983 {"typename", C_PLPL, st_C_typespec},
1984 {"",},
1985 {"interface", C_JAVA, st_C_struct},
1986 {"",},
1987 {"bool", C_PLPL, st_C_typespec},
1988 {"",}, {"",}, {"",},
1989 {"import", C_JAVA, st_C_ignore},
1990 {"",},
1991 {"friend", C_PLPL, st_C_ignore},
1992 {"float", 0, st_C_typespec},
1993 {"implements", C_JAVA, st_C_javastruct},
1994 };
1995
1996 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
1997 {
1998 register int key = hash (str, len);
1999
2000 if (key <= MAX_HASH_VALUE && key >= 0)
2001 {
2002 register char *s = wordlist[key].name;
2003
2004 if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
2005 return &wordlist[key];
2006 }
2007 }
2008 return 0;
2009 }
2010 /*%>*/
2011
2012 enum sym_type C_symtype PP ((char *str, int len, int c_ext));
2013 enum sym_type
2014 C_symtype (str, len, c_ext)
2015 char *str;
2016 int len;
2017 int c_ext;
2018 {
2019 register struct C_stab_entry *se = in_word_set (str, len);
2020
2021 if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
2022 return st_none;
2023 return se->type;
2024 }
2025
2026 /*
2027 * C functions and variables are recognized using a simple
2028 * finite automaton. fvdef is its state variable.
2029 */
2030 enum
2031 {
2032 fvnone, /* nothing seen */
2033 fvnameseen, /* function or variable name seen */
2034 fstartlist, /* func: just after open parenthesis */
2035 finlist, /* func: in parameter list */
2036 flistseen, /* func: after parameter list */
2037 fignore, /* func: before open brace */
2038 vignore /* var-like: ignore until ';' */
2039 } fvdef;
2040
2041
2042 /*
2043 * typedefs are recognized using a simple finite automaton.
2044 * typdef is its state variable.
2045 */
2046 enum
2047 {
2048 tnone, /* nothing seen */
2049 ttypedseen, /* typedef keyword seen */
2050 tinbody, /* inside typedef body */
2051 tend, /* just before typedef tag */
2052 tignore /* junk after typedef tag */
2053 } typdef;
2054
2055
2056 /*
2057 * struct-like structures (enum, struct and union) are recognized
2058 * using another simple finite automaton. `structdef' is its state
2059 * variable.
2060 */
2061 enum
2062 {
2063 snone, /* nothing seen yet */
2064 skeyseen, /* struct-like keyword seen */
2065 stagseen, /* struct-like tag seen */
2066 scolonseen, /* colon seen after struct-like tag */
2067 sinbody /* in struct body: recognize member func defs*/
2068 } structdef;
2069
2070 /*
2071 * When structdef is stagseen, scolonseen, or sinbody, structtag is the
2072 * struct tag, and structtype is the type of the preceding struct-like
2073 * keyword.
2074 */
2075 char *structtag = "<uninited>";
2076 enum sym_type structtype;
2077
2078 #ifdef OO_BROWSER
2079 void
2080 oo_browser_check_and_clear_structtype()
2081 {
2082 /* Allow for multiple enum_label tags. */
2083 if (structtype != st_C_enum)
2084 structtype = st_none;
2085 }
2086 #endif
2087
2088 /*
2089 * When objdef is different from onone, objtag is the name of the class.
2090 */
2091 char *objtag = "<uninited>";
2092
2093 /*
2094 * Yet another little state machine to deal with preprocessor lines.
2095 */
2096 enum
2097 {
2098 dnone, /* nothing seen */
2099 dsharpseen, /* '#' seen as first char on line */
2100 ddefineseen, /* '#' and 'define' seen */
2101 dignorerest /* ignore rest of line */
2102 } definedef;
2103
2104 /*
2105 * State machine for Objective C protocols and implementations.
2106 * Tom R.Hageman <tom@basil.icce.rug.nl>
2107 */
2108 enum
2109 {
2110 onone, /* nothing seen */
2111 oprotocol, /* @interface or @protocol seen */
2112 oimplementation, /* @implementations seen */
2113 otagseen, /* class name seen */
2114 oparenseen, /* parenthesis before category seen */
2115 ocatseen, /* category name seen */
2116 oinbody, /* in @implementation body */
2117 omethodsign, /* in @implementation body, after +/- */
2118 omethodtag, /* after method name */
2119 omethodcolon, /* after method colon */
2120 omethodparm, /* after method parameter */
2121 oignore /* wait for @end */
2122 } objdef;
2123
2124 /*
2125 * Use this structure to keep info about the token read, and how it
2126 * should be tagged. Used by the make_C_tag function to build a tag.
2127 */
2128 typedef struct
2129 {
2130 bool valid;
2131 char *str;
2132 bool named;
2133 int linelen;
2134 int lineno;
2135 long linepos;
2136 char *buffer;
2137 } token;
2138
2139 token tok; /* latest token read */
2140
2141 /*
2142 * Set this to TRUE, and the next token considered is called a function.
2143 * Used only for GNU emacs's function-defining macros.
2144 */
2145 bool next_token_is_func;
2146
2147 /*
2148 * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
2149 */
2150 bool yacc_rules;
2151
2152 /*
2153 * methodlen is the length of the method name stored in token_name.
2154 */
2155 int methodlen;
2156
2157 #ifdef OO_BROWSER
2158 void
2159 oo_browser_clear_all_globals()
2160 {
2161 /* Initialize globals so there is no carry over between files. */
2162 oo_browser_construct = C_NULL;
2163 fvdef = fvnone; typdef = tnone; structdef = snone;
2164 definedef = dnone; objdef = onone;
2165 structtype = st_none;
2166 next_token_is_func = yacc_rules = FALSE;
2167 }
2168
2169 void
2170 oo_browser_clear_some_globals()
2171 {
2172 oo_browser_construct = C_NULL;
2173 structtype = st_none;
2174 }
2175 #endif
2176
2177 /*
2178 * consider_token ()
2179 * checks to see if the current token is at the start of a
2180 * function or variable, or corresponds to a typedef, or
2181 * is a struct/union/enum tag, or #define, or an enum constant.
2182 *
2183 * *IS_FUNC gets TRUE iff the token is a function or #define macro
2184 * with args. C_EXT is which language we are looking at.
2185 *
2186 * In the future we will need some way to adjust where the end of
2187 * the token is; for instance, implementing the C++ keyword
2188 * `operator' properly will adjust the end of the token to be after
2189 * whatever follows `operator'.
2190 *
2191 * Globals
2192 * fvdef IN OUT
2193 * structdef IN OUT
2194 * definedef IN OUT
2195 * typdef IN OUT
2196 * objdef IN OUT
2197 * next_token_is_func IN OUT
2198 */
2199 bool consider_token PP ((char *str, int len, int c, int c_ext,
2200 int cblev, int parlev, bool *is_func_or_var));
2201 bool
2202 consider_token (str, len, c, c_ext, cblev, parlev, is_func_or_var)
2203 register char *str; /* IN: token pointer */
2204 register int len; /* IN: token length */
2205 register int c; /* IN: first char after the token */
2206 int c_ext; /* IN: C extensions mask */
2207 int cblev; /* IN: curly brace level */
2208 int parlev; /* IN: parenthesis level */
2209 bool *is_func_or_var; /* OUT: function or variable found */
2210 {
2211 enum sym_type toktype = C_symtype (str, len, c_ext);
2212
2213 #ifdef OO_BROWSER
2214 switch (toktype)
2215 {
2216 case st_C_struct:
2217 set_construct(C_STRUCTURE);
2218 break;
2219 case st_C_union:
2220 set_construct(C_UNION);
2221 break;
2222 case st_C_class:
2223 set_construct(C_CLASS);
2224 break;
2225 case st_C_enum:
2226 set_construct(C_ENUMERATION);
2227 break;
2228 case st_C_typedef:
2229 set_construct(C_TYPE);
2230 break;
2231 case st_C_extern:
2232 set_construct(C_EXTERN);
2233 break;
2234 case st_C_inline:
2235 set_construct(C_FUNCTION);
2236 break;
2237 }
2238 #endif
2239
2240 /*
2241 * Advance the definedef state machine.
2242 */
2243 switch (definedef)
2244 {
2245 case dnone:
2246 /* We're not on a preprocessor line. */
2247 break;
2248 case dsharpseen:
2249 if (toktype == st_C_define)
2250 {
2251 definedef = ddefineseen;
2252 }
2253 else
2254 {
2255 definedef = dignorerest;
2256 }
2257 return FALSE;
2258 case ddefineseen:
2259 /*
2260 * Make a tag for any macro, unless it is a constant
2261 * and constantypedefs is FALSE.
2262 */
2263 definedef = dignorerest;
2264 #ifndef OO_BROWSER
2265 *is_func_or_var = (c == '(');
2266 #else
2267 {
2268 char *p = str + len * sizeof(char);
2269
2270 if (*p == '(')
2271 /* This must be a macro since there is no
2272 whitespace between the opening parenthesis
2273 and the definition name. */
2274 *is_func_or_var = TRUE;
2275 else
2276 {
2277 *is_func_or_var = FALSE;
2278
2279 /* Handle possible whitespace between macro tag and opening
2280 parenthesis and ensure this is an actual macro.
2281 -- Bob Weiner, Altrasoft, 11/19/1997 */
2282 while (*p && isspace(*p)) p++;
2283 if (*p) c = *p;
2284
2285 /* Skip over nested parentheses. */
2286 if (c == '(')
2287 {
2288 short depth = 1;
2289
2290 while (*++p && depth > 0 && *p != '\n')
2291 {
2292 switch (*p)
2293 {
2294 case '(':
2295 depth++; break;
2296 case ')':
2297 depth--; break;
2298 }
2299 }
2300
2301 /* If this is a macro, we have just passed
2302 the arguments and there will be more on
2303 the line before the NULL character that marks
2304 the end of the line token. */
2305 while (*p == ' ' || *p == '\t') p++;
2306 if (*p) *is_func_or_var = TRUE;
2307 }
2308 }
2309 }
2310
2311 set_construct((*is_func_or_var) ? C_MACRO : C_CONSTANT);
2312 #endif
2313 if (!*is_func_or_var && !constantypedefs)
2314 return FALSE;
2315 else
2316 return TRUE;
2317 case dignorerest:
2318 return FALSE;
2319 default:
2320 error ("internal error: definedef value.", (char *)NULL);
2321 }
2322
2323 /*
2324 * Now typedefs
2325 */
2326 switch (typdef)
2327 {
2328 case tnone:
2329 if (toktype == st_C_typedef)
2330 {
2331 if (typedefs)
2332 typdef = ttypedseen;
2333 fvdef = fvnone;
2334 return FALSE;
2335 }
2336 break;
2337 case ttypedseen:
2338 switch (toktype)
2339 {
2340 case st_C_const:
2341 set_construct(C_CONSTANT);
2342 /* fall through */
2343 case st_none:
2344 case st_C_typespec:
2345 #ifdef OO_BROWSER
2346 case st_C_extern:
2347 #endif
2348 typdef = tend;
2349 break;
2350 case st_C_struct:
2351 case st_C_enum:
2352 #ifdef OO_BROWSER
2353 case st_C_union:
2354 case st_C_class:
2355 #endif
2356 break;
2357 }
2358 /* Do not return here, so the structdef stuff has a chance. */
2359 break;
2360 case tend:
2361 switch (toktype)
2362 {
2363 case st_C_const:
2364 set_construct(C_CONSTANT);
2365 /* fall through */
2366 case st_C_typespec:
2367 case st_C_struct:
2368 case st_C_enum:
2369 #ifdef OO_BROWSER
2370 case st_C_extern:
2371 case st_C_union:
2372 case st_C_class:
2373 #endif
2374 return FALSE;
2375 }
2376 return TRUE;
2377 }
2378
2379 /*
2380 * This structdef business is currently only invoked when cblev==0.
2381 * It should be recursively invoked whatever the curly brace level,
2382 * and a stack of states kept, to allow for definitions of structs
2383 * within structs.
2384 *
2385 * This structdef business is NOT invoked when we are ctags and the
2386 * file is plain C. This is because a struct tag may have the same
2387 * name as another tag, and this loses with ctags.
2388 */
2389 switch (toktype)
2390 {
2391 case st_C_javastruct:
2392 if (structdef == stagseen)
2393 structdef = scolonseen;
2394 return FALSE;
2395 case st_C_struct:
2396 case st_C_enum:
2397 #ifdef OO_BROWSER
2398 case st_C_union:
2399 case st_C_class:
2400 case st_C_extern:
2401 #endif
2402 if (typdef == ttypedseen
2403 || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
2404 {
2405 structdef = skeyseen;
2406 structtype = toktype;
2407 }
2408 return FALSE;
2409 }
2410
2411 if (structdef == skeyseen)
2412 {
2413 /* Save the tag for struct/union/class, for functions and variables
2414 that may be defined inside. */
2415 #ifndef OO_BROWSER
2416 if (structtype == st_C_struct)
2417 #else
2418 if (structtype == st_C_struct
2419 || structtype == st_C_union
2420 || structtype == st_C_class)
2421 #endif
2422 structtag = savenstr (str, len);
2423 else
2424 structtag = "<enum>";
2425 structdef = stagseen;
2426 return TRUE;
2427 }
2428
2429 /* Avoid entering fvdef stuff if typdef is going on. */
2430 if (typdef != tnone)
2431 {
2432 definedef = dnone;
2433 return FALSE;
2434 }
2435
2436 /* Detect GNU macros.
2437
2438 DEFUN note for writers of emacs C code:
2439 The DEFUN macro, used in emacs C source code, has a first arg
2440 that is a string (the lisp function name), and a second arg that
2441 is a C function name. Since etags skips strings, the second arg
2442 is tagged. This is unfortunate, as it would be better to tag the
2443 first arg. The simplest way to deal with this problem would be
2444 to name the tag with a name built from the function name, by
2445 removing the initial 'F' character and substituting '-' for '_'.
2446 Anyway, this assumes that the conventions of naming lisp
2447 functions will never change. Currently, this method is not
2448 implemented, so writers of emacs code are recommended to put the
2449 first two args of a DEFUN on the same line. */
2450 if (definedef == dnone && toktype == st_C_gnumacro)
2451 {
2452 next_token_is_func = TRUE;
2453 return FALSE;
2454 }
2455 if (next_token_is_func)
2456 {
2457 next_token_is_func = FALSE;
2458 fvdef = fignore;
2459 *is_func_or_var = TRUE;
2460 return TRUE;
2461 }
2462
2463 /* Detect Objective C constructs. */
2464 switch (objdef)
2465 {
2466 case onone:
2467 switch (toktype)
2468 {
2469 case st_C_objprot:
2470 #ifdef OO_BROWSER
2471 set_construct(C_OBJC);
2472 #endif
2473 objdef = oprotocol;
2474 return FALSE;
2475 case st_C_objimpl:
2476 #ifdef OO_BROWSER
2477 set_construct(C_OBJC);
2478 #endif
2479 objdef = oimplementation;
2480 return FALSE;
2481 }
2482 break;
2483 case oimplementation:
2484 /* Save the class tag for functions or variables defined inside. */
2485 objtag = savenstr (str, len);
2486 objdef = oinbody;
2487 return FALSE;
2488 case oprotocol:
2489 /* Save the class tag for categories. */
2490 objtag = savenstr (str, len);
2491 objdef = otagseen;
2492 *is_func_or_var = TRUE;
2493 return TRUE;
2494 case oparenseen:
2495 objdef = ocatseen;
2496 *is_func_or_var = TRUE;
2497 return TRUE;
2498 case oinbody:
2499 break;
2500 case omethodsign:
2501 if (parlev == 0)
2502 {
2503 objdef = omethodtag;
2504 methodlen = len;
2505 grow_linebuffer (&token_name, methodlen + 1);
2506 strncpy (token_name.buffer, str, len);
2507 token_name.buffer[methodlen] = '\0';
2508 token_name.len = methodlen;
2509 return TRUE;
2510 }
2511 return FALSE;
2512 case omethodcolon:
2513 if (parlev == 0)
2514 objdef = omethodparm;
2515 return FALSE;
2516 case omethodparm:
2517 if (parlev == 0)
2518 {
2519 objdef = omethodtag;
2520 methodlen += len;
2521 grow_linebuffer (&token_name, methodlen + 1);
2522 strncat (token_name.buffer, str, len);
2523 token_name.len = methodlen;
2524 return TRUE;
2525 }
2526 return FALSE;
2527 case oignore:
2528 if (toktype == st_C_objend)
2529 {
2530 /* Memory leakage here: the string pointed by objtag is
2531 never released, because many tests would be needed to
2532 avoid breaking on incorrect input code. The amount of
2533 memory leaked here is the sum of the lengths of the
2534 class tags.
2535 free (objtag); */
2536 objdef = onone;
2537 }
2538 return FALSE;
2539 }
2540
2541 /* A function, variable or enum constant? */
2542 switch (toktype)
2543 {
2544 case st_C_const:
2545 set_construct(C_CONSTANT);
2546 /* fall through */
2547 case st_C_typespec:
2548 #ifdef OO_BROWSER
2549 case st_C_extern:
2550 #endif
2551 if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
2552 fvdef = fvnone; /* should be useless */
2553 return FALSE;
2554 case st_C_ignore:
2555 fvdef = vignore;
2556 return FALSE;
2557 case st_none:
2558 if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
2559 #ifdef OO_BROWSER
2560 {
2561 oo_browser_construct = C_ENUM_LABEL;
2562 #endif
2563 return TRUE;
2564 #ifdef OO_BROWSER
2565 }
2566 #endif
2567 if (fvdef == fvnone)
2568 {
2569 fvdef = fvnameseen; /* function or variable */
2570 *is_func_or_var = TRUE;
2571 return TRUE;
2572 }
2573 }
2574
2575 return FALSE;
2576 }
2577
2578 /*
2579 * C_entries ()
2580 * This routine finds functions, variables, typedefs,
2581 * #define's, enum constants and struct/union/enum definitions in
2582 * #C syntax and adds them to the list.
2583 */
2584 #define current_lb_is_new (newndx == curndx)
2585 #define switch_line_buffers() (curndx = 1 - curndx)
2586
2587 #define curlb (lbs[curndx].lb)
2588 #define othlb (lbs[1-curndx].lb)
2589 #define newlb (lbs[newndx].lb)
2590 #define curlinepos (lbs[curndx].linepos)
2591 #define othlinepos (lbs[1-curndx].linepos)
2592 #define newlinepos (lbs[newndx].linepos)
2593
2594 #define CNL_SAVE_DEFINEDEF() \
2595 do { \
2596 curlinepos = charno; \
2597 lineno++; \
2598 linecharno = charno; \
2599 charno += readline (&curlb, inf); \
2600 lp = curlb.buffer; \
2601 quotednl = FALSE; \
2602 newndx = curndx; \
2603 } while (0)
2604
2605 #define CNL() \
2606 do { \
2607 CNL_SAVE_DEFINEDEF(); \
2608 if (savetok.valid) \
2609 { \
2610 tok = savetok; \
2611 savetok.valid = FALSE; \
2612 } \
2613 definedef = dnone; \
2614 } while (0)
2615
2616
2617 void make_C_tag PP ((bool isfun));
2618 void
2619 make_C_tag (isfun)
2620 bool isfun;
2621 {
2622 /* This function should never be called when tok.valid is FALSE, but
2623 we must protect against invalid input or internal errors. */
2624 if (tok.valid)
2625 {
2626 if (traditional_tag_style)
2627 {
2628 /* This was the original code. Now we call new_pfnote instead,
2629 which uses the new method for naming tags (see new_pfnote). */
2630 char *name = NULL;
2631
2632 if (CTAGS || tok.named)
2633 name = savestr (token_name.buffer);
2634 pfnote (name, isfun,
2635 tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2636 }
2637 else
2638 new_pfnote (token_name.buffer, token_name.len, isfun,
2639 tok.buffer, tok.linelen, tok.lineno, tok.linepos);
2640 tok.valid = FALSE;
2641 }
2642 else if (DEBUG)
2643 abort ();
2644 }
2645
2646
2647 void
2648 C_entries (c_ext, inf)
2649 int c_ext; /* extension of C */
2650 FILE *inf; /* input file */
2651 {
2652 register char c; /* latest char read; '\0' for end of line */
2653 register char *lp; /* pointer one beyond the character `c' */
2654 int curndx, newndx; /* indices for current and new lb */
2655 register int tokoff; /* offset in line of start of current token */
2656 register int toklen; /* length of current token */
2657 char *qualifier; /* string used to qualify names */
2658 int qlen; /* length of qualifier */
2659 int cblev; /* current curly brace level */
2660 int parlev; /* current parenthesis level */
2661 bool incomm, inquote, inchar, quotednl, midtoken;
2662 bool cplpl, cjava;
2663 token savetok; /* token saved during preprocessor handling */
2664
2665
2666 tokoff = toklen = 0; /* keep compiler quiet */
2667 curndx = newndx = 0;
2668 lineno = 0;
2669 charno = 0;
2670 lp = curlb.buffer;
2671 *lp = 0;
2672
2673 fvdef = fvnone; typdef = tnone; structdef = snone;
2674 definedef = dnone; objdef = onone;
2675 next_token_is_func = yacc_rules = FALSE;
2676 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2677 tok.valid = savetok.valid = FALSE;
2678 cblev = 0;
2679 parlev = 0;
2680 cplpl = (c_ext & C_PLPL) == C_PLPL;
2681 cjava = (c_ext & C_JAVA) == C_JAVA;
2682 if (cjava)
2683 { qualifier = "."; qlen = 1; }
2684 else
2685 { qualifier = "::"; qlen = 2; }
2686
2687 while (!feof (inf))
2688 {
2689 c = *lp++;
2690 if (c == '\\')
2691 {
2692 /* If we're at the end of the line, the next character is a
2693 '\0'; don't skip it, because it's the thing that tells us
2694 to read the next line. */
2695 if (*lp == '\0')
2696 {
2697 quotednl = TRUE;
2698 continue;
2699 }
2700 lp++;
2701 c = ' ';
2702 }
2703 else if (incomm)
2704 {
2705 switch (c)
2706 {
2707 case '*':
2708 if (*lp == '/')
2709 {
2710 c = *lp++;
2711 incomm = FALSE;
2712 }
2713 break;
2714 case '\0':
2715 /* Newlines inside comments do not end macro definitions in
2716 traditional cpp. */
2717 CNL_SAVE_DEFINEDEF ();
2718 break;
2719 }
2720 continue;
2721 }
2722 else if (inquote)
2723 {
2724 switch (c)
2725 {
2726 case '"':
2727 inquote = FALSE;
2728 break;
2729 case '\0':
2730 /* Newlines inside strings do not end macro definitions
2731 in traditional cpp, even though compilers don't
2732 usually accept them. */
2733 CNL_SAVE_DEFINEDEF ();
2734 break;
2735 }
2736 continue;
2737 }
2738 else if (inchar)
2739 {
2740 switch (c)
2741 {
2742 case '\0':
2743 /* Hmmm, something went wrong. */
2744 CNL ();
2745 /* FALLTHRU */
2746 case '\'':
2747 inchar = FALSE;
2748 break;
2749 }
2750 continue;
2751 }
2752 else
2753 switch (c)
2754 {
2755 case '"':
2756 inquote = TRUE;
2757 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
2758 fvdef = fvnone;
2759 continue;
2760 case '\'':
2761 inchar = TRUE;
2762 if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
2763 fvdef = fvnone;
2764 continue;
2765 case '/':
2766 if (*lp == '*')
2767 {
2768 lp++;
2769 incomm = TRUE;
2770 continue;
2771 }
2772 else if (/* cplpl && */ *lp == '/')
2773 {
2774 c = '\0';
2775 break;
2776 }
2777 else
2778 break;
2779 case '%':
2780 if ((c_ext & YACC) && *lp == '%')
2781 {
2782 /* entering or exiting rules section in yacc file */
2783 lp++;
2784 definedef = dnone; fvdef = fvnone;
2785 typdef = tnone; structdef = snone;
2786 next_token_is_func = FALSE;
2787 midtoken = inquote = inchar = incomm = quotednl = FALSE;
2788 cblev = 0;
2789 yacc_rules = !yacc_rules;
2790 continue;
2791 }
2792 else
2793 break;
2794 case '#':
2795 if (definedef == dnone)
2796 {
2797 char *cp;
2798 bool cpptoken = TRUE;
2799
2800 /* Look back on this line. If all blanks, or nonblanks
2801 followed by an end of comment, this is a preprocessor
2802 token. */
2803 for (cp = newlb.buffer; cp < lp-1; cp++)
2804 if (!iswhite (*cp))
2805 {
2806 if (*cp == '*' && *(cp+1) == '/')
2807 {
2808 cp++;
2809 cpptoken = TRUE;
2810 }
2811 else
2812 cpptoken = FALSE;
2813 }
2814 if (cpptoken)
2815 definedef = dsharpseen;
2816 } /* if (definedef == dnone) */
2817
2818 continue;
2819 } /* switch (c) */
2820
2821
2822 /* Consider token only if some complicated conditions are satisfied. */
2823 if ((definedef != dnone
2824 || (cblev == 0 && structdef != scolonseen)
2825 || (cblev == 1 && cplpl && structdef == sinbody)
2826 || (structdef == sinbody && structtype == st_C_enum))
2827 && typdef != tignore
2828 && definedef != dignorerest
2829 && fvdef != finlist)
2830 {
2831 if (midtoken)
2832 {
2833 if (endtoken (c))
2834 {
2835 if (c == ':' && cplpl && *lp == ':' && begtoken(*(lp + 1)))
2836 {
2837 /*
2838 * This handles :: in the middle, but not at the
2839 * beginning of an identifier.
2840 */
2841 lp += 2;
2842 toklen += 3;
2843 #ifdef OO_BROWSER
2844 set_construct(C_METHOD);
2845 #endif
2846 }
2847 else
2848 {
2849 bool funorvar = FALSE;
2850
2851 if (yacc_rules
2852 || consider_token (newlb.buffer + tokoff, toklen, c,
2853 c_ext, cblev, parlev, &funorvar))
2854 {
2855 tok.named = FALSE;
2856 if (structdef == sinbody
2857 && definedef == dnone
2858 && funorvar)
2859 /* function or var defined in C++ class body */
2860 {
2861 int len = strlen (structtag) + qlen + toklen;
2862 grow_linebuffer (&token_name, len + 1);
2863 strcpy (token_name.buffer, structtag);
2864 strcat (token_name.buffer, qualifier);
2865 strncat (token_name.buffer,
2866 newlb.buffer + tokoff, toklen);
2867 token_name.len = len;
2868 tok.named = TRUE;
2869 #ifdef OO_BROWSER
2870 oo_browser_construct = C_METHOD;
2871 #endif
2872 }
2873 else if (objdef == ocatseen)
2874 /* Objective C category */
2875 {
2876 int len = strlen (objtag) + 2 + toklen;
2877 grow_linebuffer (&token_name, len + 1);
2878 strcpy (token_name.buffer, objtag);
2879 strcat (token_name.buffer, "(");
2880 strncat (token_name.buffer,
2881 newlb.buffer + tokoff, toklen);
2882 strcat (token_name.buffer, ")");
2883 token_name.len = len;
2884 tok.named = TRUE;
2885 #ifdef OO_BROWSER
2886 oo_browser_construct = C_OBJC;
2887 #endif
2888 }
2889 else if (objdef == omethodtag
2890 || objdef == omethodparm)
2891 /* Objective C method */
2892 {
2893 tok.named = TRUE;
2894 #ifdef OO_BROWSER
2895 oo_browser_construct = C_OBJC;
2896 #endif
2897 }
2898 else
2899 {
2900 grow_linebuffer (&token_name, toklen + 1);
2901 strncpy (token_name.buffer,
2902 newlb.buffer + tokoff, toklen);
2903 token_name.buffer[toklen] = '\0';
2904 token_name.len = toklen;
2905 /* Name macros. */
2906 tok.named
2907 = (structdef == stagseen
2908 || typdef == tend
2909 #ifdef OO_BROWSER
2910 /* Also name #define constants,
2911 enumerations and enum_labels.
2912 Conditionalize `funorvar' reference
2913 here or #defines will appear without
2914 their #names.
2915 -- Bob Weiner, Altrasoft, 4/25/1998 */
2916 || ((oo_browser_format || funorvar)
2917 && definedef == dignorerest)
2918 || (oo_browser_format
2919 && (oo_browser_construct == C_ENUMERATION
2920 || oo_browser_construct == C_ENUM_LABEL))
2921 #else
2922 || (funorvar
2923 && definedef == dignorerest)
2924 #endif
2925 );
2926 }
2927 tok.lineno = lineno;
2928 tok.linelen = tokoff + toklen + 1;
2929 tok.buffer = newlb.buffer;
2930 tok.linepos = newlinepos;
2931 tok.valid = TRUE;
2932
2933 if (definedef == dnone
2934 && (fvdef == fvnameseen
2935 || structdef == stagseen
2936 || typdef == tend
2937 || objdef != onone))
2938 {
2939 if (current_lb_is_new)
2940 switch_line_buffers ();
2941 }
2942 else
2943 make_C_tag (funorvar);
2944 }
2945 midtoken = FALSE;
2946 }
2947 } /* if (endtoken (c)) */
2948 else if (intoken (c))
2949 {
2950 toklen++;
2951 continue;
2952 }
2953 } /* if (midtoken) */
2954 else if (begtoken (c))
2955 {
2956 switch (definedef)
2957 {
2958 case dnone:
2959 switch (fvdef)
2960 {
2961 case fstartlist:
2962 fvdef = finlist;
2963 continue;
2964 case flistseen:
2965 #ifdef OO_BROWSER
2966 set_construct(C_MACRO);
2967 #endif
2968 make_C_tag (TRUE); /* a function */
2969 fvdef = fignore;
2970 break;
2971 case fvnameseen:
2972 fvdef = fvnone;
2973 break;
2974 }
2975 if (structdef == stagseen && !cjava)
2976 structdef = snone;
2977 break;
2978 case dsharpseen:
2979 savetok = tok;
2980 }
2981 if (!yacc_rules || lp == newlb.buffer + 1)
2982 {
2983 tokoff = lp - 1 - newlb.buffer;
2984 toklen = 1;
2985 midtoken = TRUE;
2986 }
2987 continue;
2988 } /* if (begtoken) */
2989 } /* if must look at token */
2990
2991
2992 /* Detect end of line, colon, comma, semicolon and various braces
2993 after having handled a token.*/
2994 switch (c)
2995 {
2996 case ':':
2997 if (definedef != dnone)
2998 break;
2999 switch (objdef)
3000 {
3001 case otagseen:
3002 objdef = oignore;
3003 make_C_tag (TRUE); /* an Objective C class */
3004 break;
3005 case omethodtag:
3006 case omethodparm:
3007 objdef = omethodcolon;
3008 methodlen += 1;
3009 grow_linebuffer (&token_name, methodlen + 1);
3010 strcat (token_name.buffer, ":");
3011 token_name.len = methodlen;
3012 break;
3013 }
3014 if (structdef == stagseen)
3015 structdef = scolonseen;
3016 else
3017 switch (fvdef)
3018 {
3019 case fvnameseen:
3020 if (yacc_rules)
3021 {
3022 make_C_tag (FALSE); /* a yacc function */
3023 fvdef = fignore;
3024 }
3025 break;
3026 case fstartlist:
3027 fvdef = fvnone;
3028 break;
3029 }
3030 break;
3031 case ';':
3032 if (definedef != dnone)
3033 break;
3034 if (cblev == 0)
3035 switch (typdef)
3036 {
3037 case tend:
3038 #ifdef OO_BROWSER
3039 set_construct(C_TYPE);
3040 #endif
3041 make_C_tag (FALSE); /* a typedef */
3042 /* FALLTHRU */
3043 default:
3044 typdef = tnone;
3045 }
3046 switch (fvdef)
3047 {
3048 case fignore:
3049 break;
3050 case fvnameseen:
3051 if ((globals && cblev == 0) || (members && cblev == 1))
3052 #ifndef OO_BROWSER
3053 make_C_tag (FALSE); /* a variable */
3054 #else
3055 /* if (constantypedefs && structdef == snone)*/
3056 {
3057 tok.named = TRUE;
3058 switch (structtype)
3059 {
3060 case st_C_enum:
3061 set_construct(C_ENUMERATION);
3062 break;
3063 case st_C_class:
3064 set_construct(C_CLASS);
3065 break;
3066 default:
3067 set_construct(C_VARIABLE);
3068 break;
3069 }
3070 make_C_tag (FALSE);
3071 /* Force reset of st_C_enum structtype value. */
3072 structtype = st_none;
3073 }
3074 #endif
3075 /* FALLTHRU */
3076 default:
3077 fvdef = fvnone;
3078 /* The following instruction invalidates the token.
3079 Probably the token should be invalidated in all
3080 other cases where some state machine is reset. */
3081 tok.valid = FALSE;
3082 }
3083 if (structdef == stagseen)
3084 structdef = snone;
3085 break;
3086 case ',':
3087 if (definedef != dnone)
3088 break;
3089 switch (objdef)
3090 {
3091 case omethodtag:
3092 case omethodparm:
3093 make_C_tag (TRUE); /* an Objective C method */
3094 objdef = oinbody;
3095 break;
3096 }
3097 switch (fvdef)
3098 {
3099 case finlist:
3100 case fignore:
3101 case vignore:
3102 break;
3103 case fvnameseen:
3104 if ((globals && cblev == 0) || (members && cblev == 1))
3105 make_C_tag (FALSE); /* a variable */
3106 break;
3107 default:
3108 fvdef = fvnone;
3109 }
3110 if (structdef == stagseen)
3111 structdef = snone;
3112 break;
3113 case '[':
3114 if (definedef != dnone)
3115 break;
3116 if (cblev == 0 && typdef == tend)
3117 {
3118 #ifdef OO_BROWSER
3119 set_construct(C_TYPE);
3120 #endif
3121 typdef = tignore;
3122 make_C_tag (FALSE); /* a typedef */
3123 break;
3124 }
3125 switch (fvdef)
3126 {
3127 case finlist:
3128 case fignore:
3129 case vignore:
3130 break;
3131 case fvnameseen:
3132 #ifndef OO_BROWSER
3133 if ((globals && cblev == 0) || (members && cblev == 1))
3134 make_C_tag (FALSE); /* a variable */
3135 #else
3136 if (constantypedefs && structdef == snone)
3137 {
3138 tok.named = TRUE;
3139 switch (structtype)
3140 {
3141 case st_C_enum:
3142 set_construct(C_ENUMERATION);
3143 break;
3144 case st_C_class:
3145 set_construct(C_CLASS);
3146 break;
3147 default:
3148 set_construct(C_VARIABLE);
3149 break;
3150 }
3151 make_C_tag (FALSE);
3152 /* Force reset of st_C_enum structtype value. */
3153 structtype = st_none;
3154 }
3155 #endif
3156 /* FALLTHRU */
3157 default:
3158 fvdef = fvnone;
3159 }
3160 if (structdef == stagseen)
3161 structdef = snone;
3162 break;
3163 case '(':
3164 if (definedef != dnone)
3165 break;
3166 if (objdef == otagseen && parlev == 0)
3167 objdef = oparenseen;
3168 switch (fvdef)
3169 {
3170 case fvnone:
3171 switch (typdef)
3172 {
3173 case ttypedseen:
3174 case tend:
3175 if (tok.valid && *lp != '*')
3176 {
3177 /* This handles constructs like:
3178 typedef void OperatorFun (int fun); */
3179 typdef = tignore;
3180 #ifdef OO_BROWSER
3181 set_construct(C_TYPE);
3182 #endif
3183 make_C_tag (FALSE);
3184 }
3185 break;
3186 } /* switch (typdef) */
3187 break;
3188 case fvnameseen:
3189 fvdef = fstartlist;
3190 break;
3191 case flistseen:
3192 fvdef = finlist;
3193 break;
3194 }
3195 parlev++;
3196 break;
3197 case ')':
3198 if (definedef != dnone)
3199 break;
3200 if (objdef == ocatseen && parlev == 1)
3201 {
3202 make_C_tag (TRUE); /* an Objective C category */
3203 objdef = oignore;
3204 }
3205 if (--parlev == 0)
3206 {
3207 switch (fvdef)
3208 {
3209 case fstartlist:
3210 case finlist:
3211 fvdef = flistseen;
3212 break;
3213 }
3214 if (cblev == 0 && typdef == tend)
3215 {
3216 #ifdef OO_BROWSER
3217 set_construct(C_TYPE);
3218 #endif
3219 typdef = tignore;
3220 make_C_tag (FALSE); /* a typedef */
3221 }
3222 }
3223 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
3224 parlev = 0;
3225 break;
3226 case '{':
3227 if (definedef != dnone)
3228 break;
3229 if (typdef == ttypedseen)
3230 typdef = tinbody;
3231 switch (structdef)
3232 {
3233 case skeyseen: /* unnamed struct */
3234 structdef = sinbody;
3235 structtag = "_anonymous_";
3236 break;
3237 case stagseen:
3238 case scolonseen: /* named struct */
3239 structdef = sinbody;
3240 make_C_tag (FALSE); /* a struct */
3241 break;
3242 }
3243 switch (fvdef)
3244 {
3245 case flistseen:
3246 #ifdef OO_BROWSER
3247 set_construct(C_FUNCTION);
3248 /* Ensure function name is recorded.
3249 -- Bob Weiner, Altrasoft */
3250 tok.named = TRUE;
3251 #endif
3252 make_C_tag (TRUE); /* a function */
3253 /* FALLTHRU */
3254 case fignore:
3255 fvdef = fvnone;
3256 break;
3257 case fvnone:
3258 switch (objdef)
3259 {
3260 case otagseen:
3261 make_C_tag (TRUE); /* an Objective C class */
3262 objdef = oignore;
3263 break;
3264 case omethodtag:
3265 case omethodparm:
3266 make_C_tag (TRUE); /* an Objective C method */
3267 objdef = oinbody;
3268 break;
3269 default:
3270 /* Neutralize `extern "C" {' grot. */
3271 if (cblev == 0 && structdef == snone && typdef == tnone)
3272 cblev = -1;
3273 }
3274 }
3275 cblev++;
3276 break;
3277 case '*':
3278 if (definedef != dnone)
3279 break;
3280 if (fvdef == fstartlist)
3281 fvdef = fvnone; /* avoid tagging `foo' in `foo (*bar()) ()' */
3282 break;
3283 case '}':
3284 if (definedef != dnone)
3285 break;
3286 if (!noindentypedefs && lp == newlb.buffer + 1)
3287 {
3288 cblev = 0; /* reset curly brace level if first column */
3289 parlev = 0; /* also reset paren level, just in case... */
3290 }
3291 else if (cblev > 0)
3292 cblev--;
3293 if (cblev == 0)
3294 {
3295 if (typdef == tinbody)
3296 typdef = tend;
3297 /* Memory leakage here: the string pointed by structtag is
3298 never released, because I fear to miss something and
3299 break things while freeing the area. The amount of
3300 memory leaked here is the sum of the lengths of the
3301 struct tags.
3302 if (structdef == sinbody)
3303 free (structtag); */
3304
3305 structdef = snone;
3306 structtag = "<error>";
3307 #ifdef OO_BROWSER
3308 /* Next line added to avoid any state carryover between
3309 functions. -- Bob Weiner, Altrasoft, 11/19/1997 */
3310 fvdef = fvnone; oo_browser_construct = C_NULL;
3311 #endif
3312 }
3313 break;
3314 case '=':
3315 if (definedef != dnone)
3316 break;
3317 #ifdef OO_BROWSER
3318 {
3319 int is_method = 0;
3320 #endif
3321 switch (fvdef)
3322 {
3323 case finlist:
3324 case fignore:
3325 case vignore:
3326 break;
3327 case fvnameseen:
3328 if ((globals && cblev == 0) || (members && cblev == 1))
3329 #ifndef OO_BROWSER
3330 make_C_tag (FALSE); /* a variable */
3331 #else
3332 {
3333 tok.named = TRUE;
3334 switch (structtype)
3335 {
3336 case st_C_enum:
3337 set_construct(C_ENUMERATION);
3338 break;
3339 case st_C_class:
3340 set_construct(C_CLASS);
3341 break;
3342 default:
3343 /* a global variable */
3344 set_construct(C_VARIABLE);
3345 break;
3346 }
3347 /* We need this hack because *tags doesn't really parse */
3348 /* the input, and the OO Browser scanning has slightly */
3349 /* more context. -slb */
3350 is_method = (oo_browser_construct == C_METHOD);
3351 make_C_tag (FALSE);
3352 /* Force reset of st_C_enum structtype value. */
3353 structtype = st_none;
3354 }
3355 #endif
3356 /* FALLTHRU */
3357 default:
3358 #ifdef OO_BROWSER
3359 fvdef = is_method ? fignore : vignore;
3360 #else
3361 fvdef = vignore;
3362 #endif
3363 }
3364 #ifdef OO_BROWSER
3365 }
3366 #endif
3367 break;
3368 case '+':
3369 case '-':
3370 if (objdef == oinbody && cblev == 0)
3371 {
3372 objdef = omethodsign;
3373 break;
3374 }
3375 /* FALLTHRU */
3376 case '#': case '~': case '&': case '%': case '/': case '|':
3377 case '^': case '!': case '<': case '>': case '.': case '?': case ']':
3378 if (definedef != dnone)
3379 break;
3380 #ifdef OO_BROWSER
3381 if (!cplpl)
3382 {
3383 #endif
3384 /* These surely cannot follow a function tag. */
3385 /* Not if the language is C++ -slb */
3386 if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
3387 fvdef = fvnone;
3388 #ifdef OO_BROWSER
3389 }
3390 #endif
3391 break;
3392 case '\0':
3393 if (objdef == otagseen)
3394 {
3395 make_C_tag (TRUE); /* an Objective C class */
3396 objdef = oignore;
3397 }
3398 /* If a macro spans multiple lines don't reset its state. */
3399 if (quotednl)
3400 CNL_SAVE_DEFINEDEF ();
3401 else
3402 CNL ();
3403 break;
3404 } /* switch (c) */
3405
3406 } /* while not eof */
3407 }
3408
3409 /*
3410 * Process either a C++ file or a C file depending on the setting
3411 * of a global flag.
3412 */
3413 void
3414 default_C_entries (inf)
3415 FILE *inf;
3416 {
3417 C_entries (cplusplus ? C_PLPL : 0, inf);
3418 }
3419
3420 /* Always do plain ANSI C. */
3421 void
3422 plain_C_entries (inf)
3423 FILE *inf;
3424 {
3425 C_entries (0, inf);
3426 }
3427
3428 /* Always do C++. */
3429 void
3430 Cplusplus_entries (inf)
3431 FILE *inf;
3432 {
3433 C_entries (C_PLPL, inf);
3434 }
3435
3436 /* Always do Java. */
3437 void
3438 Cjava_entries (inf)
3439 FILE *inf;
3440 {
3441 C_entries (C_JAVA, inf);
3442 }
3443
3444 /* Always do C*. */
3445 void
3446 Cstar_entries (inf)
3447 FILE *inf;
3448 {
3449 C_entries (C_STAR, inf);
3450 }
3451
3452 /* Always do Yacc. */
3453 void
3454 Yacc_entries (inf)
3455 FILE *inf;
3456 {
3457 C_entries (YACC, inf);
3458 }
3459
3460 /* A useful macro. */
3461 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer) \
3462 for (lineno = charno = 0; /* loop initialization */ \
3463 !feof (file_pointer) /* loop test */ \
3464 && (lineno++, /* instructions at start of loop */ \
3465 linecharno = charno, \
3466 charno += readline (&line_buffer, file_pointer), \
3467 char_pointer = lb.buffer, \
3468 TRUE); \
3469 )
3470
3471
3472 /*
3473 * Read a file, but do no processing. This is used to do regexp
3474 * matching on files that have no language defined.
3475 */
3476 void
3477 just_read_file (inf)
3478 FILE *inf;
3479 {
3480 register char *dummy;
3481
3482 LOOP_ON_INPUT_LINES (inf, lb, dummy)
3483 continue;
3484 }
3485
3486 /* Fortran parsing */
3487
3488 bool tail PP ((char *cp));
3489 bool
3490 tail (cp)
3491 char *cp;
3492 {
3493 register int len = 0;
3494
3495 while (*cp && lowcase(*cp) == lowcase(dbp[len]))
3496 cp++, len++;
3497 if (*cp == '\0' && !intoken(dbp[len]))
3498 {
3499 dbp += len;
3500 return TRUE;
3501 }
3502 return FALSE;
3503 }
3504
3505 void
3506 takeprec ()
3507 {
3508 dbp = skip_spaces (dbp);
3509 if (*dbp != '*')
3510 return;
3511 dbp++;
3512 dbp = skip_spaces (dbp);
3513 if (strneq (dbp, "(*)", 3))
3514 {
3515 dbp += 3;
3516 return;
3517 }
3518 if (!isdigit (*dbp))
3519 {
3520 --dbp; /* force failure */
3521 return;
3522 }
3523 do
3524 dbp++;
3525 while (isdigit (*dbp));
3526 }
3527
3528 void getit PP ((FILE *inf));
3529 void
3530 getit (inf)
3531 FILE *inf;
3532 {
3533 register char *cp;
3534
3535 dbp = skip_spaces (dbp);
3536 if (*dbp == '\0')
3537 {
3538 lineno++;
3539 linecharno = charno;
3540 charno += readline (&lb, inf);
3541 dbp = lb.buffer;
3542 if (dbp[5] != '&')
3543 return;
3544 dbp += 6;
3545 dbp = skip_spaces (dbp);
3546 }
3547 if (!isalpha (*dbp)
3548 && *dbp != '_'
3549 && *dbp != '$')
3550 return;
3551 for (cp = dbp + 1; *cp && intoken (*cp); cp++)
3552 continue;
3553 pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
3554 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3555 }
3556
3557
3558 void
3559 Fortran_functions (inf)
3560 FILE *inf;
3561 {
3562 LOOP_ON_INPUT_LINES (inf, lb, dbp)
3563 {
3564 if (*dbp == '%')
3565 dbp++; /* Ratfor escape to fortran */
3566 dbp = skip_spaces (dbp);
3567 if (*dbp == '\0')
3568 continue;
3569 switch (lowcase (*dbp))
3570 {
3571 case 'i':
3572 if (tail ("integer"))
3573 takeprec ();
3574 break;
3575 case 'r':
3576 if (tail ("real"))
3577 takeprec ();
3578 break;
3579 case 'l':
3580 if (tail ("logical"))
3581 takeprec ();
3582 break;
3583 case 'c':
3584 if (tail ("complex") || tail ("character"))
3585 takeprec ();
3586 break;
3587 case 'd':
3588 if (tail ("double"))
3589 {
3590 dbp = skip_spaces (dbp);
3591 if (*dbp == '\0')
3592 continue;
3593 if (tail ("precision"))
3594 break;
3595 continue;
3596 }
3597 break;
3598 }
3599 dbp = skip_spaces (dbp);
3600 if (*dbp == '\0')
3601 continue;
3602 switch (lowcase (*dbp))
3603 {
3604 case 'f':
3605 if (tail ("function"))
3606 getit (inf);
3607 continue;
3608 case 's':
3609 if (tail ("subroutine"))
3610 getit (inf);
3611 continue;
3612 case 'e':
3613 if (tail ("entry"))
3614 getit (inf);
3615 continue;
3616 case 'p':
3617 if (tail ("program"))
3618 {
3619 getit (inf);
3620 continue;
3621 }
3622 if (tail ("procedure"))
3623 getit (inf);
3624 continue;
3625 }
3626 }
3627 }
3628
3629 /*
3630 * Bob Weiner, Motorola Inc., 4/3/94
3631 * Unix and microcontroller assembly tag handling
3632 * look for '^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]'
3633 */
3634 void
3635 Asm_labels (inf)
3636 FILE *inf;
3637 {
3638 register char *cp;
3639
3640 LOOP_ON_INPUT_LINES (inf, lb, cp)
3641 {
3642 /* If first char is alphabetic or one of [_.$], test for colon
3643 following identifier. */
3644 if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3645 {
3646 /* Read past label. */
3647 cp++;
3648 while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
3649 cp++;
3650 if (*cp == ':' || isspace (*cp))
3651 {
3652 /* Found end of label, so copy it and add it to the table. */
3653 pfnote ((CTAGS) ? savenstr(lb.buffer, cp-lb.buffer) : NULL, TRUE,
3654 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3655 }
3656 }
3657 }
3658 }
3659
3660 /*
3661 * Perl support by Bart Robinson <lomew@cs.utah.edu>
3662 * enhanced by Michael Ernst <mernst@alum.mit.edu>
3663 * Perl sub names: look for /^sub[ \t\n]+[^ \t\n{]+/
3664 * Perl variable names: /^(my|local).../
3665 */
3666 void
3667 Perl_functions (inf)
3668 FILE *inf;
3669 {
3670 register char *cp;
3671
3672 LOOP_ON_INPUT_LINES (inf, lb, cp)
3673 {
3674 if (*cp++ == 's'
3675 && *cp++ == 'u'
3676 && *cp++ == 'b' && isspace (*cp++))
3677 {
3678 cp = skip_spaces (cp);
3679 if (*cp != '\0')
3680 {
3681 while (*cp != '\0'
3682 && !isspace (*cp) && *cp != '{' && *cp != '(')
3683 cp++;
3684 pfnote ((CTAGS) ? savenstr(lb.buffer, cp-lb.buffer) : NULL, TRUE,
3685 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3686 }
3687 }
3688 else if (globals /* only if tagging global vars is enabled */
3689 && ((cp = lb.buffer,
3690 *cp++ == 'm'
3691 && *cp++ == 'y')
3692 || (cp = lb.buffer,
3693 *cp++ == 'l'
3694 && *cp++ == 'o'
3695 && *cp++ == 'c'
3696 && *cp++ == 'a'
3697 && *cp++ == 'l'))
3698 && (*cp == '(' || isspace (*cp)))
3699 {
3700 /* After "my" or "local", but before any following paren or space. */
3701 char *varname = NULL;
3702
3703 cp = skip_spaces (cp);
3704 if (*cp == '$' || *cp == '@' || *cp == '%')
3705 {
3706 char* varstart = ++cp;
3707 while (isalnum (*cp) || *cp == '_')
3708 cp++;
3709 varname = savenstr (varstart, cp-varstart);
3710 }
3711 else
3712 {
3713 /* Should be examining a variable list at this point;
3714 could insist on seeing an open parenthesis. */
3715 while (*cp != '\0' && *cp != ';' && *cp != '=' && *cp != ')')
3716 cp++;
3717 }
3718
3719 /* Perhaps I should back cp up one character, so the TAGS table
3720 doesn't mention (and so depend upon) the following char. */
3721 pfnote ((CTAGS) ? savenstr (lb.buffer, cp-lb.buffer) : varname,
3722 FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3723 }
3724 }
3725 }
3726
3727 /*
3728 * Python support by Eric S. Raymond <esr@thyrsus.com>
3729 * Look for /^def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
3730 */
3731 void
3732 Python_functions (inf)
3733 FILE *inf;
3734 {
3735 register char *cp;
3736
3737 LOOP_ON_INPUT_LINES (inf, lb, cp)
3738 {
3739 if (*cp++ == 'd'
3740 && *cp++ == 'e'
3741 && *cp++ == 'f' && isspace (*cp++))
3742 {
3743 cp = skip_spaces (cp);
3744 while (*cp != '\0' && !isspace (*cp) && *cp != '(' && *cp != ':')
3745 cp++;
3746 pfnote ((char *) NULL, TRUE,
3747 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3748 }
3749
3750 cp = lb.buffer;
3751 if (*cp++ == 'c'
3752 && *cp++ == 'l'
3753 && *cp++ == 'a'
3754 && *cp++ == 's'
3755 && *cp++ == 's' && isspace (*cp++))
3756 {
3757 cp = skip_spaces (cp);
3758 while (*cp != '\0' && !isspace (*cp) && *cp != '(' && *cp != ':')
3759 cp++;
3760 pfnote ((char *) NULL, TRUE,
3761 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
3762 }
3763 }
3764 }
3765
3766 /* Idea by Corny de Souza
3767 * Cobol tag functions
3768 * We could look for anything that could be a paragraph name.
3769 * i.e. anything that starts in column 8 is one word and ends in a full stop.
3770 */
3771 void
3772 Cobol_paragraphs (inf)
3773 FILE *inf;
3774 {
3775 register char *bp, *ep;
3776
3777 LOOP_ON_INPUT_LINES (inf, lb, bp)
3778 {
3779 if (lb.len < 9)
3780 continue;
3781 bp += 8;
3782
3783 /* If eoln, compiler option or comment ignore whole line. */
3784 if (bp[-1] != ' ' || !isalnum (bp[0]))
3785 continue;
3786
3787 for (ep = bp; isalnum (*ep) || *ep == '-'; ep++)
3788 continue;
3789 if (*ep++ == '.')
3790 pfnote ((CTAGS) ? savenstr (bp, ep-bp) : NULL, TRUE,
3791 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
3792 }
3793 }
3794
3795 /* Added by Mosur Mohan, 4/22/88 */
3796 /* Pascal parsing */
3797
3798 /*
3799 * Locates tags for procedures & functions. Doesn't do any type- or
3800 * var-definitions. It does look for the keyword "extern" or
3801 * "forward" immediately following the procedure statement; if found,
3802 * the tag is skipped.
3803 */
3804 void
3805 Pascal_functions (inf)
3806 FILE *inf;
3807 {
3808 linebuffer tline; /* mostly copied from C_entries */
3809 long save_lcno;
3810 int save_lineno, save_len;
3811 char c, *cp, *namebuf;
3812
3813 bool /* each of these flags is TRUE iff: */
3814 incomment, /* point is inside a comment */
3815 inquote, /* point is inside '..' string */
3816 get_tagname, /* point is after PROCEDURE/FUNCTION
3817 keyword, so next item = potential tag */
3818 found_tag, /* point is after a potential tag */
3819 inparms, /* point is within parameter-list */
3820 verify_tag; /* point has passed the parm-list, so the
3821 next token will determine whether this
3822 is a FORWARD/EXTERN to be ignored, or
3823 whether it is a real tag */
3824
3825 save_lcno = save_lineno = save_len = 0; /* keep compiler quiet */
3826 namebuf = NULL; /* keep compiler quiet */
3827 lineno = 0;
3828 charno = 0;
3829 dbp = lb.buffer;
3830 *dbp = '\0';
3831 initbuffer (&tline);
3832
3833 incomment = inquote = FALSE;
3834 found_tag = FALSE; /* have a proc name; check if extern */
3835 get_tagname = FALSE; /* have found "procedure" keyword */
3836 inparms = FALSE; /* found '(' after "proc" */
3837 verify_tag = FALSE; /* check if "extern" is ahead */
3838
3839
3840 while (!feof (inf)) /* long main loop to get next char */
3841 {
3842 c = *dbp++;
3843 if (c == '\0') /* if end of line */
3844 {
3845 lineno++;
3846 linecharno = charno;
3847 charno += readline (&lb, inf);
3848 dbp = lb.buffer;
3849 if (*dbp == '\0')
3850 continue;
3851 if (!((found_tag && verify_tag)
3852 || get_tagname))
3853 c = *dbp++; /* only if don't need *dbp pointing
3854 to the beginning of the name of
3855 the procedure or function */
3856 }
3857 if (incomment)
3858 {
3859 if (c == '}') /* within { } comments */
3860 incomment = FALSE;
3861 else if (c == '*' && *dbp == ')') /* within (* *) comments */
3862 {
3863 dbp++;
3864 incomment = FALSE;
3865 }
3866 continue;
3867 }
3868 else if (inquote)
3869 {
3870 if (c == '\'')
3871 inquote = FALSE;
3872 continue;
3873 }
3874 else
3875 switch (c)
3876 {
3877 case '\'':
3878 inquote = TRUE; /* found first quote */
3879 continue;
3880 case '{': /* found open { comment */
3881 incomment = TRUE;
3882 continue;
3883 case '(':
3884 if (*dbp == '*') /* found open (* comment */
3885 {
3886 incomment = TRUE;
3887 dbp++;
3888 }
3889 else if (found_tag) /* found '(' after tag, i.e., parm-list */
3890 inparms = TRUE;
3891 continue;
3892 case ')': /* end of parms list */
3893 if (inparms)
3894 inparms = FALSE;
3895 continue;
3896 case ';':
3897 if (found_tag && !inparms) /* end of proc or fn stmt */
3898 {
3899 verify_tag = TRUE;
3900 break;
3901 }
3902 continue;
3903 }
3904 if (found_tag && verify_tag && (*dbp != ' '))
3905 {
3906 /* check if this is an "extern" declaration */
3907 if (*dbp == '\0')
3908 continue;
3909 if (lowcase (*dbp == 'e'))
3910 {
3911 if (tail ("extern")) /* superfluous, really! */
3912 {
3913 found_tag = FALSE;
3914 verify_tag = FALSE;
3915 }
3916 }
3917 else if (lowcase (*dbp) == 'f')
3918 {
3919 if (tail ("forward")) /* check for forward reference */
3920 {
3921 found_tag = FALSE;
3922 verify_tag = FALSE;
3923 }
3924 }
3925 if (found_tag && verify_tag) /* not external proc, so make tag */
3926 {
3927 found_tag = FALSE;
3928 verify_tag = FALSE;
3929 pfnote (namebuf, TRUE,
3930 tline.buffer, save_len, save_lineno, save_lcno);
3931 continue;
3932 }
3933 }
3934 if (get_tagname) /* grab name of proc or fn */
3935 {
3936 if (*dbp == '\0')
3937 continue;
3938
3939 /* save all values for later tagging */
3940 grow_linebuffer (&tline, lb.len + 1);
3941 strcpy (tline.buffer, lb.buffer);
3942 save_lineno = lineno;
3943 save_lcno = linecharno;
3944
3945 /* grab block name */
3946 for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
3947 continue;
3948 namebuf = (CTAGS) ? savenstr (dbp, cp-dbp) : NULL;
3949 dbp = cp; /* set dbp to e-o-token */
3950 save_len = dbp - lb.buffer + 1;
3951 get_tagname = FALSE;
3952 found_tag = TRUE;
3953 continue;
3954
3955 /* and proceed to check for "extern" */
3956 }
3957 else if (!incomment && !inquote && !found_tag)
3958 {
3959 /* check for proc/fn keywords */
3960 switch (lowcase (c))
3961 {
3962 case 'p':
3963 if (tail ("rocedure")) /* c = 'p', dbp has advanced */
3964 get_tagname = TRUE;
3965 continue;
3966 case 'f':
3967 if (tail ("unction"))
3968 get_tagname = TRUE;
3969 continue;
3970 }
3971 }
3972 } /* while not eof */
3973
3974 free (tline.buffer);
3975 }
3976
3977 /*
3978 * lisp tag functions
3979 * look for (def or (DEF, quote or QUOTE
3980 */
3981 int L_isdef PP ((char *strp));
3982 int
3983 L_isdef (strp)
3984 register char *strp;
3985 {
3986 return ((strp[1] == 'd' || strp[1] == 'D')
3987 && (strp[2] == 'e' || strp[2] == 'E')
3988 && (strp[3] == 'f' || strp[3] == 'F'));
3989 }
3990 int L_isquote PP ((char *strp));
3991 int
3992 L_isquote (strp)
3993 register char *strp;
3994 {
3995 return ((*++strp == 'q' || *strp == 'Q')
3996 && (*++strp == 'u' || *strp == 'U')
3997 && (*++strp == 'o' || *strp == 'O')
3998 && (*++strp == 't' || *strp == 'T')
3999 && (*++strp == 'e' || *strp == 'E')
4000 && isspace (*++strp));
4001 }
4002
4003 void L_getit PP ((void));
4004 void
4005 L_getit ()
4006 {
4007 register char *cp;
4008
4009 if (*dbp == '\'') /* Skip prefix quote */
4010 dbp++;
4011 else if (*dbp == '(')
4012 {
4013 if (L_isquote (dbp))
4014 dbp += 7; /* Skip "(quote " */
4015 else
4016 dbp += 1; /* Skip "(" before name in (defstruct (foo)) */
4017 dbp = skip_spaces (dbp);
4018 }
4019
4020 for (cp = dbp /*+1*/;
4021 *cp != '\0' && *cp != '(' && *cp != ' ' && *cp != ')';
4022 cp++)
4023 continue;
4024 if (cp == dbp)
4025 return;
4026
4027 pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
4028 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4029 }
4030
4031 void
4032 Lisp_functions (inf)
4033 FILE *inf;
4034 {
4035 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4036 {
4037 if (dbp[0] == '(')
4038 {
4039 if (L_isdef (dbp))
4040 {
4041 dbp = skip_non_spaces (dbp);
4042 dbp = skip_spaces (dbp);
4043 L_getit ();
4044 }
4045 else
4046 {
4047 /* Check for (foo::defmumble name-defined ... */
4048 do
4049 dbp++;
4050 while (*dbp != '\0' && !isspace (*dbp)
4051 && *dbp != ':' && *dbp != '(' && *dbp != ')');
4052 if (*dbp == ':')
4053 {
4054 do
4055 dbp++;
4056 while (*dbp == ':');
4057
4058 if (L_isdef (dbp - 1))
4059 {
4060 dbp = skip_non_spaces (dbp);
4061 dbp = skip_spaces (dbp);
4062 L_getit ();
4063 }
4064 }
4065 }
4066 }
4067 }
4068 }
4069
4070 /*
4071 * Postscript tag functions
4072 * Just look for lines where the first character is '/'
4073 * Richard Mlynarik <mly@adoc.xerox.com>
4074 */
4075 void
4076 Postscript_functions (inf)
4077 FILE *inf;
4078 {
4079 register char *bp, *ep;
4080
4081 LOOP_ON_INPUT_LINES (inf, lb, bp)
4082 {
4083 if (bp[0] == '/')
4084 {
4085 for (ep = bp+1;
4086 *ep != '\0' && *ep != ' ' && *ep != '{';
4087 ep++)
4088 continue;
4089 pfnote ((CTAGS) ? savenstr (bp, ep-bp) : NULL, TRUE,
4090 lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
4091 }
4092 }
4093 }
4094
4095
4096 /*
4097 * Scheme tag functions
4098 * look for (def... xyzzy
4099 * look for (def... (xyzzy
4100 * look for (def ... ((...(xyzzy ....
4101 * look for (set! xyzzy
4102 */
4103
4104 void get_scheme PP ((void));
4105
4106 void
4107 Scheme_functions (inf)
4108 FILE *inf;
4109 {
4110 LOOP_ON_INPUT_LINES (inf, lb, dbp)
4111 {
4112 if (dbp[0] == '('
4113 && (dbp[1] == 'D' || dbp[1] == 'd')
4114 && (dbp[2] == 'E' || dbp[2] == 'e')
4115 && (dbp[3] == 'F' || dbp[3] == 'f'))
4116 {
4117 dbp = skip_non_spaces (dbp);
4118 /* Skip over open parens and white space */
4119 while (isspace (*dbp) || *dbp == '(')
4120 dbp++;
4121 get_scheme ();
4122 }
4123 if (dbp[0] == '('
4124 && (dbp[1] == 'S' || dbp[1] == 's')
4125 && (dbp[2] == 'E' || dbp[2] == 'e')
4126 && (dbp[3] == 'T' || dbp[3] == 't')
4127 && (dbp[4] == '!' || dbp[4] == '!')
4128 && (isspace (dbp[5])))
4129 {
4130 dbp = skip_non_spaces (dbp);
4131 dbp = skip_spaces (dbp);
4132 get_scheme ();
4133 }
4134 }
4135 }
4136
4137 void
4138 get_scheme ()
4139 {
4140 register char *cp;
4141
4142 if (*dbp == '\0')
4143 return;
4144 /* Go till you get to white space or a syntactic break */
4145 for (cp = dbp + 1;
4146 *cp != '\0' && *cp != '(' && *cp != ')' && !isspace (*cp);
4147 cp++)
4148 continue;
4149 pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
4150 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
4151 }
4152
4153 /* Find tags in TeX and LaTeX input files. */
4154
4155 /* TEX_toktab is a table of TeX control sequences that define tags.
4156 Each TEX_tabent records one such control sequence.
4157 CONVERT THIS TO USE THE Stab TYPE!! */
4158 struct TEX_tabent
4159 {
4160 char *name;
4161 int len;
4162 };
4163
4164 struct TEX_tabent *TEX_toktab = NULL; /* Table with tag tokens */
4165
4166 /* Default set of control sequences to put into TEX_toktab.
4167 The value of environment var TEXTAGS is prepended to this. */
4168
4169 char *TEX_defenv = "\
4170 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
4171 :part:appendix:entry:index";
4172
4173 void TEX_mode PP ((FILE *inf));
4174 struct TEX_tabent *TEX_decode_env PP ((char *evarname, char *defenv));
4175 int TEX_Token PP ((char *cp));
4176
4177 char TEX_esc = '\\';
4178 char TEX_opgrp = '{';
4179 char TEX_clgrp = '}';
4180
4181 /*
4182 * TeX/LaTeX scanning loop.
4183 */
4184 void
4185 TeX_functions (inf)
4186 FILE *inf;
4187 {
4188 char *cp, *lasthit;
4189 register int i;
4190
4191 /* Select either \ or ! as escape character. */
4192 TEX_mode (inf);
4193
4194 /* Initialize token table once from environment. */
4195 if (!TEX_toktab)
4196 TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
4197
4198 LOOP_ON_INPUT_LINES (inf, lb, cp)
4199 {
4200 lasthit = cp;
4201 /* Look at each esc in line. */
4202 while ((cp = etags_strchr (cp, TEX_esc)) != NULL)
4203 {
4204 if (*++cp == '\0')
4205 break;
4206 linecharno += cp - lasthit;
4207 lasthit = cp;
4208 i = TEX_Token (lasthit);
4209 if (i >= 0)
4210 {
4211 /* We seem to include the TeX command in the tag name.
4212 register char *p;
4213 for (p = lasthit + TEX_toktab[i].len;
4214 *p != '\0' && *p != TEX_clgrp;
4215 p++)
4216 continue; */
4217 pfnote (/*savenstr (lasthit, p-lasthit)*/ (char *)NULL, TRUE,
4218 lb.buffer, lb.len, lineno, linecharno);
4219 break; /* We only tag a line once */
4220 }
4221 }
4222 }
4223 }
4224
4225 #define TEX_LESC '\\'
4226 #define TEX_SESC '!'
4227 #define TEX_cmt '%'
4228
4229 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
4230 chars accordingly. */
4231 void
4232 TEX_mode (inf)
4233 FILE *inf;
4234 {
4235 int c;
4236
4237 while ((c = getc (inf)) != EOF)
4238 {
4239 /* Skip to next line if we hit the TeX comment char. */
4240 if (c == TEX_cmt)
4241 while (c != '\n')
4242 c = getc (inf);
4243 else if (c == TEX_LESC || c == TEX_SESC )
4244 break;
4245 }
4246
4247 if (c == TEX_LESC)
4248 {
4249 TEX_esc = TEX_LESC;
4250 TEX_opgrp = '{';
4251 TEX_clgrp = '}';
4252 }
4253 else
4254 {
4255 TEX_esc = TEX_SESC;
4256 TEX_opgrp = '<';
4257 TEX_clgrp = '>';
4258 }
4259 rewind (inf);
4260 }
4261
4262 /* Read environment and prepend it to the default string.
4263 Build token table. */
4264 struct TEX_tabent *
4265 TEX_decode_env (evarname, defenv)
4266 char *evarname;
4267 char *defenv;
4268 {
4269 register char *env, *p;
4270
4271 struct TEX_tabent *tab;
4272 int size, i;
4273
4274 /* Append default string to environment. */
4275 env = getenv (evarname);
4276 if (!env)
4277 env = defenv;
4278 else
4279 {
4280 char *oldenv = env;
4281 env = concat (oldenv, defenv, "");
4282 free (oldenv);
4283 }
4284
4285 /* Allocate a token table */
4286 for (size = 1, p = env; p;)
4287 if ((p = etags_strchr (p, ':')) && *++p != '\0')
4288 size++;
4289 /* Add 1 to leave room for null terminator. */
4290 tab = xnew (size + 1, struct TEX_tabent);
4291
4292 /* Unpack environment string into token table. Be careful about */
4293 /* zero-length strings (leading ':', "::" and trailing ':') */
4294 for (i = 0; *env;)
4295 {
4296 p = etags_strchr (env, ':');
4297 if (!p) /* End of environment string. */
4298 p = env + strlen (env);
4299 if (p - env > 0)
4300 { /* Only non-zero strings. */
4301 tab[i].name = savenstr (env, p - env);
4302 tab[i].len = strlen (tab[i].name);
4303 i++;
4304 }
4305 if (*p)
4306 env = p + 1;
4307 else
4308 {
4309 tab[i].name = NULL; /* Mark end of table. */
4310 tab[i].len = 0;
4311 break;
4312 }
4313 }
4314 return tab;
4315 }
4316
4317 /* If the text at CP matches one of the tag-defining TeX command names,
4318 return the pointer to the first occurrence of that command in TEX_toktab.
4319 Otherwise return -1.
4320 Keep the capital `T' in `token' for dumb truncating compilers
4321 (this distinguishes it from `TEX_toktab' */
4322 int
4323 TEX_Token (cp)
4324 char *cp;
4325 {
4326 int i;
4327
4328 for (i = 0; TEX_toktab[i].len > 0; i++)
4329 if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
4330 return i;
4331 return -1;
4332 }
4333
4334 /*
4335 * Prolog support (rewritten) by Anders Lindgren, Mar. 96
4336 *
4337 * Assumes that the predicate starts at column 0.
4338 * Only the first clause of a predicate is added.
4339 */
4340 int prolog_pred PP ((char *s, char *last));
4341 void prolog_skip_comment PP ((linebuffer *plb, FILE *inf));
4342 int prolog_atom PP ((char *s, int pos));
4343
4344 void
4345 Prolog_functions (inf)
4346 FILE *inf;
4347 {
4348 char *cp, *last;
4349 int len;
4350 int allocated;
4351
4352 allocated = 0;
4353 len = 0;
4354 last = NULL;
4355
4356 LOOP_ON_INPUT_LINES (inf, lb, cp)
4357 {
4358 if (cp[0] == '\0') /* Empty line */
4359 continue;
4360 else if (isspace (cp[0])) /* Not a predicate */
4361 continue;
4362 else if (cp[0] == '/' && cp[1] == '*') /* comment. */
4363 prolog_skip_comment (&lb, inf);
4364 else if ((len = prolog_pred (cp, last)) > 0)
4365 {
4366 /* Predicate. Store the function name so that we only
4367 generate a tag for the first clause. */
4368 if (last == NULL)
4369 last = xnew(len + 1, char);
4370 else if (len + 1 > allocated)
4371 last = xrnew (last, len + 1, char);
4372 allocated = len + 1;
4373 strncpy (last, cp, len);
4374 last[len] = '\0';
4375 }
4376 }
4377 }
4378
4379
4380 void
4381 prolog_skip_comment (plb, inf)
4382 linebuffer *plb;
4383 FILE *inf;
4384 {
4385 char *cp;
4386
4387 do
4388 {
4389 for (cp = plb->buffer; *cp != '\0'; cp++)
4390 if (cp[0] == '*' && cp[1] == '/')
4391 return;
4392 lineno++;
4393 linecharno += readline (plb, inf);
4394 }
4395 while (!feof(inf));
4396 }
4397
4398 /*
4399 * A predicate definition is added if it matches:
4400 * <beginning of line><Prolog Atom><whitespace>(
4401 *
4402 * It is added to the tags database if it doesn't match the
4403 * name of the previous clause header.
4404 *
4405 * Return the size of the name of the predicate, or 0 if no header
4406 * was found.
4407 */
4408 int
4409 prolog_pred (s, last)
4410 char *s;
4411 char *last; /* Name of last clause. */
4412 {
4413 int pos;
4414 int len;
4415
4416 pos = prolog_atom (s, 0);
4417 if (pos < 1)
4418 return 0;
4419
4420 len = pos;
4421 pos = skip_spaces (s + pos) - s;
4422
4423 if ((s[pos] == '(') || (s[pos] == '.'))
4424 {
4425 if (s[pos] == '(')
4426 pos++;
4427
4428 /* Save only the first clause. */
4429 if (last == NULL
4430 || len != strlen (last)
4431 || !strneq (s, last, len))
4432 {
4433 pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
4434 s, pos, lineno, linecharno);
4435 return len;
4436 }
4437 }
4438 return 0;
4439 }
4440
4441 /*
4442 * Consume a Prolog atom.
4443 * Return the number of bytes consumed, or -1 if there was an error.
4444 *
4445 * A prolog atom, in this context, could be one of:
4446 * - An alphanumeric sequence, starting with a lower case letter.
4447 * - A quoted arbitrary string. Single quotes can escape themselves.
4448 * Backslash quotes everything.
4449 */
4450 int
4451 prolog_atom (s, pos)
4452 char *s;
4453 int pos;
4454 {
4455 int origpos;
4456
4457 origpos = pos;
4458
4459 if (islower(s[pos]) || (s[pos] == '_'))
4460 {
4461 /* The atom is unquoted. */
4462 pos++;
4463 while (isalnum(s[pos]) || (s[pos] == '_'))
4464 {
4465 pos++;
4466 }
4467 return pos - origpos;
4468 }
4469 else if (s[pos] == '\'')
4470 {
4471 pos++;
4472
4473 while (1)
4474 {
4475 if (s[pos] == '\'')
4476 {
4477 pos++;
4478 if (s[pos] != '\'')
4479 break;
4480 pos++; /* A double quote */
4481 }
4482 else if (s[pos] == '\0')
4483 /* Multiline quoted atoms are ignored. */
4484 return -1;
4485 else if (s[pos] == '\\')
4486 {
4487 if (s[pos+1] == '\0')
4488 return -1;
4489 pos += 2;
4490 }
4491 else
4492 pos++;
4493 }
4494 return pos - origpos;
4495 }
4496 else
4497 return -1;
4498 }
4499
4500 /*
4501 * Support for Erlang -- Anders Lindgren, Feb 1996.
4502 *
4503 * Generates tags for functions, defines, and records.
4504 *
4505 * Assumes that Erlang functions start at column 0.
4506 */
4507 int erlang_func PP ((char *s, char *last));
4508 void erlang_attribute PP ((char *s));
4509 int erlang_atom PP ((char *s, int pos));
4510
4511 void
4512 Erlang_functions (inf)
4513 FILE *inf;
4514 {
4515 char *cp, *last;
4516 int len;
4517 int allocated;
4518
4519 allocated = 0;
4520 len = 0;
4521 last = NULL;
4522
4523 LOOP_ON_INPUT_LINES (inf, lb, cp)
4524 {
4525 if (cp[0] == '\0') /* Empty line */
4526 continue;
4527 else if (isspace (cp[0])) /* Not function nor attribute */
4528 continue;
4529 else if (cp[0] == '%') /* comment */
4530 continue;
4531 else if (cp[0] == '"') /* Sometimes, strings start in column one */
4532 continue;
4533 else if (cp[0] == '-') /* attribute, e.g. "-define" */
4534 {
4535 erlang_attribute (cp);
4536 last = NULL;
4537 }
4538 else if ((len = erlang_func (cp, last)) > 0)
4539 {
4540 /*
4541 * Function. Store the function name so that we only
4542 * generates a tag for the first clause.
4543 */
4544 if (last == NULL)
4545 last = xnew (len + 1, char);
4546 else if (len + 1 > allocated)
4547 last = xrnew (last, len + 1, char);
4548 allocated = len + 1;
4549 strncpy (last, cp, len);
4550 last[len] = '\0';
4551 }
4552 }
4553 }
4554
4555
4556 /*
4557 * A function definition is added if it matches:
4558 * <beginning of line><Erlang Atom><whitespace>(
4559 *
4560 * It is added to the tags database if it doesn't match the
4561 * name of the previous clause header.
4562 *
4563 * Return the size of the name of the function, or 0 if no function
4564 * was found.
4565 */
4566 int
4567 erlang_func (s, last)
4568 char *s;
4569 char *last; /* Name of last clause. */
4570 {
4571 int pos;
4572 int len;
4573
4574 pos = erlang_atom (s, 0);
4575 if (pos < 1)
4576 return 0;
4577
4578 len = pos;
4579 pos = skip_spaces (s + pos) - s;
4580
4581 /* Save only the first clause. */
4582 if (s[pos++] == '('
4583 && (last == NULL
4584 || len != strlen (last)
4585 || !strneq (s, last, len)))
4586 {
4587 pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
4588 s, pos, lineno, linecharno);
4589 return len;
4590 }
4591
4592 return 0;
4593 }
4594
4595
4596 /*
4597 * Handle attributes. Currently, tags are generated for defines
4598 * and records.
4599 *
4600 * They are on the form:
4601 * -define(foo, bar).
4602 * -define(Foo(M, N), M+N).
4603 * -record(graph, {vtab = notable, cyclic = true}).
4604 */
4605 void
4606 erlang_attribute (s)
4607 char *s;
4608 {
4609 int pos;
4610 int len;
4611
4612 if (strneq (s, "-define", 7) || strneq (s, "-record", 7))
4613 {
4614 pos = skip_spaces (s + 7) - s;
4615 if (s[pos++] == '(')
4616 {
4617 pos = skip_spaces (s + pos) - s;
4618 len = erlang_atom (s, pos);
4619 if (len != 0)
4620 pfnote ((CTAGS) ? savenstr (& s[pos], len) : NULL, TRUE,
4621 s, pos + len, lineno, linecharno);
4622 }
4623 }
4624 return;
4625 }
4626
4627
4628 /*
4629 * Consume an Erlang atom (or variable).
4630 * Return the number of bytes consumed, or -1 if there was an error.
4631 */
4632 int
4633 erlang_atom (s, pos)
4634 char *s;
4635 int pos;
4636 {
4637 int origpos;
4638
4639 origpos = pos;
4640
4641 if (isalpha (s[pos]) || s[pos] == '_')
4642 {
4643 /* The atom is unquoted. */
4644 pos++;
4645 while (isalnum (s[pos]) || s[pos] == '_')
4646 pos++;
4647 return pos - origpos;
4648 }
4649 else if (s[pos] == '\'')
4650 {
4651 pos++;
4652
4653 while (1)
4654 {
4655 if (s[pos] == '\'')
4656 {
4657 pos++;
4658 break;
4659 }
4660 else if (s[pos] == '\0')
4661 /* Multiline quoted atoms are ignored. */
4662 return -1;
4663 else if (s[pos] == '\\')
4664 {
4665 if (s[pos+1] == '\0')
4666 return -1;
4667 pos += 2;
4668 }
4669 else
4670 pos++;
4671 }
4672 return pos - origpos;
4673 }
4674 else
4675 return -1;
4676 }
4677
4678 #ifdef ETAGS_REGEXPS
4679
4680 /* Take a string like "/blah/" and turn it into "blah", making sure
4681 that the first and last characters are the same, and handling
4682 quoted separator characters. Actually, stops on the occurrence of
4683 an unquoted separator. Also turns "\t" into a Tab character.
4684 Returns pointer to terminating separator. Works in place. Null
4685 terminates name string. */
4686 char * scan_separators PP ((char *name));
4687 char *
4688 scan_separators (name)
4689 char *name;
4690 {
4691 char sep = name[0];
4692 char *copyto = name;
4693 bool quoted = FALSE;
4694
4695 for (++name; *name != '\0'; ++name)
4696 {
4697 if (quoted)
4698 {
4699 if (*name == 't')
4700 *copyto++ = '\t';
4701 else if (*name == sep)
4702 *copyto++ = sep;
4703 else
4704 {
4705 /* Something else is quoted, so preserve the quote. */
4706 *copyto++ = '\\';
4707 *copyto++ = *name;
4708 }
4709 quoted = FALSE;
4710 }
4711 else if (*name == '\\')
4712 quoted = TRUE;
4713 else if (*name == sep)
4714 break;
4715 else
4716 *copyto++ = *name;
4717 }
4718
4719 /* Terminate copied string. */
4720 *copyto = '\0';
4721 return name;
4722 }
4723
4724 /* Look at the argument of --regex or --no-regex and do the right
4725 thing. Same for each line of a regexp file. */
4726 void
4727 analyse_regex (regex_arg)
4728 char *regex_arg;
4729 {
4730 if (regex_arg == NULL)
4731 free_patterns (); /* --no-regex: remove existing regexps */
4732
4733 /* A real --regexp option or a line in a regexp file. */
4734 switch (regex_arg[0])
4735 {
4736 /* Comments in regexp file or null arg to --regex. */
4737 case '\0':
4738 case ' ':
4739 case '\t':
4740 break;
4741
4742 /* Read a regex file. This is recursive and may result in a
4743 loop, which will stop when the file descriptors are exhausted. */
4744 case '@':
4745 {
4746 FILE *regexfp;
4747 linebuffer regexbuf;
4748 char *regexfile = regex_arg + 1;
4749
4750 /* regexfile is a file containing regexps, one per line. */
4751 regexfp = fopen (regexfile, "r");
4752 if (regexfp == NULL)
4753 {
4754 pfatal (regexfile);
4755 return;
4756 }
4757 initbuffer (&regexbuf);
4758 while (readline_internal (&regexbuf, regexfp) > 0)
4759 analyse_regex (regexbuf.buffer);
4760 free (regexbuf.buffer);
4761 fclose (regexfp);
4762 }
4763 break;
4764
4765 /* Regexp to be used for a specific language only. */
4766 case '{':
4767 {
4768 language *lang;
4769 char *lang_name = regex_arg + 1;
4770 char *cp;
4771
4772 for (cp = lang_name; *cp != '}'; cp++)
4773 if (*cp == '\0')
4774 {
4775 error ("unterminated language name in regex: %s", regex_arg);
4776 return;
4777 }
4778 *cp = '\0';
4779 lang = get_language_from_name (lang_name);
4780 if (lang == NULL)
4781 return;
4782 add_regex (cp + 1, lang);
4783 }
4784 break;
4785
4786 /* Regexp to be used for any language. */
4787 default:
4788 add_regex (regex_arg, NULL);
4789 break;
4790 }
4791 }
4792
4793 /* Turn a name, which is an ed-style (but Emacs syntax) regular
4794 expression, into a real regular expression by compiling it. */
4795 void
4796 add_regex (regexp_pattern, lang)
4797 char *regexp_pattern;
4798 language *lang;
4799 {
4800 char *name;
4801 const char *err;
4802 struct re_pattern_buffer *patbuf;
4803 pattern *pp;
4804
4805
4806 if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
4807 {
4808 error ("%s: unterminated regexp", regexp_pattern);
4809 return;
4810 }
4811 name = scan_separators (regexp_pattern);
4812 if (regexp_pattern[0] == '\0')
4813 {
4814 error ("null regexp", (char *)NULL);
4815 return;
4816 }
4817 (void) scan_separators (name);
4818
4819 patbuf = xnew (1, struct re_pattern_buffer);
4820 patbuf->translate = NULL;
4821 patbuf->fastmap = NULL;
4822 patbuf->buffer = NULL;
4823 patbuf->allocated = 0;
4824
4825 err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
4826 if (err != NULL)
4827 {
4828 error ("%s while compiling pattern", err);
4829 return;
4830 }
4831
4832 pp = p_head;
4833 p_head = xnew (1, pattern);
4834 p_head->regex = savestr (regexp_pattern);
4835 p_head->p_next = pp;
4836 p_head->language = lang;
4837 p_head->pattern = patbuf;
4838 p_head->name_pattern = savestr (name);
4839 p_head->error_signaled = FALSE;
4840 }
4841
4842 /*
4843 * Do the substitutions indicated by the regular expression and
4844 * arguments.
4845 */
4846 char * substitute PP ((char *in, char *out, struct re_registers *regs));
4847 char *
4848 substitute (in, out, regs)
4849 char *in, *out;
4850 struct re_registers *regs;
4851 {
4852 char *result, *t;
4853 int size, dig, diglen;
4854
4855 result = NULL;
4856 size = strlen (out);
4857
4858 /* Pass 1: figure out how much to allocate by finding all \N strings. */
4859 if (out[size - 1] == '\\')
4860 fatal ("pattern error in \"%s\"", out);
4861 for (t = etags_strchr (out, '\\');
4862 t != NULL;
4863 t = etags_strchr (t + 2, '\\'))
4864 if (isdigit (t[1]))
4865 {
4866 dig = t[1] - '0';
4867 diglen = regs->end[dig] - regs->start[dig];
4868 size += diglen - 2;
4869 }
4870 else
4871 size -= 1;
4872
4873 /* Allocate space and do the substitutions. */
4874 result = xnew (size + 1, char);
4875
4876 for (t = result; *out != '\0'; out++)
4877 if (*out == '\\' && isdigit (*++out))
4878 {
4879 /* Using "dig2" satisfies my debugger. Bleah. */
4880 dig = *out - '0';
4881 diglen = regs->end[dig] - regs->start[dig];
4882 strncpy (t, in + regs->start[dig], diglen);
4883 t += diglen;
4884 }
4885 else
4886 *t++ = *out;
4887 *t = '\0';
4888
4889 if (DEBUG && (t > result + size || t - result != strlen (result)))
4890 abort ();
4891
4892 return result;
4893 }
4894
4895 /* Deallocate all patterns. */
4896 void
4897 free_patterns ()
4898 {
4899 pattern *pp;
4900 while (p_head != NULL)
4901 {
4902 pp = p_head->p_next;
4903 free (p_head->regex);
4904 free (p_head->name_pattern);
4905 free (p_head);
4906 p_head = pp;
4907 }
4908 return;
4909 }
4910
4911 #endif /* ETAGS_REGEXPS */
4912 /* Initialize a linebuffer for use */
4913 void
4914 initbuffer (lbp)
4915 linebuffer *lbp;
4916 {
4917 lbp->size = 200;
4918 lbp->buffer = xnew (200, char);
4919 }
4920
4921 /*
4922 * Read a line of text from `stream' into `lbp', excluding the
4923 * newline or CR-NL, if any. Return the number of characters read from
4924 * `stream', which is the length of the line including the newline.
4925 *
4926 * On DOS or Windows we do not count the CR character, if any, before the
4927 * NL, in the returned length; this mirrors the behavior of emacs on those
4928 * platforms (for text files, it translates CR-NL to NL as it reads in the
4929 * file).
4930 */
4931 long
4932 readline_internal (lbp, stream)
4933 linebuffer *lbp;
4934 register FILE *stream;
4935 {
4936 char *buffer = lbp->buffer;
4937 register char *p = lbp->buffer;
4938 register char *pend;
4939 int chars_deleted;
4940
4941 pend = p + lbp->size; /* Separate to avoid 386/IX compiler bug. */
4942
4943 while (1)
4944 {
4945 register int c = getc (stream);
4946 if (p == pend)
4947 {
4948 /* We're at the end of linebuffer: expand it. */
4949 lbp->size *= 2;
4950 buffer = xrnew (buffer, lbp->size, char);
4951 p += buffer - lbp->buffer;
4952 pend = buffer + lbp->size;
4953 lbp->buffer = buffer;
4954 }
4955 if (c == EOF)
4956 {
4957 *p = '\0';
4958 chars_deleted = 0;
4959 break;
4960 }
4961 if (c == '\n')
4962 {
4963 if (p > buffer && p[-1] == '\r')
4964 {
4965 p -= 1;
4966 #ifdef DOS_NT
4967 /* Assume CRLF->LF translation will be performed by Emacs
4968 when loading this file, so CRs won't appear in the buffer.
4969 It would be cleaner to compensate within Emacs;
4970 however, Emacs does not know how many CRs were deleted
4971 before any given point in the file. */
4972 chars_deleted = 1;
4973 #else
4974 chars_deleted = 2;
4975 #endif
4976 }
4977 else
4978 {
4979 chars_deleted = 1;
4980 }
4981 *p = '\0';
4982 break;
4983 }
4984 *p++ = c;
4985 }
4986 lbp->len = p - buffer;
4987
4988 return lbp->len + chars_deleted;
4989 }
4990
4991 /*
4992 * Like readline_internal, above, but in addition try to match the
4993 * input line against relevant regular expressions.
4994 */
4995 long
4996 readline (lbp, stream)
4997 linebuffer *lbp;
4998 FILE *stream;
4999 {
5000 /* Read new line. */
5001 long result = readline_internal (lbp, stream);
5002 #ifdef ETAGS_REGEXPS
5003 int match;
5004 pattern *pp;
5005
5006 /* Match against relevant patterns. */
5007 if (lbp->len > 0)
5008 for (pp = p_head; pp != NULL; pp = pp->p_next)
5009 {
5010 /* Only use generic regexps or those for the current language. */
5011 if (pp->language != NULL && pp->language != curlang)
5012 continue;
5013
5014 match = re_match (pp->pattern, lbp->buffer, lbp->len, 0, &pp->regs);
5015 switch (match)
5016 {
5017 case -2:
5018 /* Some error. */
5019 if (!pp->error_signaled)
5020 {
5021 error ("error while matching \"%s\"", pp->regex);
5022 pp->error_signaled = TRUE;
5023 }
5024 break;
5025 case -1:
5026 /* No match. */
5027 break;
5028 default:
5029 /* Match occurred. Construct a tag. */
5030 if (pp->name_pattern[0] != '\0')
5031 {
5032 /* Make a named tag. */
5033 char *name = substitute (lbp->buffer,
5034 pp->name_pattern, &pp->regs);
5035 if (name != NULL)
5036 pfnote (name, TRUE, lbp->buffer, match, lineno, linecharno);
5037 }
5038 else
5039 {
5040 /* Make an unnamed tag. */
5041 pfnote ((char *)NULL, TRUE,
5042 lbp->buffer, match, lineno, linecharno);
5043 }
5044 break;
5045 }
5046 }
5047 #endif /* ETAGS_REGEXPS */
5048
5049 return result;
5050 }
5051
5052 /*
5053 * Return a pointer to a space of size strlen(cp)+1 allocated
5054 * with xnew where the string CP has been copied.
5055 */
5056 char *
5057 savestr (cp)
5058 char *cp;
5059 {
5060 return savenstr (cp, strlen (cp));
5061 }
5062
5063 /*
5064 * Return a pointer to a space of size LEN+1 allocated with xnew where
5065 * the string CP has been copied for at most the first LEN characters.
5066 */
5067 char *
5068 savenstr (cp, len)
5069 char *cp;
5070 int len;
5071 {
5072 register char *dp;
5073
5074 dp = xnew (len + 1, char);
5075 strncpy (dp, cp, len);
5076 dp[len] = '\0';
5077 return dp;
5078 }
5079
5080 /*
5081 * Return the ptr in sp at which the character c last
5082 * appears; NULL if not found
5083 *
5084 * Identical to System V strrchr, included for portability.
5085 */
5086 char *
5087 etags_strrchr (sp, c)
5088 register char *sp;
5089 register int c;
5090 {
5091 register char *r;
5092
5093 r = NULL;
5094 do
5095 {
5096 if (*sp == c)
5097 r = sp;
5098 } while (*sp++);
5099 return r;
5100 }
5101
5102
5103 /*
5104 * Return the ptr in sp at which the character c first
5105 * appears; NULL if not found
5106 *
5107 * Identical to System V strchr, included for portability.
5108 */
5109 char *
5110 etags_strchr (sp, c)
5111 register char *sp;
5112 register int c;
5113 {
5114 do
5115 {
5116 if (*sp == c)
5117 return sp;
5118 } while (*sp++);
5119 return NULL;
5120 }
5121
5122 /* Skip spaces, return new pointer. */
5123 char *
5124 skip_spaces (cp)
5125 char *cp;
5126 {
5127 while (isspace (*cp)) /* isspace('\0')==FALSE */
5128 cp++;
5129 return cp;
5130 }
5131
5132 /* Skip non spaces, return new pointer. */
5133 char *
5134 skip_non_spaces (cp)
5135 char *cp;
5136 {
5137 while (!iswhite (*cp)) /* iswhite('\0')==TRUE */
5138 cp++;
5139 return cp;
5140 }
5141
5142 /* Print error message and exit. */
5143 void
5144 fatal (s1, s2)
5145 char *s1, *s2;
5146 {
5147 error (s1, s2);
5148 exit (BAD);
5149 }
5150
5151 void
5152 pfatal (s1)
5153 char *s1;
5154 {
5155 perror (s1);
5156 exit (BAD);
5157 }
5158
5159 void
5160 suggest_asking_for_help ()
5161 {
5162 fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
5163 progname,
5164 #ifdef LONG_OPTIONS
5165 "--help"
5166 #else
5167 "-h"
5168 #endif
5169 );
5170 exit (BAD);
5171 }
5172
5173 /* Print error message. `s1' is printf control string, `s2' is arg for it. */
5174 void
5175 error (s1, s2)
5176 const char *s1, *s2;
5177 {
5178 fprintf (stderr, "%s: ", progname);
5179 fprintf (stderr, s1, s2);
5180 fprintf (stderr, "\n");
5181 }
5182
5183 /* Return a newly-allocated string whose contents
5184 concatenate those of s1, s2, s3. */
5185 char *
5186 concat (s1, s2, s3)
5187 char *s1, *s2, *s3;
5188 {
5189 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
5190 char *result = xnew (len1 + len2 + len3 + 1, char);
5191
5192 strcpy (result, s1);
5193 strcpy (result + len1, s2);
5194 strcpy (result + len1 + len2, s3);
5195 result[len1 + len2 + len3] = '\0';
5196
5197 return result;
5198 }
5199
5200 /* Does the same work as the system V getcwd, but does not need to
5201 guess the buffer size in advance. */
5202 char *
5203 etags_getcwd ()
5204 {
5205 #ifdef HAVE_GETCWD
5206 int bufsize = 200;
5207 char *path = xnew (bufsize, char);
5208
5209 while (getcwd (path, bufsize) == NULL)
5210 {
5211 if (errno != ERANGE)
5212 pfatal ("getcwd");
5213 bufsize *= 2;
5214 free (path);
5215 path = xnew (bufsize, char);
5216 }
5217
5218 canonicalize_filename (path);
5219 return path;
5220
5221 #else /* not HAVE_GETCWD */
5222 #ifdef MSDOS
5223 char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
5224
5225 getwd (path);
5226
5227 for (p = path; *p != '\0'; p++)
5228 if (*p == '\\')
5229 *p = '/';
5230 else
5231 *p = lowcase (*p);
5232
5233 return strdup (path);
5234 #else /* not MSDOS */
5235 linebuffer path;
5236 FILE *pipe;
5237
5238 initbuffer (&path);
5239 pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
5240 if (pipe == NULL || readline_internal (&path, pipe) == 0)
5241 pfatal ("pwd");
5242 pclose (pipe);
5243
5244 return path.buffer;
5245 #endif /* not MSDOS */
5246 #endif /* not HAVE_GETCWD */
5247 }
5248
5249 /* Return a newly allocated string containing the file name of FILE
5250 relative to the absolute directory DIR (which should end with a slash). */
5251 char *
5252 relative_filename (file, dir)
5253 char *file, *dir;
5254 {
5255 char *fp, *dp, *afn, *res;
5256 int i;
5257
5258 /* Find the common root of file and dir (with a trailing slash). */
5259 afn = absolute_filename (file, cwd);
5260 fp = afn;
5261 dp = dir;
5262 while (*fp++ == *dp++)
5263 continue;
5264 fp--, dp--; /* back to the first differing char */
5265 do /* look at the equal chars until '/' */
5266 fp--, dp--;
5267 while (*fp != '/');
5268
5269 /* Build a sequence of "../" strings for the resulting relative file name. */
5270 i = 0;
5271 while ((dp = etags_strchr (dp + 1, '/')) != NULL)
5272 i += 1;
5273 res = xnew (3*i + strlen (fp + 1) + 1, char);
5274 res[0] = '\0';
5275 while (i-- > 0)
5276 strcat (res, "../");
5277
5278 /* Add the file name relative to the common root of file and dir. */
5279 strcat (res, fp + 1);
5280 free (afn);
5281
5282 return res;
5283 }
5284
5285 /* Return a newly allocated string containing the absolute file name
5286 of FILE given DIR (which should end with a slash). */
5287 char *
5288 absolute_filename (file, dir)
5289 char *file, *dir;
5290 {
5291 char *slashp, *cp, *res;
5292
5293 if (filename_is_absolute (file))
5294 res = savestr (file);
5295 #ifdef DOS_NT
5296 /* We don't support non-absolute file names with a drive
5297 letter, like `d:NAME' (it's too much hassle). */
5298 else if (file[1] == ':')
5299 fatal ("%s: relative file names with drive letters not supported", file);
5300 #endif
5301 else
5302 res = concat (dir, file, "");
5303
5304 /* Delete the "/dirname/.." and "/." substrings. */
5305 slashp = etags_strchr (res, '/');
5306 while (slashp != NULL && slashp[0] != '\0')
5307 {
5308 if (slashp[1] == '.')
5309 {
5310 if (slashp[2] == '.'
5311 && (slashp[3] == '/' || slashp[3] == '\0'))
5312 {
5313 cp = slashp;
5314 do
5315 cp--;
5316 while (cp >= res && !filename_is_absolute (cp));
5317 if (cp < res)
5318 cp = slashp; /* the absolute name begins with "/.." */
5319 #ifdef DOS_NT
5320 /* Under MSDOS and NT we get `d:/NAME' as absolute
5321 file name, so the luser could say `d:/../NAME'.
5322 We silently treat this as `d:/NAME'. */
5323 else if (cp[0] != '/')
5324 cp = slashp;
5325 #endif
5326 strcpy (cp, slashp + 3);
5327 slashp = cp;
5328 continue;
5329 }
5330 else if (slashp[2] == '/' || slashp[2] == '\0')
5331 {
5332 strcpy (slashp, slashp + 2);
5333 continue;
5334 }
5335 }
5336
5337 slashp = etags_strchr (slashp + 1, '/');
5338 }
5339
5340 if (res[0] == '\0')
5341 return savestr ("/");
5342 else
5343 return res;
5344 }
5345
5346 /* Return a newly allocated string containing the absolute
5347 file name of dir where FILE resides given DIR (which should
5348 end with a slash). */
5349 char *
5350 absolute_dirname (file, dir)
5351 char *file, *dir;
5352 {
5353 char *slashp, *res;
5354 char save;
5355
5356 canonicalize_filename (file);
5357 slashp = etags_strrchr (file, '/');
5358 if (slashp == NULL)
5359 return savestr (dir);
5360 save = slashp[1];
5361 slashp[1] = '\0';
5362 res = absolute_filename (file, dir);
5363 slashp[1] = save;
5364
5365 return res;
5366 }
5367
5368 /* Whether the argument string is an absolute file name. The argument
5369 string must have been canonicalized with canonicalize_filename. */
5370 bool
5371 filename_is_absolute (fn)
5372 char *fn;
5373 {
5374 return (fn[0] == '/'
5375 #ifdef DOS_NT
5376 || (isalpha(fn[0]) && fn[1] == ':' && fn[2] == '/')
5377 #endif
5378 );
5379 }
5380
5381 /* Translate backslashes into slashes. Works in place. */
5382 void
5383 canonicalize_filename (fn)
5384 register char *fn;
5385 {
5386 #ifdef DOS_NT
5387 for (; *fn != '\0'; fn++)
5388 if (*fn == '\\')
5389 *fn = '/';
5390 #else
5391 /* No action. */
5392 #endif
5393 }
5394
5395 /* Increase the size of a linebuffer. */
5396 void
5397 grow_linebuffer (lbp, toksize)
5398 linebuffer *lbp;
5399 int toksize;
5400 {
5401 while (lbp->size < toksize)
5402 lbp->size *= 2;
5403 lbp->buffer = xrnew (lbp->buffer, lbp->size, char);
5404 }
5405
5406 /* Like malloc but get fatal error if memory is exhausted. */
5407 long *
5408 xmalloc (size)
5409 unsigned int size;
5410 {
5411 long *result = (long *) malloc (size);
5412 if (result == NULL)
5413 fatal ("virtual memory exhausted", (char *)NULL);
5414 return result;
5415 }
5416
5417 long *
5418 xrealloc (ptr, size)
5419 char *ptr;
5420 unsigned int size;
5421 {
5422 long *result = (long *) realloc (ptr, size);
5423 if (result == NULL)
5424 fatal ("virtual memory exhausted", (char *)NULL);
5425 return result;
5426 }