Mercurial > hg > xemacs-beta
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 |