[project @ 1996-07-19 18:36:04 by partain]
[ghc-hetmet.git] / glafp-utils / etags / wells-fixes
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
6 Distribution: gnu
7 Organization: GNUs Not Usenet
8
9 Enclosed is a patch with numerous changes for etags.  The following are
10 the changes and bugs fixed:
11
12 1. Improvement: don't waste time calling strncmp (with "struct", "union",
13    "enum", "typedef") if the lengths are different.
14
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.
18
19 3. Improvement: record defining occurrences of struct/union/enum tags.
20    This works even if combined with a typedef definition, for example:
21
22      typedef struct XXX {
23        .....
24      } YYY;
25
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.
29
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
32    above.
33
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
38    `#'.)
39
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.
43
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.)
50
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
54    buffer.
55
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.
59
60 11. An unfinished attempt to detect and record global variable
61     definitions.
62
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.
66
67 -- 
68 Enjoy,
69
70 Joe Wells <jbw@cs.bu.edu>
71
72 Member of the League for Programming Freedom --- send e-mail for details
73
74 ----------------------------------------------------------------------
75 --- etags.c-dist        Tue Jan  8 14:08:38 1991
76 +++ etags.c     Sat Apr  4 00:41:22 1992
77 @@ -62,7 +62,10 @@
78  
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)))))
86  
87  struct nd_st {                 /* sorting structure                    */
88         char    *name;                  /* function or type name        */
89 @@ -505,6 +508,7 @@
90  {
91    register char *fp;
92    register NODE *np;
93 +  char save;
94    char *altname;
95    char tem[51];
96  
97 @@ -538,6 +542,7 @@
98    np->left = np->right = 0;
99    if (eflag)
100      {
101 +      save = linestart[linelen];
102        linestart[linelen] = 0;
103      }
104    else if (xflag == 0)
105 @@ -546,6 +551,7 @@
106        linestart = tem;
107      }
108    np->pat = savestr (linestart);
109 +  linestart[linelen] = save;
110    if (head == NULL)
111      head = np;
112    else
113 @@ -725,6 +731,17 @@
114    number = 0; \
115  }
116  
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. */
120 +logical infunc;
121 +int idents_in_decl;
122 +
123 +/* indicates whether the next token (if any) is the tag corresponding to */
124 +/* `struct', `union', or `enum' */
125 +logical next_token_is_tag;
126 +
127 +
128  C_entries ()
129  {
130    register int c;
131 @@ -731,6 +748,15 @@
132    register char *token, *tp, *lp;
133    logical incomm, inquote, inchar, midtoken;
134    int level;
135 +
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 */
138 +  /* done. */
139 +  logical new_line_flag;
140 +
141 +  /* same as new_line_flag for left braces. */
142 +  logical left_brace_flag;
143 +
144    char tok[BUFSIZ];
145  
146    lineno = 0;
147 @@ -739,17 +765,22 @@
148    *lp = 0;
149  
150    number = 0;
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;
155    level = 0;
156 +  idents_in_decl = 0;
157 +  next_token_is_tag = FALSE;
158  
159    while (!feof (inf))
160      {
161        c = *lp++;
162        if (c == 0)
163 -       {
164 -         CNL;
165 -         gotone = FALSE;
166 -       }
167 +       new_line_flag = TRUE;
168 +#ifdef DEBUG
169 +      if (next_token_is_tag)
170 +       fprintf (stderr, "E: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
171 +#endif /* DEBUG */
172        if (c == '\\')
173         {
174           c = *lp++;
175 @@ -756,15 +787,18 @@
176           if (c == 0)
177             CNL_SAVE_NUMBER;
178           c = ' ';
179 +         /* is this correct?  I thought escaped newlines disappeared even */
180 +         /* before the token breaker got to see things. */ 
181         } 
182        else if (incomm)
183         {
184 +         new_line_flag = FALSE;
185           if (c == '*')
186             {
187               while ((c = *lp++) == '*')
188                 continue;
189               if (c == 0)
190 -               CNL;
191 +               CNL_SAVE_NUMBER;
192               if (c == '/')
193                 incomm = FALSE;
194             }
195 @@ -771,6 +805,7 @@
196         }
197        else if (inquote)
198         {
199 +         new_line_flag = FALSE;
200           /*
201           * Too dumb to know about \" not being magic, but
202           * they usually occur in pairs anyway.
203 @@ -781,6 +816,7 @@
204         }
205        else if (inchar)
206         {
207 +         new_line_flag = FALSE;
208           if (c == '\'')
209             inchar = FALSE;
210           continue;
211 @@ -809,8 +845,8 @@
212             {
213               tydef=middle;
214             }
215 -         level++;
216 -         continue;
217 +         left_brace_flag = TRUE;
218 +         break;
219         case '}':
220           if (lp == lb.buffer + 1)
221             level = 0;  /* reset */
222 @@ -820,8 +856,17 @@
223             {
224               tydef=end;
225             }
226 +         if (level == 0 && infunc)
227 +           {
228 +             idents_in_decl = 0;
229 +             infunc = FALSE;
230 +           }
231           continue;
232         }
233 +#ifdef DEBUG
234 +      if (next_token_is_tag)
235 +       fprintf (stderr, "D: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
236 +#endif /* DEBUG */
237        if (!level && !inquote && !incomm && gotone == FALSE)
238         {
239           if (midtoken)
240 @@ -852,6 +897,11 @@
241                                    tp-token+1);
242                           tok[tp-token+1] = 0;
243                           pfnote(tok, f, lb1.buffer, endpos, line, linestart);
244 +#ifdef DEBUG
245 +                         fprintf (stderr,
246 +                                "f: %d, infunc %d, tok: %s\nlb1.buffer: %s\n",
247 +                                  f, infunc, tok, lb1.buffer);
248 +#endif /* DEBUG */
249                         }
250                       else
251                         {
252 @@ -858,8 +908,15 @@
253                           strncpy (tok, token, tp-token+1);
254                           tok[tp-token+1] = 0;
255                           pfnote(tok, f, lb.buffer, endpos, line, linestart);
256 +#ifdef DEBUG
257 +                         fprintf (stderr,
258 +                                "f: %d, infunc %d, tok: %s\nlb.buffer:  %s\n",
259 +                                  f, infunc, tok, lb.buffer);
260 +#endif /* DEBUG */
261                         }
262                       gotone = f;       /* function */
263 +                     if (f)
264 +                       infunc = TRUE;
265                     }
266                   midtoken = FALSE;
267                   token = lp - 1;
268 @@ -873,8 +930,32 @@
269               midtoken = TRUE;
270             }
271         }
272 +#ifdef DEBUG
273 +      if (next_token_is_tag)
274 +       fprintf (stderr, "F: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
275 +#endif /* DEBUG */
276 +      if (left_brace_flag)
277 +       {
278 +         left_brace_flag = FALSE;
279 +         next_token_is_tag = FALSE;
280 +         level++;
281 +       }
282 +      if (new_line_flag)
283 +       {
284 +         new_line_flag = FALSE;
285 +         number = 0;
286 +         gotone = FALSE;
287 +       }
288 +      if (lp > lb.buffer && lp[-1] == 0)
289 +       CNL_SAVE_NUMBER;
290        if (c == ';'  &&  tydef==end)    /* clean with typedefs */
291         tydef=none;
292 +      if (c == ';' && level == 0 && !infunc)
293 +       idents_in_decl = 0;
294 +#ifdef DEBUG
295 +      if (next_token_is_tag)
296 +       fprintf (stderr, "G: c: [%c], lp[-2]: [%c]\n", c, lp[-2]);
297 +#endif /* DEBUG */
298      }
299  }
300  
301 @@ -891,70 +972,176 @@
302    reg char *lp = *lpp;
303    reg char c;
304    static logical next_token_is_func;
305 +
306 +  /* indicates that the next token will be a macro defined with #define */
307 +  static logical next_token_is_macro;
308 +
309    logical firsttok;    /* T if have seen first token in ()'s */
310 -  int bad, win;
311 +  int bad = FALSE, win = FALSE;
312 +  int length = (lp - 1) - token;
313 +  
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;
318  
319    *f = 1;                      /* a function */
320    c = lp[-1];
321 -  bad = FALSE;
322    if (!number)
323      {          /* space is not allowed in macro defs   */
324 -      while (iswhite(c))
325 +      while ((c == 0) || iswhite(c))
326         {
327 -         c = *lp++;
328 -         if (c == 0)
329 +#ifdef DEBUG
330 +         if (next_token_is_tag)
331 +           fprintf (stderr, "C: token: %s, c: [%c], lp - token: %d\n",
332 +                    token, c, lp - token);
333 +#endif /* DEBUG */
334 +         while (c == 0)
335             {
336               if (feof (inf))
337 -               break;
338 +               goto break_while_1;
339 +             if (token != tok_buffer)
340 +               {
341 +                 if (length + 1 > tok_buffer_size)
342 +                   if (tok_buffer_size == 0)
343 +                     {
344 +                       tok_buffer_size = length + 1;
345 +                       tok_buffer = (char *) xmalloc (tok_buffer_size);
346 +                     }
347 +                   else
348 +                     {
349 +                       tok_buffer_size = length + 1;
350 +                       tok_buffer =
351 +                         (char *) xrealloc (tok_buffer, tok_buffer_size);
352 +                     }
353 +                 strncpy (tok_buffer, token, length);
354 +                 tok_buffer[length] = '\0';
355 +                 token = tok_buffer;
356 +               }
357               CNL;
358 +             c = *lp++;
359             }
360 +         while ((c != 0) && iswhite(c))
361 +           c = *lp++;
362         }
363 -      /* the following tries to make it so that a #define a b(c)       */
364 -      /* doesn't count as a define of b.                               */
365 +    break_while_1:
366 +      ;
367      }
368    else
369      {
370 +      /* the following tries to make it so that a #define a b(c)       */
371 +      /* doesn't count as a define of b.                               */
372        number++;
373 -      if (number >= 4  || (number==2 && strncmp (token, "define", 6)))
374 -       {
375 -         gotone = TRUE;
376 -       badone:
377 +#ifdef DEBUG
378 +      fprintf (stderr, "number: %d, n_t_i_m: %d, token: %s\n",
379 +              number, next_token_is_macro, token);
380 +#endif /* DEBUG */
381 +      if (number == 2 && strncmp (token, "define", 6) == 0)
382 +       next_token_is_macro = TRUE;
383 +      else if (number == 3 && next_token_is_macro)
384 +       {
385 +         next_token_is_macro = FALSE;
386 +         while ((c != 0) && iswhite(c))
387 +           {
388 +#ifdef DEBUG
389 +             fprintf (stderr, "c: %c, %d\n", c, c);
390 +#endif /* DEBUG */
391 +             c = *lp++;
392 +           }
393 +#ifdef DEBUG
394 +         fprintf (stderr, "c: %c, %d\n", c, c);
395 +#endif /* DEBUG */
396 +         if (c == 0)           /* ignore plain "#define FLAG" */
397           bad = TRUE;
398 +         else
399 +           win = TRUE;
400 +         /* speed up skipping the rest of this line */
401 +         gotone = TRUE;
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). */
404 +         *f = FALSE;
405           goto ret;
406         }
407 +      else
408 +       /* speed up skipping the rest of this line */
409 +       gotone = TRUE;
410 +      goto badone;
411      }
412 +  idents_in_decl ++;
413 +#ifdef DEBUG
414 +  fprintf (stderr,
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);
418 +#endif /* DEBUG */
419    /* check for the typedef cases               */
420 -  if (tflag && istoken(token, "typedef", 7))
421 +  if (istoken (token, "typedef", length))
422      {
423        tydef=begin;
424        goto badone;
425      }
426 -  if (tydef==begin && (istoken(token, "struct", 6) ||
427 -                      istoken(token, "union", 5) || istoken(token, "enum", 4)))
428 -  {
429 +#ifdef DEBUG
430 +  fprintf (stderr, "D\n");
431 +#endif /* DEBUG */
432 +  if (istoken (token, "struct", length) ||
433 +      istoken (token, "union", length) ||
434 +      istoken (token, "enum", length))
435 +    {
436 +      next_token_is_tag = 1;
437 +#ifdef DEBUG
438 +      fprintf (stderr, "A: token: %s\n", token);
439 +#endif /* DEBUG */
440 +      if (tydef == begin)
441      tydef=tag_ok;      
442      goto badone;
443    }
444 -  if (tydef==tag_ok)
445 +  else if (next_token_is_tag)
446      {
447 +#ifdef DEBUG
448 +      fprintf (stderr, "B: token: %s, c: [%c]\n", token, c);
449 +#endif /* DEBUG */
450 +      if (tydef==tag_ok)
451        tydef=middle;
452 -      goto badone;
453 +      next_token_is_tag = 0;
454 +      *f = 0;
455 +      /* only notice when a tag is being defined, not when it is merely */
456 +      /* being used. */
457 +      if (c == '{')
458 +       win = TRUE;
459 +      else
460 +       bad = TRUE;
461 +      goto ret;
462      }
463 +#ifdef DEBUG
464 +  fprintf (stderr, "E\n");
465 +#endif /* DEBUG */
466    if (tydef==begin)            /* e.g. typedef ->int<- */
467      {
468        tydef=end;
469        goto badone;
470      }
471 +#ifdef DEBUG
472 +  fprintf (stderr, "F\n");
473 +#endif /* DEBUG */
474    if (tydef==middle && level == 0) /* e.g. typedef struct tag ->struct_t<- */
475      {
476        tydef=end;
477      }
478 +#ifdef DEBUG
479 +  fprintf (stderr, "G\n");
480 +#endif /* DEBUG */
481    if (tydef==end)
482      {
483        *f = 0;
484 -      win = 1;
485 +#ifdef DEBUG
486 +      fprintf (stderr, "C token: %s\n", token);
487 +#endif /* DEBUG */
488 +      win = tflag;
489        goto ret;
490      }
491 +#ifdef DEBUG
492 +  fprintf (stderr, "H\n");
493 +#endif /* DEBUG */
494    /* Detect GNUmacs's function-defining macros. */
495    if (!number && !strncmp (token, "DEF", 3))
496          
497 @@ -962,6 +1149,9 @@
498        next_token_is_func = 1;
499        goto badone;
500      }
501 +#ifdef DEBUG
502 +  fprintf (stderr, "I\n");
503 +#endif /* DEBUG */
504    if (next_token_is_func)
505      {
506        next_token_is_func = 0;
507 @@ -968,9 +1158,15 @@
508        win = 1;
509        goto ret;
510      }
511 +#ifdef DEBUG
512 +  fprintf (stderr, "J\n");
513 +#endif /* DEBUG */
514    if (c != '(')
515      goto badone;
516    firsttok = FALSE;
517 +#ifdef DEBUG
518 +  fprintf (stderr, "K\n");
519 +#endif /* DEBUG */
520    while ((c = *lp++) != ')')
521      {
522        if (c == 0)
523 @@ -999,9 +1195,20 @@
524         }
525      }
526    win = isgood (c);
527 +  
528  ret:
529 +#ifdef DEBUG
530 +  fprintf (stderr,
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);
534 +#endif /* DEBUG */
535    *lpp = lp - 1;
536    return !bad && win;
537 +
538 + badone:
539 +  bad = TRUE;
540 +  goto ret;
541  }
542  
543  getline (atchar)
544 ----------------------------------------------------------------------
545