1 From jbw@bigbird.bu.edu Sun Apr 5 14:58:19 1992
2 From: jbw@bigbird.bu.edu (Joe Wells)
3 Newsgroups: gnu.emacs.bug
4 Subject: numerous bug fixes for etags
5 Date: 3 Apr 92 19:46:52 GMT
7 Organization: GNUs Not Usenet
9 Enclosed is a patch with numerous changes for etags. The following are
10 the changes and bugs fixed:
12 1. Improvement: don't waste time calling strncmp (with "struct", "union",
13 "enum", "typedef") if the lengths are different.
15 2. Bug: pfnote placed a NUL in the line buffer after the tag token which caused
16 things like `{' or `/*' to be ignored, thus severely screwing up the
17 parser. Or it did something horrible, I don't remember for sure.
19 3. Improvement: record defining occurrences of struct/union/enum tags.
20 This works even if combined with a typedef definition, for example:
26 4. Bug: when a tag token was the last item on the line before the newline
27 character, garbage would be seen as the token. This is because when a
28 NUL was seen in the buffer the buffer was replaced with the next line.
30 5. Bug: tag tokens immediately followed by a `{' with no intervening space
31 were not recorded. This was only a problem because of improvement 3
34 6. Bug: a newline in the middle of a comment zeroed the `number' variable.
35 (Just for good measure I made it not zero `number' in strings even when
36 the newline is not preceded by `\', in case someone wants to run etags
37 on illegal code :-) (`number' is used only on lines that begin with
40 7. Bug: handling of #define lines was severely broken. I don't actually
41 remember what etags did with them, but it was really bad. It now
42 records macro definitions.
44 8. Bug: when a tag token was the last item on the line except for
45 whitespace, etags would replace the contents of the line buffer and
46 then later do various string comparisons and inspections against
47 garbage values instead of against the token. Fixing this required
48 copying the token into a buffer. (This is roughly the same as bug 4
49 above, but in a different function.)
51 9. Bug: when a tag token was the last item on the line before the newline
52 (and under various other circumstances), etags would skip over the NUL
53 in the buffer and skip to the first non-whitespace character in the
56 10. Improvement (possibly bug fix): parse typedefs even when we aren't
57 going to print them out. I seem to remember that this fixed some bug,
58 but I don't remember the specific case that would trigger the bug.
60 11. An unfinished attempt to detect and record global variable
63 The changes are to the 18.57 version of etags, but the only change in
64 18.58 to the C code handling is to initialize some variables when starting
65 on a new file, so these changes are orthogonal.
70 Joe Wells <jbw@cs.bu.edu>
72 Member of the League for Programming Freedom --- send e-mail for details
74 ----------------------------------------------------------------------
75 --- etags.c-dist Tue Jan 8 14:08:38 1991
76 +++ etags.c Sat Apr 4 00:41:22 1992
79 /* cause token checking for typedef, struct, union, enum to distinguish
80 keywords from identifier-prefixes (e.g. struct vs struct_tag). */
81 -#define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))
82 +#define istoken(s, t, len) \
83 + (((len) == (sizeof (t) -1)) && \
84 + ((strncmp(s, t, len)) == 0) && \
85 + (endtoken(*((s)+(len)))))
87 struct nd_st { /* sorting structure */
88 char *name; /* function or type name */
98 np->left = np->right = 0;
101 + save = linestart[linelen];
102 linestart[linelen] = 0;
108 np->pat = savestr (linestart);
109 + linestart[linelen] = save;
117 +/* These two are part of a never-finished attempt to record global */
118 +/* variable definitions. This is nearly impossible in C without the full */
119 +/* power of a C compiler due to C's stupid grammar. */
123 +/* indicates whether the next token (if any) is the tag corresponding to */
124 +/* `struct', `union', or `enum' */
125 +logical next_token_is_tag;
132 register char *token, *tp, *lp;
133 logical incomm, inquote, inchar, midtoken;
136 + /* there are certain things that must be done when the end of line is */
137 + /* encountered, but they must be delayed until after other things are */
139 + logical new_line_flag;
141 + /* same as new_line_flag for left braces. */
142 + logical left_brace_flag;
147 @@ -739,17 +765,22 @@
151 - gotone = midtoken = inquote = inchar = incomm = FALSE;
152 + gotone = midtoken = inquote = inchar = incomm = infunc = FALSE;
153 + new_line_flag = FALSE;
154 + left_brace_flag = FALSE;
156 + idents_in_decl = 0;
157 + next_token_is_tag = FALSE;
167 + new_line_flag = TRUE;
169 + if (next_token_is_tag)
170 + fprintf (stderr, "E: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
175 @@ -756,15 +787,18 @@
179 + /* is this correct? I thought escaped newlines disappeared even */
180 + /* before the token breaker got to see things. */
184 + new_line_flag = FALSE;
187 while ((c = *lp++) == '*')
199 + new_line_flag = FALSE;
201 * Too dumb to know about \" not being magic, but
202 * they usually occur in pairs anyway.
207 + new_line_flag = FALSE;
217 + left_brace_flag = TRUE;
220 if (lp == lb.buffer + 1)
221 level = 0; /* reset */
226 + if (level == 0 && infunc)
228 + idents_in_decl = 0;
234 + if (next_token_is_tag)
235 + fprintf (stderr, "D: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
237 if (!level && !inquote && !incomm && gotone == FALSE)
243 pfnote(tok, f, lb1.buffer, endpos, line, linestart);
246 + "f: %d, infunc %d, tok: %s\nlb1.buffer: %s\n",
247 + f, infunc, tok, lb1.buffer);
253 strncpy (tok, token, tp-token+1);
255 pfnote(tok, f, lb.buffer, endpos, line, linestart);
258 + "f: %d, infunc %d, tok: %s\nlb.buffer: %s\n",
259 + f, infunc, tok, lb.buffer);
262 gotone = f; /* function */
273 + if (next_token_is_tag)
274 + fprintf (stderr, "F: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
276 + if (left_brace_flag)
278 + left_brace_flag = FALSE;
279 + next_token_is_tag = FALSE;
284 + new_line_flag = FALSE;
288 + if (lp > lb.buffer && lp[-1] == 0)
290 if (c == ';' && tydef==end) /* clean with typedefs */
292 + if (c == ';' && level == 0 && !infunc)
293 + idents_in_decl = 0;
295 + if (next_token_is_tag)
296 + fprintf (stderr, "G: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
301 @@ -891,70 +972,176 @@
304 static logical next_token_is_func;
306 + /* indicates that the next token will be a macro defined with #define */
307 + static logical next_token_is_macro;
309 logical firsttok; /* T if have seen first token in ()'s */
311 + int bad = FALSE, win = FALSE;
312 + int length = (lp - 1) - token;
314 + /* used to keep a copy of the token when we have to fill the line buffer */
315 + /* with the contents of the next line */
316 + static char *tok_buffer = NULL;
317 + static long tok_buffer_size = 0;
319 *f = 1; /* a function */
323 { /* space is not allowed in macro defs */
325 + while ((c == 0) || iswhite(c))
330 + if (next_token_is_tag)
331 + fprintf (stderr, "C: token: %s, c: [%c], lp - token: %d\n",
332 + token, c, lp - token);
338 + goto break_while_1;
339 + if (token != tok_buffer)
341 + if (length + 1 > tok_buffer_size)
342 + if (tok_buffer_size == 0)
344 + tok_buffer_size = length + 1;
345 + tok_buffer = (char *) xmalloc (tok_buffer_size);
349 + tok_buffer_size = length + 1;
351 + (char *) xrealloc (tok_buffer, tok_buffer_size);
353 + strncpy (tok_buffer, token, length);
354 + tok_buffer[length] = '\0';
355 + token = tok_buffer;
360 + while ((c != 0) && iswhite(c))
363 - /* the following tries to make it so that a #define a b(c) */
364 - /* doesn't count as a define of b. */
370 + /* the following tries to make it so that a #define a b(c) */
371 + /* doesn't count as a define of b. */
373 - if (number >= 4 || (number==2 && strncmp (token, "define", 6)))
378 + fprintf (stderr, "number: %d, n_t_i_m: %d, token: %s\n",
379 + number, next_token_is_macro, token);
381 + if (number == 2 && strncmp (token, "define", 6) == 0)
382 + next_token_is_macro = TRUE;
383 + else if (number == 3 && next_token_is_macro)
385 + next_token_is_macro = FALSE;
386 + while ((c != 0) && iswhite(c))
389 + fprintf (stderr, "c: %c, %d\n", c, c);
394 + fprintf (stderr, "c: %c, %d\n", c, c);
396 + if (c == 0) /* ignore plain "#define FLAG" */
400 + /* speed up skipping the rest of this line */
402 + /* never treat a macro as a function, because it doesn't have a */
403 + /* function body, which is what "f" really stands for (now). */
408 + /* speed up skipping the rest of this line */
415 + "A: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n",
416 + idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c,
417 + length + 5, token);
419 /* check for the typedef cases */
420 - if (tflag && istoken(token, "typedef", 7))
421 + if (istoken (token, "typedef", length))
426 - if (tydef==begin && (istoken(token, "struct", 6) ||
427 - istoken(token, "union", 5) || istoken(token, "enum", 4)))
430 + fprintf (stderr, "D\n");
432 + if (istoken (token, "struct", length) ||
433 + istoken (token, "union", length) ||
434 + istoken (token, "enum", length))
436 + next_token_is_tag = 1;
438 + fprintf (stderr, "A: token: %s\n", token);
440 + if (tydef == begin)
445 + else if (next_token_is_tag)
448 + fprintf (stderr, "B: token: %s, c: [%c]\n", token, c);
453 + next_token_is_tag = 0;
455 + /* only notice when a tag is being defined, not when it is merely */
464 + fprintf (stderr, "E\n");
466 if (tydef==begin) /* e.g. typedef ->int<- */
472 + fprintf (stderr, "F\n");
474 if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */
479 + fprintf (stderr, "G\n");
486 + fprintf (stderr, "C token: %s\n", token);
492 + fprintf (stderr, "H\n");
494 /* Detect GNUmacs's function-defining macros. */
495 if (!number && !strncmp (token, "DEF", 3))
498 next_token_is_func = 1;
502 + fprintf (stderr, "I\n");
504 if (next_token_is_func)
506 next_token_is_func = 0;
507 @@ -968,9 +1158,15 @@
512 + fprintf (stderr, "J\n");
518 + fprintf (stderr, "K\n");
520 while ((c = *lp++) != ')')
523 @@ -999,9 +1195,20 @@
531 + "B: iid: %d, tydef: %d, ntit: %d, ntif: %d, c: %c, token: %.*s\n",
532 + idents_in_decl, tydef, next_token_is_tag, next_token_is_func, c,
533 + length + 5, token);
544 ----------------------------------------------------------------------