diff options
| author | Francesco Potortì | 1994-03-23 18:27:19 +0000 |
|---|---|---|
| committer | Francesco Potortì | 1994-03-23 18:27:19 +0000 |
| commit | 46c145db6c5561a7fd6871108d9ca239dc88a3f9 (patch) | |
| tree | ad41feb6c393968b5ab3c016e9311794b1717536 /lib-src | |
| parent | 6af6cbb5306f58a93da8e141d0dfe0a0d6cd454d (diff) | |
| download | emacs-46c145db6c5561a7fd6871108d9ca239dc88a3f9.tar.gz emacs-46c145db6c5561a7fd6871108d9ca239dc88a3f9.zip | |
* etags.c (cwd, outfiledir): vars added.
(relative_filename, absolute_filename, absolute_dirname):
functions added to compute filenames in tags files.
(process_file): filenames in tags file are relative to the
directory where the tags file is (useful with the -o option).
(main): initialise the outfiledir var.
(TYPEDST): added the `tignore' value.
(C_entries): corrected various small bugs.
Diffstat (limited to 'lib-src')
| -rw-r--r-- | lib-src/etags.c | 257 |
1 files changed, 212 insertions, 45 deletions
diff --git a/lib-src/etags.c b/lib-src/etags.c index f65336f3c45..461d9dc6042 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c | |||
| @@ -25,9 +25,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 25 | * Gnu Emacs TAGS format and modifications by RMS? | 25 | * Gnu Emacs TAGS format and modifications by RMS? |
| 26 | * Sam Kendall added C++. | 26 | * Sam Kendall added C++. |
| 27 | * | 27 | * |
| 28 | * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. 10.7 | 28 | * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. |
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | char etags_version[] = "@(#) pot revision number is 10.15"; | ||
| 32 | |||
| 31 | #ifdef MSDOS | 33 | #ifdef MSDOS |
| 32 | #include <fcntl.h> | 34 | #include <fcntl.h> |
| 33 | #endif /* MSDOS */ | 35 | #endif /* MSDOS */ |
| @@ -48,9 +50,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 48 | #include "getopt.h" | 50 | #include "getopt.h" |
| 49 | 51 | ||
| 50 | extern char *getenv (); | 52 | extern char *getenv (); |
| 53 | extern char *getcwd (); | ||
| 51 | 54 | ||
| 52 | char *etags_index (), *etags_rindex (); | ||
| 53 | char *savenstr (); | ||
| 54 | 55 | ||
| 55 | /* Define the symbol ETAGS to make the program "etags", | 56 | /* Define the symbol ETAGS to make the program "etags", |
| 56 | which makes emacs-style tag tables by default. | 57 | which makes emacs-style tag tables by default. |
| @@ -151,19 +152,20 @@ struct nd_st | |||
| 151 | struct nd_st *left, *right; /* left and right sons */ | 152 | struct nd_st *left, *right; /* left and right sons */ |
| 152 | }; | 153 | }; |
| 153 | 154 | ||
| 154 | long ftell (); | ||
| 155 | typedef struct nd_st NODE; | 155 | typedef struct nd_st NODE; |
| 156 | 156 | ||
| 157 | logical header_file; /* TRUE if .h file, FALSE o.w. */ | 157 | logical header_file; /* TRUE if .h file, FALSE o.w. */ |
| 158 | /* boolean "functions" (see init) */ | 158 | /* boolean "functions" (see init) */ |
| 159 | logical _wht[0177], _etk[0177], _itk[0177], _btk[0177]; | 159 | logical _wht[0177], _etk[0177], _itk[0177], _btk[0177]; |
| 160 | 160 | ||
| 161 | char cwd [BUFSIZ]; /* current working directory */ | ||
| 162 | char *outfiledir; /* directory of tagfile */ | ||
| 161 | 163 | ||
| 162 | char *concat (); | 164 | char *concat (); |
| 163 | char *savenstr (); | 165 | char *savenstr (), *savestr (); |
| 164 | char *savestr (); | 166 | char *etags_index (), *etags_rindex (); |
| 165 | char *xmalloc (); | 167 | char *relative_filename (), *absolute_filename (), *absolute_dirname (); |
| 166 | char *xrealloc (); | 168 | char *xmalloc (), *xrealloc (); |
| 167 | int L_isdef (), L_isquote (); | 169 | int L_isdef (), L_isquote (); |
| 168 | int PF_funcs (); | 170 | int PF_funcs (); |
| 169 | int total_size_of_entries (); | 171 | int total_size_of_entries (); |
| @@ -241,7 +243,7 @@ char *curfile, /* current input file name */ | |||
| 241 | *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */ | 243 | *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */ |
| 242 | /* token starting chars */ | 244 | /* token starting chars */ |
| 243 | *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~", | 245 | *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~", |
| 244 | /* valid in-token chars */ | 246 | /* valid in-token chars */ |
| 245 | *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789"; | 247 | *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789"; |
| 246 | 248 | ||
| 247 | int append_to_tagfile; /* -a: append to tags */ | 249 | int append_to_tagfile; /* -a: append to tags */ |
| @@ -442,7 +444,7 @@ main (argc, argv) | |||
| 442 | extern char *gfnames (); | 444 | extern char *gfnames (); |
| 443 | extern char *massage_name (); | 445 | extern char *massage_name (); |
| 444 | #endif | 446 | #endif |
| 445 | 447 | ||
| 446 | #ifdef MSDOS | 448 | #ifdef MSDOS |
| 447 | _fmode = O_BINARY; /* all of files are treated as binary files */ | 449 | _fmode = O_BINARY; /* all of files are treated as binary files */ |
| 448 | #endif /* MSDOS */ | 450 | #endif /* MSDOS */ |
| @@ -465,7 +467,7 @@ main (argc, argv) | |||
| 465 | for (;;) | 467 | for (;;) |
| 466 | { | 468 | { |
| 467 | int opt; | 469 | int opt; |
| 468 | opt = getopt_long (argc, argv, "aACdDo:f:StTi:BFuvxwVH", longopts, 0); | 470 | opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0); |
| 469 | 471 | ||
| 470 | if (opt == EOF) | 472 | if (opt == EOF) |
| 471 | break; | 473 | break; |
| @@ -569,10 +571,20 @@ main (argc, argv) | |||
| 569 | exit (BAD); | 571 | exit (BAD); |
| 570 | } | 572 | } |
| 571 | 573 | ||
| 572 | if (outfile == 0) | 574 | if (outfile == NULL) |
| 573 | { | 575 | { |
| 574 | outfile = emacs_tags_format ? "TAGS" : "tags"; | 576 | outfile = emacs_tags_format ? "TAGS" : "tags"; |
| 575 | } | 577 | } |
| 578 | getcwd (cwd, BUFSIZ); /* the current working directory */ | ||
| 579 | strcat (cwd, "/"); | ||
| 580 | if (streq (outfile, "-")) | ||
| 581 | { | ||
| 582 | outfiledir = cwd; | ||
| 583 | } | ||
| 584 | else | ||
| 585 | { | ||
| 586 | outfiledir = absolute_dirname (outfile, cwd); | ||
| 587 | } | ||
| 576 | 588 | ||
| 577 | init (); /* set up boolean "functions" */ | 589 | init (); /* set up boolean "functions" */ |
| 578 | 590 | ||
| @@ -619,18 +631,18 @@ main (argc, argv) | |||
| 619 | this_file = argv[optind]; | 631 | this_file = argv[optind]; |
| 620 | #endif | 632 | #endif |
| 621 | /* Input file named "-" means read file names from stdin and use them. */ | 633 | /* Input file named "-" means read file names from stdin and use them. */ |
| 622 | if (streq (this_file, "-")) | 634 | if (streq (this_file, "-")) |
| 635 | { | ||
| 636 | while (!feof (stdin)) | ||
| 623 | { | 637 | { |
| 624 | while (!feof (stdin)) | 638 | (void) readline (&filename_lb, stdin); |
| 625 | { | 639 | if (strlen (filename_lb.buffer) > 0) |
| 626 | (void) readline (&filename_lb, stdin); | 640 | process_file (filename_lb.buffer); |
| 627 | if (strlen (filename_lb.buffer) > 0) | ||
| 628 | process_file (filename_lb.buffer); | ||
| 629 | } | ||
| 630 | } | 641 | } |
| 631 | else | ||
| 632 | process_file (this_file); | ||
| 633 | } | 642 | } |
| 643 | else | ||
| 644 | process_file (this_file); | ||
| 645 | } | ||
| 634 | 646 | ||
| 635 | if (emacs_tags_format) | 647 | if (emacs_tags_format) |
| 636 | { | 648 | { |
| @@ -701,7 +713,20 @@ process_file (file) | |||
| 701 | } | 713 | } |
| 702 | if (emacs_tags_format) | 714 | if (emacs_tags_format) |
| 703 | { | 715 | { |
| 704 | fprintf (outf, "\f\n%s,%d\n", file, total_size_of_entries (head)); | 716 | char *filename; |
| 717 | |||
| 718 | if (file[0] == '/') | ||
| 719 | { | ||
| 720 | /* file is an absolute filename. Canonicalise it. */ | ||
| 721 | filename = absolute_filename (file, cwd); | ||
| 722 | } | ||
| 723 | else | ||
| 724 | { | ||
| 725 | /* file is a filename relative to cwd. Make it relative | ||
| 726 | to the directory of the tags file. */ | ||
| 727 | filename = relative_filename (file, outfiledir); | ||
| 728 | } | ||
| 729 | fprintf (outf, "\f\n%s,%d\n", filename, total_size_of_entries (head)); | ||
| 705 | put_entries (head); | 730 | put_entries (head); |
| 706 | free_tree (head); | 731 | free_tree (head); |
| 707 | head = NULL; | 732 | head = NULL; |
| @@ -1318,7 +1343,8 @@ typedef enum | |||
| 1318 | FUNCST funcdef; | 1343 | FUNCST funcdef; |
| 1319 | 1344 | ||
| 1320 | 1345 | ||
| 1321 | /* typedefs are recognized using a simple finite automaton. | 1346 | /* |
| 1347 | * typedefs are recognized using a simple finite automaton. | ||
| 1322 | * typeddef is its state variable. | 1348 | * typeddef is its state variable. |
| 1323 | */ | 1349 | */ |
| 1324 | typedef enum | 1350 | typedef enum |
| @@ -1326,16 +1352,16 @@ typedef enum | |||
| 1326 | tnone, /* nothing seen */ | 1352 | tnone, /* nothing seen */ |
| 1327 | ttypedseen, /* typedef keyword seen */ | 1353 | ttypedseen, /* typedef keyword seen */ |
| 1328 | tinbody, /* inside typedef body */ | 1354 | tinbody, /* inside typedef body */ |
| 1329 | tend /* just before typedef tag */ | 1355 | tend, /* just before typedef tag */ |
| 1356 | tignore /* junk after typedef tag */ | ||
| 1330 | } TYPEDST; | 1357 | } TYPEDST; |
| 1331 | TYPEDST typdef; | 1358 | TYPEDST typdef; |
| 1332 | 1359 | ||
| 1333 | 1360 | ||
| 1334 | /* struct tags for C++ are recognized using another simple | 1361 | /* |
| 1335 | * finite automaton. `structdef' is its state variable. | 1362 | * struct-like structures (enum, struct and union) are recognized |
| 1336 | * This machinery is only invoked for C++; otherwise structdef | 1363 | * using another simple finite automaton. `structdef' is its state |
| 1337 | * should remain snone. However, this machinery can easily be | 1364 | * variable. |
| 1338 | * adapted to find structure tags in normal C code. | ||
| 1339 | */ | 1365 | */ |
| 1340 | typedef enum | 1366 | typedef enum |
| 1341 | { | 1367 | { |
| @@ -1346,6 +1372,7 @@ typedef enum | |||
| 1346 | sinbody /* in struct body: recognize member func defs*/ | 1372 | sinbody /* in struct body: recognize member func defs*/ |
| 1347 | } STRUCTST; | 1373 | } STRUCTST; |
| 1348 | STRUCTST structdef; | 1374 | STRUCTST structdef; |
| 1375 | |||
| 1349 | /* | 1376 | /* |
| 1350 | * When structdef is stagseen, scolonseen, or sinbody, structtag is the | 1377 | * When structdef is stagseen, scolonseen, or sinbody, structtag is the |
| 1351 | * struct tag, and structtype is the type of the preceding struct-like | 1378 | * struct tag, and structtype is the type of the preceding struct-like |
| @@ -1448,7 +1475,7 @@ C_entries (c_ext) | |||
| 1448 | lp = curlb.buffer; | 1475 | lp = curlb.buffer; |
| 1449 | *lp = 0; | 1476 | *lp = 0; |
| 1450 | 1477 | ||
| 1451 | definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone; | 1478 | definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone; |
| 1452 | next_token_is_func = yacc_rules = FALSE; | 1479 | next_token_is_func = yacc_rules = FALSE; |
| 1453 | midtoken = inquote = inchar = incomm = quotednl = FALSE; | 1480 | midtoken = inquote = inchar = incomm = quotednl = FALSE; |
| 1454 | cblev = 0; | 1481 | cblev = 0; |
| @@ -1515,7 +1542,7 @@ C_entries (c_ext) | |||
| 1515 | CNL; | 1542 | CNL; |
| 1516 | /* FALLTHRU */ | 1543 | /* FALLTHRU */ |
| 1517 | case '\'': | 1544 | case '\'': |
| 1518 | inchar = FALSE; | 1545 | inchar = FALSE; |
| 1519 | break; | 1546 | break; |
| 1520 | } | 1547 | } |
| 1521 | continue; | 1548 | continue; |
| @@ -1553,7 +1580,7 @@ C_entries (c_ext) | |||
| 1553 | /* entering or exiting rules section in yacc file */ | 1580 | /* entering or exiting rules section in yacc file */ |
| 1554 | lp++; | 1581 | lp++; |
| 1555 | definedef = dnone; funcdef = fnone; | 1582 | definedef = dnone; funcdef = fnone; |
| 1556 | typdef= tnone; structdef= snone; | 1583 | typdef = tnone; structdef = snone; |
| 1557 | next_token_is_func = FALSE; | 1584 | next_token_is_func = FALSE; |
| 1558 | midtoken = inquote = inchar = incomm = quotednl = FALSE; | 1585 | midtoken = inquote = inchar = incomm = quotednl = FALSE; |
| 1559 | cblev = 0; | 1586 | cblev = 0; |
| @@ -1572,9 +1599,10 @@ C_entries (c_ext) | |||
| 1572 | /* Consider token only if some complicated conditions are satisfied. */ | 1599 | /* Consider token only if some complicated conditions are satisfied. */ |
| 1573 | if (((cblev == 0 && structdef != scolonseen) | 1600 | if (((cblev == 0 && structdef != scolonseen) |
| 1574 | || (cblev == 1 && cplpl && structdef == sinbody)) | 1601 | || (cblev == 1 && cplpl && structdef == sinbody)) |
| 1602 | && typdef != tignore | ||
| 1575 | && definedef != dignorerest | 1603 | && definedef != dignorerest |
| 1576 | && (funcdef != finlist | 1604 | && (funcdef != finlist |
| 1577 | || (definedef != dnone && definedef != dignorerest))) | 1605 | || definedef != dnone)) |
| 1578 | { | 1606 | { |
| 1579 | if (midtoken) | 1607 | if (midtoken) |
| 1580 | { | 1608 | { |
| @@ -1714,19 +1742,37 @@ C_entries (c_ext) | |||
| 1714 | case ';': | 1742 | case ';': |
| 1715 | if (definedef != dnone) | 1743 | if (definedef != dnone) |
| 1716 | break; | 1744 | break; |
| 1717 | if (cblev == 0 && typdef == tend) | 1745 | if (cblev == 0) |
| 1718 | { | 1746 | switch (typdef) |
| 1719 | typdef = tnone; | 1747 | { |
| 1720 | MAKE_TAG_FROM_OTH_LB (FALSE); | 1748 | case tend: |
| 1721 | } | 1749 | MAKE_TAG_FROM_OTH_LB (FALSE); |
| 1750 | /* FALLTHRU */ | ||
| 1751 | default: | ||
| 1752 | typdef = tnone; | ||
| 1753 | } | ||
| 1722 | if (funcdef != fignore) | 1754 | if (funcdef != fignore) |
| 1723 | funcdef = fnone; | 1755 | funcdef = fnone; |
| 1724 | /* FALLTHRU */ | 1756 | if (structdef == stagseen) |
| 1757 | structdef = snone; | ||
| 1758 | break; | ||
| 1725 | case ',': | 1759 | case ',': |
| 1726 | /* FALLTHRU */ | 1760 | if (definedef != dnone) |
| 1761 | break; | ||
| 1762 | if (funcdef != finlist && funcdef != fignore) | ||
| 1763 | funcdef = fnone; | ||
| 1764 | if (structdef == stagseen) | ||
| 1765 | structdef = snone; | ||
| 1766 | break; | ||
| 1727 | case '[': | 1767 | case '[': |
| 1728 | if (definedef != dnone) | 1768 | if (definedef != dnone) |
| 1729 | break; | 1769 | break; |
| 1770 | if (cblev == 0 && typdef == tend) | ||
| 1771 | { | ||
| 1772 | typdef = tignore; | ||
| 1773 | MAKE_TAG_FROM_OTH_LB (FALSE); | ||
| 1774 | break; | ||
| 1775 | } | ||
| 1730 | if (funcdef != finlist && funcdef != fignore) | 1776 | if (funcdef != finlist && funcdef != fignore) |
| 1731 | funcdef = fnone; | 1777 | funcdef = fnone; |
| 1732 | if (structdef == stagseen) | 1778 | if (structdef == stagseen) |
| @@ -1758,6 +1804,11 @@ C_entries (c_ext) | |||
| 1758 | funcdef = flistseen; | 1804 | funcdef = flistseen; |
| 1759 | break; | 1805 | break; |
| 1760 | } | 1806 | } |
| 1807 | if (cblev == 0 && typdef == tend) | ||
| 1808 | { | ||
| 1809 | typdef = tignore; | ||
| 1810 | MAKE_TAG_FROM_OTH_LB (FALSE); | ||
| 1811 | } | ||
| 1761 | } | 1812 | } |
| 1762 | else if (parlev < 0) /* can happen due to ill-conceived #if's. */ | 1813 | else if (parlev < 0) /* can happen due to ill-conceived #if's. */ |
| 1763 | parlev = 0; | 1814 | parlev = 0; |
| @@ -1786,6 +1837,11 @@ C_entries (c_ext) | |||
| 1786 | /* FALLTHRU */ | 1837 | /* FALLTHRU */ |
| 1787 | case fignore: | 1838 | case fignore: |
| 1788 | funcdef = fnone; | 1839 | funcdef = fnone; |
| 1840 | break; | ||
| 1841 | case fnone: | ||
| 1842 | /* Neutralize `extern "C" {' grot. | ||
| 1843 | if (cblev == 0 && structdef == snone && typdef == tnone) | ||
| 1844 | cblev--; */; | ||
| 1789 | } | 1845 | } |
| 1790 | cblev++; | 1846 | cblev++; |
| 1791 | break; | 1847 | break; |
| @@ -1910,6 +1966,7 @@ consider_token (c, tokp, c_ext, cblev, is_func) | |||
| 1910 | { | 1966 | { |
| 1911 | if (typedefs) | 1967 | if (typedefs) |
| 1912 | typdef = ttypedseen; | 1968 | typdef = ttypedseen; |
| 1969 | funcdef = fnone; | ||
| 1913 | return (FALSE); | 1970 | return (FALSE); |
| 1914 | } | 1971 | } |
| 1915 | break; | 1972 | break; |
| @@ -2015,7 +2072,8 @@ consider_token (c, tokp, c_ext, cblev, is_func) | |||
| 2015 | switch (toktype) | 2072 | switch (toktype) |
| 2016 | { | 2073 | { |
| 2017 | case st_C_typespec: | 2074 | case st_C_typespec: |
| 2018 | funcdef = fnone; /* should be useless */ | 2075 | if (funcdef != finlist && funcdef != fignore) |
| 2076 | funcdef = fnone; /* should be useless */ | ||
| 2019 | return (FALSE); | 2077 | return (FALSE); |
| 2020 | default: | 2078 | default: |
| 2021 | if (funcdef == fnone) | 2079 | if (funcdef == fnone) |
| @@ -2176,7 +2234,7 @@ getit (fi) | |||
| 2176 | dbp++; | 2234 | dbp++; |
| 2177 | } | 2235 | } |
| 2178 | if (!isalpha (*dbp) | 2236 | if (!isalpha (*dbp) |
| 2179 | && *dbp != '_' | 2237 | && *dbp != '_' |
| 2180 | && *dbp != '$') | 2238 | && *dbp != '$') |
| 2181 | return; | 2239 | return; |
| 2182 | for (cp = dbp + 1; | 2240 | for (cp = dbp + 1; |
| @@ -2364,7 +2422,7 @@ PAS_funcs (fi) | |||
| 2364 | verify_tag = FALSE; | 2422 | verify_tag = FALSE; |
| 2365 | } | 2423 | } |
| 2366 | } | 2424 | } |
| 2367 | if ((found_tag) && (verify_tag)) /* not external proc, so make tag */ | 2425 | if ((found_tag) && (verify_tag)) /* not external proc, so make tag */ |
| 2368 | { | 2426 | { |
| 2369 | found_tag = FALSE; | 2427 | found_tag = FALSE; |
| 2370 | verify_tag = FALSE; | 2428 | verify_tag = FALSE; |
| @@ -3073,7 +3131,8 @@ error (s1, s2) | |||
| 3073 | fprintf (stderr, "\n"); | 3131 | fprintf (stderr, "\n"); |
| 3074 | } | 3132 | } |
| 3075 | 3133 | ||
| 3076 | /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ | 3134 | /* Return a newly-allocated string whose contents |
| 3135 | concatenate those of s1, s2, s3. */ | ||
| 3077 | 3136 | ||
| 3078 | char * | 3137 | char * |
| 3079 | concat (s1, s2, s3) | 3138 | concat (s1, s2, s3) |
| @@ -3085,11 +3144,119 @@ concat (s1, s2, s3) | |||
| 3085 | strcpy (result, s1); | 3144 | strcpy (result, s1); |
| 3086 | strcpy (result + len1, s2); | 3145 | strcpy (result + len1, s2); |
| 3087 | strcpy (result + len1 + len2, s3); | 3146 | strcpy (result + len1 + len2, s3); |
| 3088 | *(result + len1 + len2 + len3) = 0; | 3147 | result[len1 + len2 + len3] = '\0'; |
| 3089 | 3148 | ||
| 3090 | return result; | 3149 | return result; |
| 3091 | } | 3150 | } |
| 3092 | 3151 | ||
| 3152 | /* Return a newly allocated string containing the filename of FILE relative | ||
| 3153 | to the absolute directory DIR (which should end with a slash). */ | ||
| 3154 | |||
| 3155 | char * | ||
| 3156 | relative_filename (file, dir) | ||
| 3157 | char *file, *dir; | ||
| 3158 | { | ||
| 3159 | char *fp, *dp, *res; | ||
| 3160 | |||
| 3161 | /* Find the common root of file and dir. */ | ||
| 3162 | fp = absolute_filename (file, cwd); | ||
| 3163 | dp = dir; | ||
| 3164 | while (*fp++ == *dp++) | ||
| 3165 | continue; | ||
| 3166 | do | ||
| 3167 | { | ||
| 3168 | fp--; | ||
| 3169 | dp--; | ||
| 3170 | } | ||
| 3171 | while (*fp != '/'); | ||
| 3172 | |||
| 3173 | /* Build a sequence of "../" strings for the resulting relative filename. */ | ||
| 3174 | for (dp = etags_index (dp + 1, '/'), res = ""; | ||
| 3175 | dp != NULL; | ||
| 3176 | dp = etags_index (dp + 1, '/')) | ||
| 3177 | { | ||
| 3178 | res = concat (res, "../", ""); | ||
| 3179 | } | ||
| 3180 | |||
| 3181 | /* Add the filename relative to the common root of file and dir. */ | ||
| 3182 | res = concat (res, fp + 1, ""); | ||
| 3183 | |||
| 3184 | return res; /* temporary stub */ | ||
| 3185 | } | ||
| 3186 | |||
| 3187 | /* Return a newly allocated string containing the | ||
| 3188 | absolute filename of FILE given CWD (which should end with a slash). */ | ||
| 3189 | char * | ||
| 3190 | absolute_filename (file, cwd) | ||
| 3191 | char *file, *cwd; | ||
| 3192 | { | ||
| 3193 | char *slashp, *cp, *res; | ||
| 3194 | |||
| 3195 | if (file[0] == '/') | ||
| 3196 | res = concat (file, "", ""); | ||
| 3197 | else | ||
| 3198 | res = concat (cwd, file, ""); | ||
| 3199 | |||
| 3200 | /* Delete the "/dirname/.." and "/." substrings. */ | ||
| 3201 | slashp = etags_index (res, '/'); | ||
| 3202 | while (slashp != NULL && slashp[0] != '\0') | ||
| 3203 | { | ||
| 3204 | if (slashp[1] == '.') | ||
| 3205 | { | ||
| 3206 | if (slashp[2] == '.' | ||
| 3207 | && (slashp[3] == '/' || slashp[3] == '\0')) | ||
| 3208 | { | ||
| 3209 | cp = slashp; | ||
| 3210 | do | ||
| 3211 | cp--; | ||
| 3212 | while (cp >= res && *cp != '/'); | ||
| 3213 | if (*cp == '/') | ||
| 3214 | { | ||
| 3215 | strcpy (cp, slashp + 3); | ||
| 3216 | } | ||
| 3217 | else /* else (cp == res) */ | ||
| 3218 | { | ||
| 3219 | if (slashp[3] != NULL) | ||
| 3220 | strcpy (cp, slashp + 4); | ||
| 3221 | else | ||
| 3222 | return "."; | ||
| 3223 | } | ||
| 3224 | slashp = cp; | ||
| 3225 | } | ||
| 3226 | else if (slashp[2] == '/' || slashp[2] == '\0') | ||
| 3227 | { | ||
| 3228 | strcpy (slashp, slashp + 2); | ||
| 3229 | } | ||
| 3230 | } | ||
| 3231 | else | ||
| 3232 | { | ||
| 3233 | slashp = etags_index (slashp + 1, '/'); | ||
| 3234 | } | ||
| 3235 | } | ||
| 3236 | |||
| 3237 | return res; | ||
| 3238 | } | ||
| 3239 | |||
| 3240 | /* Return a newly allocated string containing the absolute filename | ||
| 3241 | of dir where FILE resides given CWD (which should end with a slash). */ | ||
| 3242 | char * | ||
| 3243 | absolute_dirname (file, cwd) | ||
| 3244 | char *file, *cwd; | ||
| 3245 | { | ||
| 3246 | char *slashp, *res; | ||
| 3247 | char save; | ||
| 3248 | |||
| 3249 | slashp = etags_rindex (file, '/'); | ||
| 3250 | if (slashp == NULL) | ||
| 3251 | return cwd; | ||
| 3252 | save = slashp[1]; | ||
| 3253 | slashp[1] = '\0'; | ||
| 3254 | res = absolute_filename (file, cwd); | ||
| 3255 | slashp[1] = save; | ||
| 3256 | |||
| 3257 | return res; | ||
| 3258 | } | ||
| 3259 | |||
| 3093 | /* Like malloc but get fatal error if memory is exhausted. */ | 3260 | /* Like malloc but get fatal error if memory is exhausted. */ |
| 3094 | 3261 | ||
| 3095 | char * | 3262 | char * |