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