comparison lib-src/etags.c @ 134:34a5b81f86ba r20-2b1

Import from CVS: tag r20-2b1
author cvs
date Mon, 13 Aug 2007 09:30:11 +0200
parents b82b59fe008d
children 1856695b1fa9
comparison
equal deleted inserted replaced
133:b27e67717092 134:34a5b81f86ba
29 * Regexp tags by Tom Tromey. 29 * Regexp tags by Tom Tromey.
30 * 30 *
31 * Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer. 31 * Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer.
32 */ 32 */
33 33
34 char pot_etags_version[] = "@(#) pot revision number is 11.78"; 34 char pot_etags_version[] = "@(#) pot revision number is 11.83";
35 35
36 #define TRUE 1 36 #define TRUE 1
37 #define FALSE 0 37 #define FALSE 0
38 38
39 #ifndef DEBUG 39 #ifndef DEBUG
84 #ifdef ETAGS_REGEXPS 84 #ifdef ETAGS_REGEXPS
85 # include <regex.h> 85 # include <regex.h>
86 #endif /* ETAGS_REGEXPS */ 86 #endif /* ETAGS_REGEXPS */
87 87
88 /* Define CTAGS to make the program "ctags" compatible with the usual one. 88 /* Define CTAGS to make the program "ctags" compatible with the usual one.
89 Let it undefined to make the program "etags", which makes emacs-style 89 Leave it undefined to make the program "etags", which makes emacs-style
90 tag tables and tags typedefs, #defines and struct/union/enum by default. */ 90 tag tables and tags typedefs, #defines and struct/union/enum by default. */
91 #ifdef CTAGS 91 #ifdef CTAGS
92 # undef CTAGS 92 # undef CTAGS
93 # define CTAGS TRUE 93 # define CTAGS TRUE
94 #else 94 #else
107 /* C extensions. */ 107 /* C extensions. */
108 #define C_PLPL 0x00001 /* C++ */ 108 #define C_PLPL 0x00001 /* C++ */
109 #define C_STAR 0x00003 /* C* */ 109 #define C_STAR 0x00003 /* C* */
110 #define YACC 0x10000 /* yacc file */ 110 #define YACC 0x10000 /* yacc file */
111 111
112 #define streq(s,t) ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strcmp(s,t)) 112 #define streq(s,t) ((DEBUG && (s) == NULL && (t) == NULL \
113 #define strneq(s,t,n) ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strncmp(s,t,n)) 113 && (abort (), 1)) || !strcmp (s, t))
114 #define strneq(s,t,n) ((DEBUG && (s) == NULL && (t) == NULL \
115 && (abort (), 1)) || !strncmp (s, t, n))
114 116
115 #define lowcase(c) tolower ((char)c) 117 #define lowcase(c) tolower ((char)c)
116 118
117 #define iswhite(arg) (_wht[arg]) /* T if char is white */ 119 #define iswhite(arg) (_wht[arg]) /* T if char is white */
118 #define begtoken(arg) (_btk[arg]) /* T if char can start token */ 120 #define begtoken(arg) (_btk[arg]) /* T if char can start token */
566 at_language, 568 at_language,
567 at_regexp, 569 at_regexp,
568 at_filename 570 at_filename
569 }; 571 };
570 572
571 /* This structure helps us allow mixing of --lang and filenames. */ 573 /* This structure helps us allow mixing of --lang and file names. */
572 typedef struct 574 typedef struct
573 { 575 {
574 enum argument_type arg_type; 576 enum argument_type arg_type;
575 char *what; 577 char *what;
576 Lang_function *function; 578 Lang_function *function;
588 char body[MAX_FILE_SPEC_LEN + 1]; 590 char body[MAX_FILE_SPEC_LEN + 1];
589 } vspec; 591 } vspec;
590 592
591 /* 593 /*
592 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names 594 v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
593 returning in each successive call the next filename matching the input 595 returning in each successive call the next file name matching the input
594 spec. The function expects that each in_spec passed 596 spec. The function expects that each in_spec passed
595 to it will be processed to completion; in particular, up to and 597 to it will be processed to completion; in particular, up to and
596 including the call following that in which the last matching name 598 including the call following that in which the last matching name
597 is returned, the function ignores the value of in_spec, and will 599 is returned, the function ignores the value of in_spec, and will
598 only start processing a new spec with the following call. 600 only start processing a new spec with the following call.
599 If an error occurs, on return out_spec contains the value 601 If an error occurs, on return out_spec contains the value
600 of in_spec when the error occurred. 602 of in_spec when the error occurred.
601 603
602 With each successive filename returned in out_spec, the 604 With each successive file name returned in out_spec, the
603 function's return value is one. When there are no more matching 605 function's return value is one. When there are no more matching
604 names the function returns zero. If on the first call no file 606 names the function returns zero. If on the first call no file
605 matches in_spec, or there is any other error, -1 is returned. 607 matches in_spec, or there is any other error, -1 is returned.
606 */ 608 */
607 609
753 /* If getopt returns 0, then it has already processed a 755 /* If getopt returns 0, then it has already processed a
754 long-named option. We should do nothing. */ 756 long-named option. We should do nothing. */
755 break; 757 break;
756 758
757 case 1: 759 case 1:
758 /* This means that a filename has been seen. Record it. */ 760 /* This means that a file name has been seen. Record it. */
759 argbuffer[current_arg].arg_type = at_filename; 761 argbuffer[current_arg].arg_type = at_filename;
760 argbuffer[current_arg].what = optarg; 762 argbuffer[current_arg].what = optarg;
761 ++current_arg; 763 ++current_arg;
762 ++file_count; 764 ++file_count;
763 break; 765 break;
1104 { 1106 {
1105 char *filename; 1107 char *filename;
1106 1108
1107 if (absolutefn (file)) 1109 if (absolutefn (file))
1108 { 1110 {
1109 /* file is an absolute filename. Canonicalise it. */ 1111 /* file is an absolute file name. Canonicalise it. */
1110 filename = absolute_filename (file, cwd); 1112 filename = absolute_filename (file, cwd);
1111 } 1113 }
1112 else 1114 else
1113 { 1115 {
1114 /* file is a filename relative to cwd. Make it relative 1116 /* file is a file name relative to cwd. Make it relative
1115 to the directory of the tags file. */ 1117 to the directory of the tags file. */
1116 filename = relative_filename (file, tagfiledir); 1118 filename = relative_filename (file, tagfiledir);
1117 } 1119 }
1118 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head)); 1120 fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
1119 free (filename); 1121 free (filename);
2098 savetok.valid = FALSE; \ 2100 savetok.valid = FALSE; \
2099 } \ 2101 } \
2100 definedef = dnone; \ 2102 definedef = dnone; \
2101 } while (0) 2103 } while (0)
2102 2104
2103 /* This macro should never be called when tok.valid is FALSE, but 2105
2104 we must protect about both invalid input and internal errors. */ 2106 void
2105 #define make_C_tag(isfun) do \ 2107 make_C_tag (isfun, tokp)
2106 if (tok.valid) { \ 2108 logical isfun;
2107 char *name = NULL; \ 2109 TOKEN *tokp;
2108 if (CTAGS || tok.named) \ 2110 {
2109 name = savestr (token_name.buffer); \ 2111 char *name = NULL;
2110 pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \ 2112
2111 tok.valid = FALSE; \ 2113 /* This function should never be called when tok.valid is FALSE, but
2112 } /* else if (DEBUG) abort (); */ while (0) 2114 we must protect against invalid input or internal errors. */
2115 if (tokp->valid)
2116 {
2117 if (CTAGS || tokp->named)
2118 name = savestr (token_name.buffer);
2119 pfnote (name, isfun,
2120 tokp->buffer, tokp->linelen, tokp->lineno, tokp->linepos);
2121 tokp->valid = FALSE;
2122 }
2123 else if (DEBUG)
2124 abort ();
2125 }
2126
2113 2127
2114 void 2128 void
2115 C_entries (c_ext, inf) 2129 C_entries (c_ext, inf)
2116 int c_ext; /* extension of C */ 2130 int c_ext; /* extension of C */
2117 FILE *inf; /* input file */ 2131 FILE *inf; /* input file */
2368 { 2382 {
2369 if (current_lb_is_new) 2383 if (current_lb_is_new)
2370 switch_line_buffers (); 2384 switch_line_buffers ();
2371 } 2385 }
2372 else 2386 else
2373 make_C_tag (is_func); 2387 make_C_tag (is_func, &tok);
2374 } 2388 }
2375 midtoken = FALSE; 2389 midtoken = FALSE;
2376 } 2390 }
2377 } /* if (endtoken (c)) */ 2391 } /* if (endtoken (c)) */
2378 else if (intoken (c)) 2392 else if (intoken (c))
2390 { 2404 {
2391 case fstartlist: 2405 case fstartlist:
2392 funcdef = finlist; 2406 funcdef = finlist;
2393 continue; 2407 continue;
2394 case flistseen: 2408 case flistseen:
2395 make_C_tag (TRUE); 2409 make_C_tag (TRUE, &tok);
2396 funcdef = fignore; 2410 funcdef = fignore;
2397 break; 2411 break;
2398 case ftagseen: 2412 case ftagseen:
2399 funcdef = fnone; 2413 funcdef = fnone;
2400 break; 2414 break;
2425 break; 2439 break;
2426 switch (objdef) 2440 switch (objdef)
2427 { 2441 {
2428 case otagseen: 2442 case otagseen:
2429 objdef = oignore; 2443 objdef = oignore;
2430 make_C_tag (TRUE); 2444 make_C_tag (TRUE, &tok);
2431 break; 2445 break;
2432 case omethodtag: 2446 case omethodtag:
2433 case omethodparm: 2447 case omethodparm:
2434 objdef = omethodcolon; 2448 objdef = omethodcolon;
2435 methodlen += 1; 2449 methodlen += 1;
2443 switch (funcdef) 2457 switch (funcdef)
2444 { 2458 {
2445 case ftagseen: 2459 case ftagseen:
2446 if (yacc_rules) 2460 if (yacc_rules)
2447 { 2461 {
2448 make_C_tag (FALSE); 2462 make_C_tag (FALSE, &tok);
2449 funcdef = fignore; 2463 funcdef = fignore;
2450 } 2464 }
2451 break; 2465 break;
2452 case fstartlist: 2466 case fstartlist:
2453 funcdef = fnone; 2467 funcdef = fnone;
2459 break; 2473 break;
2460 if (cblev == 0) 2474 if (cblev == 0)
2461 switch (typdef) 2475 switch (typdef)
2462 { 2476 {
2463 case tend: 2477 case tend:
2464 make_C_tag (FALSE); 2478 make_C_tag (FALSE, &tok);
2465 /* FALLTHRU */ 2479 /* FALLTHRU */
2466 default: 2480 default:
2467 typdef = tnone; 2481 typdef = tnone;
2468 } 2482 }
2469 if (funcdef != fignore) 2483 if (funcdef != fignore)
2482 break; 2496 break;
2483 switch (objdef) 2497 switch (objdef)
2484 { 2498 {
2485 case omethodtag: 2499 case omethodtag:
2486 case omethodparm: 2500 case omethodparm:
2487 make_C_tag (TRUE); 2501 make_C_tag (TRUE, &tok);
2488 objdef = oinbody; 2502 objdef = oinbody;
2489 break; 2503 break;
2490 } 2504 }
2491 if (funcdef != finlist && funcdef != fignore) 2505 if (funcdef != finlist && funcdef != fignore)
2492 funcdef = fnone; 2506 funcdef = fnone;
2497 if (definedef != dnone) 2511 if (definedef != dnone)
2498 break; 2512 break;
2499 if (cblev == 0 && typdef == tend) 2513 if (cblev == 0 && typdef == tend)
2500 { 2514 {
2501 typdef = tignore; 2515 typdef = tignore;
2502 make_C_tag (FALSE); 2516 make_C_tag (FALSE, &tok);
2503 break; 2517 break;
2504 } 2518 }
2505 if (funcdef != finlist && funcdef != fignore) 2519 if (funcdef != finlist && funcdef != fignore)
2506 funcdef = fnone; 2520 funcdef = fnone;
2507 if (structdef == stagseen) 2521 if (structdef == stagseen)
2520 case ttypedseen: 2534 case ttypedseen:
2521 case tend: 2535 case tend:
2522 /* Make sure that the next char is not a '*'. 2536 /* Make sure that the next char is not a '*'.
2523 This handles constructs like: 2537 This handles constructs like:
2524 typedef void OperatorFun (int fun); */ 2538 typedef void OperatorFun (int fun); */
2525 if (*lp != '*') 2539 if (tok.valid && *lp != '*')
2526 { 2540 {
2527 typdef = tignore; 2541 typdef = tignore;
2528 make_C_tag (FALSE); 2542 make_C_tag (FALSE, &tok);
2529 } 2543 }
2530 break; 2544 break;
2531 } /* switch (typdef) */ 2545 } /* switch (typdef) */
2532 break; 2546 break;
2533 case ftagseen: 2547 case ftagseen:
2542 case ')': 2556 case ')':
2543 if (definedef != dnone) 2557 if (definedef != dnone)
2544 break; 2558 break;
2545 if (objdef == ocatseen && parlev == 1) 2559 if (objdef == ocatseen && parlev == 1)
2546 { 2560 {
2547 make_C_tag (TRUE); 2561 make_C_tag (TRUE, &tok);
2548 objdef = oignore; 2562 objdef = oignore;
2549 } 2563 }
2550 if (--parlev == 0) 2564 if (--parlev == 0)
2551 { 2565 {
2552 switch (funcdef) 2566 switch (funcdef)
2557 break; 2571 break;
2558 } 2572 }
2559 if (cblev == 0 && typdef == tend) 2573 if (cblev == 0 && typdef == tend)
2560 { 2574 {
2561 typdef = tignore; 2575 typdef = tignore;
2562 make_C_tag (FALSE); 2576 make_C_tag (FALSE, &tok);
2563 } 2577 }
2564 } 2578 }
2565 else if (parlev < 0) /* can happen due to ill-conceived #if's. */ 2579 else if (parlev < 0) /* can happen due to ill-conceived #if's. */
2566 parlev = 0; 2580 parlev = 0;
2567 break; 2581 break;
2577 structtag = "_anonymous_"; 2591 structtag = "_anonymous_";
2578 break; 2592 break;
2579 case stagseen: 2593 case stagseen:
2580 case scolonseen: /* named struct */ 2594 case scolonseen: /* named struct */
2581 structdef = sinbody; 2595 structdef = sinbody;
2582 make_C_tag (FALSE); 2596 make_C_tag (FALSE, &tok);
2583 break; 2597 break;
2584 } 2598 }
2585 switch (funcdef) 2599 switch (funcdef)
2586 { 2600 {
2587 case flistseen: 2601 case flistseen:
2588 make_C_tag (TRUE); 2602 make_C_tag (TRUE, &tok);
2589 /* FALLTHRU */ 2603 /* FALLTHRU */
2590 case fignore: 2604 case fignore:
2591 funcdef = fnone; 2605 funcdef = fnone;
2592 break; 2606 break;
2593 case fnone: 2607 case fnone:
2594 switch (objdef) 2608 switch (objdef)
2595 { 2609 {
2596 case otagseen: 2610 case otagseen:
2597 make_C_tag (TRUE); 2611 make_C_tag (TRUE, &tok);
2598 objdef = oignore; 2612 objdef = oignore;
2599 break; 2613 break;
2600 case omethodtag: 2614 case omethodtag:
2601 case omethodparm: 2615 case omethodparm:
2602 make_C_tag (TRUE); 2616 make_C_tag (TRUE, &tok);
2603 objdef = oinbody; 2617 objdef = oinbody;
2604 break; 2618 break;
2605 default: 2619 default:
2606 /* Neutralize `extern "C" {' grot. */ 2620 /* Neutralize `extern "C" {' grot. */
2607 if (cblev == 0 && structdef == snone && typdef == tnone) 2621 if (cblev == 0 && structdef == snone && typdef == tnone)
2659 funcdef = fnone; 2673 funcdef = fnone;
2660 break; 2674 break;
2661 case '\0': 2675 case '\0':
2662 if (objdef == otagseen) 2676 if (objdef == otagseen)
2663 { 2677 {
2664 make_C_tag (TRUE); 2678 make_C_tag (TRUE, &tok);
2665 objdef = oignore; 2679 objdef = oignore;
2666 } 2680 }
2667 /* If a macro spans multiple lines don't reset its state. */ 2681 /* If a macro spans multiple lines don't reset its state. */
2668 if (quotednl) 2682 if (quotednl)
2669 CNL_SAVE_DEFINEDEF; 2683 CNL_SAVE_DEFINEDEF;
3540 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */ 3554 else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
3541 prolog_skip_comment (&lb, inf); 3555 prolog_skip_comment (&lb, inf);
3542 else if (len = prolog_pred (dbp, last)) 3556 else if (len = prolog_pred (dbp, last))
3543 { 3557 {
3544 /* Predicate. Store the function name so that we only 3558 /* Predicate. Store the function name so that we only
3545 * generates a tag for the first clause. */ 3559 generate a tag for the first clause. */
3546 if (last == NULL) 3560 if (last == NULL)
3547 last = xnew(len + 1, char); 3561 last = xnew(len + 1, char);
3548 else if (len + 1 > allocated) 3562 else if (len + 1 > allocated)
3549 last = (char *) xrealloc(last, len + 1); 3563 last = (char *) xrealloc(last, len + 1);
3550 allocated = len + 1; 3564 allocated = len + 1;
4397 return path.buffer; 4411 return path.buffer;
4398 #endif /* not MSDOS */ 4412 #endif /* not MSDOS */
4399 #endif /* not HAVE_GETCWD */ 4413 #endif /* not HAVE_GETCWD */
4400 } 4414 }
4401 4415
4402 /* Return a newly allocated string containing the filename 4416 /* Return a newly allocated string containing the file name
4403 of FILE relative to the absolute directory DIR (which 4417 of FILE relative to the absolute directory DIR (which
4404 should end with a slash). */ 4418 should end with a slash). */
4405 char * 4419 char *
4406 relative_filename (file, dir) 4420 relative_filename (file, dir)
4407 char *file, *dir; 4421 char *file, *dir;
4408 { 4422 {
4409 char *fp, *dp, *abs, *res; 4423 char *fp, *dp, *abs, *res;
4424 int i;
4410 4425
4411 /* Find the common root of file and dir (with a trailing slash). */ 4426 /* Find the common root of file and dir (with a trailing slash). */
4412 abs = absolute_filename (file, cwd); 4427 abs = absolute_filename (file, cwd);
4413 fp = abs; 4428 fp = abs;
4414 dp = dir; 4429 dp = dir;
4415 while (*fp++ == *dp++) 4430 while (*fp++ == *dp++)
4416 continue; 4431 continue;
4417 fp--, dp--; /* back to the first differing char */ 4432 fp--, dp--; /* back to the first differing char */
4418 do /* look at the equal chars until / */ 4433 do /* look at the equal chars until '/' */
4419 fp--, dp--; 4434 fp--, dp--;
4420 while (*fp != '/'); 4435 while (*fp != '/');
4421 4436
4422 /* Build a sequence of "../" strings for the resulting relative filename. */ 4437 /* Build a sequence of "../" strings for the resulting relative file name. */
4423 for (dp = etags_strchr (dp + 1, '/'), res = ""; 4438 i = 0;
4424 dp != NULL; 4439 while ((dp = etags_strchr (dp + 1, '/')) != NULL)
4425 dp = etags_strchr (dp + 1, '/')) 4440 i += 1;
4426 { 4441 res = xnew (3*i + strlen (fp + 1) + 1, char);
4427 res = concat (res, "../", ""); 4442 res[0] = '\0';
4428 } 4443 while (i-- > 0)
4429 4444 strcat (res, "../");
4430 /* Add the filename relative to the common root of file and dir. */ 4445
4431 res = concat (res, fp + 1, ""); 4446 /* Add the file name relative to the common root of file and dir. */
4447 strcat (res, fp + 1);
4432 free (abs); 4448 free (abs);
4433 4449
4434 return res; 4450 return res;
4435 } 4451 }
4436 4452
4437 /* Return a newly allocated string containing the 4453 /* Return a newly allocated string containing the
4438 absolute filename of FILE given CWD (which should 4454 absolute file name of FILE given CWD (which should
4439 end with a slash). */ 4455 end with a slash). */
4440 char * 4456 char *
4441 absolute_filename (file, cwd) 4457 absolute_filename (file, cwd)
4442 char *file, *cwd; 4458 char *file, *cwd;
4443 { 4459 {
4444 char *slashp, *cp, *res; 4460 char *slashp, *cp, *res;
4445 4461
4446 if (absolutefn (file)) 4462 if (absolutefn (file))
4447 res = concat (file, "", ""); 4463 res = savestr (file);
4448 #ifdef DOS_NT 4464 #ifdef DOS_NT
4449 /* We don't support non-absolute filenames with a drive 4465 /* We don't support non-absolute file names with a drive
4450 letter, like `d:NAME' (it's too much hassle). */ 4466 letter, like `d:NAME' (it's too much hassle). */
4451 else if (file[1] == ':') 4467 else if (file[1] == ':')
4452 fatal ("%s: relative filenames with drive letters not supported", file); 4468 fatal ("%s: relative file names with drive letters not supported", file);
4453 #endif 4469 #endif
4454 else 4470 else
4455 res = concat (cwd, file, ""); 4471 res = concat (cwd, file, "");
4456 4472
4457 /* Delete the "/dirname/.." and "/." substrings. */ 4473 /* Delete the "/dirname/.." and "/." substrings. */
4465 { 4481 {
4466 cp = slashp; 4482 cp = slashp;
4467 do 4483 do
4468 cp--; 4484 cp--;
4469 while (cp >= res && !absolutefn (cp)); 4485 while (cp >= res && !absolutefn (cp));
4470 if (*cp == '/') 4486 if (cp < res)
4471 { 4487 cp = slashp; /* the absolute name begins with "/.." */
4472 strcpy (cp, slashp + 3);
4473 }
4474 #ifdef DOS_NT 4488 #ifdef DOS_NT
4475 /* Under MSDOS and NT we get `d:/NAME' as absolute 4489 /* Under MSDOS and NT we get `d:/NAME' as absolute
4476 filename, so the luser could say `d:/../NAME'. 4490 file name, so the luser could say `d:/../NAME'.
4477 We silently treat this as `d:/NAME'. */ 4491 We silently treat this as `d:/NAME'. */
4478 else if (cp[1] == ':') 4492 else if (cp[0] != '/')
4479 strcpy (cp + 3, slashp + 4); 4493 cp = slashp;
4480 #endif 4494 #endif
4481 else /* else (cp == res) */ 4495 strcpy (cp, slashp + 3);
4482 {
4483 if (slashp[3] != '\0')
4484 strcpy (cp, slashp + 4);
4485 else
4486 return ".";
4487 }
4488 slashp = cp; 4496 slashp = cp;
4489 continue; 4497 continue;
4490 } 4498 }
4491 else if (slashp[2] == '/' || slashp[2] == '\0') 4499 else if (slashp[2] == '/' || slashp[2] == '\0')
4492 { 4500 {
4495 } 4503 }
4496 } 4504 }
4497 4505
4498 slashp = etags_strchr (slashp + 1, '/'); 4506 slashp = etags_strchr (slashp + 1, '/');
4499 } 4507 }
4500 4508
4501 return res; 4509 if (res[0] == '\0')
4510 return savestr ("/");
4511 else
4512 return res;
4502 } 4513 }
4503 4514
4504 /* Return a newly allocated string containing the absolute 4515 /* Return a newly allocated string containing the absolute
4505 filename of dir where FILE resides given CWD (which should 4516 file name of dir where FILE resides given CWD (which should
4506 end with a slash). */ 4517 end with a slash). */
4507 char * 4518 char *
4508 absolute_dirname (file, cwd) 4519 absolute_dirname (file, cwd)
4509 char *file, *cwd; 4520 char *file, *cwd;
4510 { 4521 {
4518 *p = '/'; 4529 *p = '/';
4519 #endif 4530 #endif
4520 4531
4521 slashp = etags_strrchr (file, '/'); 4532 slashp = etags_strrchr (file, '/');
4522 if (slashp == NULL) 4533 if (slashp == NULL)
4523 return cwd; 4534 return savestr (cwd);
4524 save = slashp[1]; 4535 save = slashp[1];
4525 slashp[1] = '\0'; 4536 slashp[1] = '\0';
4526 res = absolute_filename (file, cwd); 4537 res = absolute_filename (file, cwd);
4527 slashp[1] = save; 4538 slashp[1] = save;
4528 4539