# HG changeset patch # User Francesco Potort # Date 764447239 0 # Node ID 91112dd5c9f514491fb3b8e142acf5a118b79d27 # Parent 55236c5bca7cee465a34ec9fd8cec1811a38a860 * 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. diff -r 55236c5bca7c -r 91112dd5c9f5 lib-src/etags.c --- a/lib-src/etags.c Wed Mar 23 18:23:32 1994 +0000 +++ b/lib-src/etags.c Wed Mar 23 18:27:19 1994 +0000 @@ -25,9 +25,11 @@ * Gnu Emacs TAGS format and modifications by RMS? * Sam Kendall added C++. * - * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. 10.7 + * Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. */ +char etags_version[] = "@(#) pot revision number is 10.15"; + #ifdef MSDOS #include #endif /* MSDOS */ @@ -48,9 +50,8 @@ #include "getopt.h" extern char *getenv (); +extern char *getcwd (); -char *etags_index (), *etags_rindex (); -char *savenstr (); /* Define the symbol ETAGS to make the program "etags", which makes emacs-style tag tables by default. @@ -151,19 +152,20 @@ struct nd_st *left, *right; /* left and right sons */ }; -long ftell (); typedef struct nd_st NODE; logical header_file; /* TRUE if .h file, FALSE o.w. */ /* boolean "functions" (see init) */ logical _wht[0177], _etk[0177], _itk[0177], _btk[0177]; +char cwd [BUFSIZ]; /* current working directory */ +char *outfiledir; /* directory of tagfile */ char *concat (); -char *savenstr (); -char *savestr (); -char *xmalloc (); -char *xrealloc (); +char *savenstr (), *savestr (); +char *etags_index (), *etags_rindex (); +char *relative_filename (), *absolute_filename (), *absolute_dirname (); +char *xmalloc (), *xrealloc (); int L_isdef (), L_isquote (); int PF_funcs (); int total_size_of_entries (); @@ -241,7 +243,7 @@ *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */ /* token starting chars */ *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~", - /* valid in-token chars */ + /* valid in-token chars */ *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789"; int append_to_tagfile; /* -a: append to tags */ @@ -442,7 +444,7 @@ extern char *gfnames (); extern char *massage_name (); #endif - + #ifdef MSDOS _fmode = O_BINARY; /* all of files are treated as binary files */ #endif /* MSDOS */ @@ -465,7 +467,7 @@ for (;;) { int opt; - opt = getopt_long (argc, argv, "aACdDo:f:StTi:BFuvxwVH", longopts, 0); + opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0); if (opt == EOF) break; @@ -569,10 +571,20 @@ exit (BAD); } - if (outfile == 0) + if (outfile == NULL) { outfile = emacs_tags_format ? "TAGS" : "tags"; } + getcwd (cwd, BUFSIZ); /* the current working directory */ + strcat (cwd, "/"); + if (streq (outfile, "-")) + { + outfiledir = cwd; + } + else + { + outfiledir = absolute_dirname (outfile, cwd); + } init (); /* set up boolean "functions" */ @@ -619,18 +631,18 @@ this_file = argv[optind]; #endif /* Input file named "-" means read file names from stdin and use them. */ - if (streq (this_file, "-")) + if (streq (this_file, "-")) + { + while (!feof (stdin)) { - while (!feof (stdin)) - { - (void) readline (&filename_lb, stdin); - if (strlen (filename_lb.buffer) > 0) - process_file (filename_lb.buffer); - } + (void) readline (&filename_lb, stdin); + if (strlen (filename_lb.buffer) > 0) + process_file (filename_lb.buffer); } - else - process_file (this_file); } + else + process_file (this_file); + } if (emacs_tags_format) { @@ -701,7 +713,20 @@ } if (emacs_tags_format) { - fprintf (outf, "\f\n%s,%d\n", file, total_size_of_entries (head)); + char *filename; + + if (file[0] == '/') + { + /* file is an absolute filename. Canonicalise it. */ + filename = absolute_filename (file, cwd); + } + else + { + /* file is a filename relative to cwd. Make it relative + to the directory of the tags file. */ + filename = relative_filename (file, outfiledir); + } + fprintf (outf, "\f\n%s,%d\n", filename, total_size_of_entries (head)); put_entries (head); free_tree (head); head = NULL; @@ -1318,7 +1343,8 @@ FUNCST funcdef; - /* typedefs are recognized using a simple finite automaton. + /* + * typedefs are recognized using a simple finite automaton. * typeddef is its state variable. */ typedef enum @@ -1326,16 +1352,16 @@ tnone, /* nothing seen */ ttypedseen, /* typedef keyword seen */ tinbody, /* inside typedef body */ - tend /* just before typedef tag */ + tend, /* just before typedef tag */ + tignore /* junk after typedef tag */ } TYPEDST; TYPEDST typdef; - /* struct tags for C++ are recognized using another simple - * finite automaton. `structdef' is its state variable. - * This machinery is only invoked for C++; otherwise structdef - * should remain snone. However, this machinery can easily be - * adapted to find structure tags in normal C code. + /* + * struct-like structures (enum, struct and union) are recognized + * using another simple finite automaton. `structdef' is its state + * variable. */ typedef enum { @@ -1346,6 +1372,7 @@ sinbody /* in struct body: recognize member func defs*/ } STRUCTST; STRUCTST structdef; + /* * When structdef is stagseen, scolonseen, or sinbody, structtag is the * struct tag, and structtype is the type of the preceding struct-like @@ -1448,7 +1475,7 @@ lp = curlb.buffer; *lp = 0; - definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone; + definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone; next_token_is_func = yacc_rules = FALSE; midtoken = inquote = inchar = incomm = quotednl = FALSE; cblev = 0; @@ -1515,7 +1542,7 @@ CNL; /* FALLTHRU */ case '\'': - inchar = FALSE; + inchar = FALSE; break; } continue; @@ -1553,7 +1580,7 @@ /* entering or exiting rules section in yacc file */ lp++; definedef = dnone; funcdef = fnone; - typdef= tnone; structdef= snone; + typdef = tnone; structdef = snone; next_token_is_func = FALSE; midtoken = inquote = inchar = incomm = quotednl = FALSE; cblev = 0; @@ -1572,9 +1599,10 @@ /* Consider token only if some complicated conditions are satisfied. */ if (((cblev == 0 && structdef != scolonseen) || (cblev == 1 && cplpl && structdef == sinbody)) + && typdef != tignore && definedef != dignorerest && (funcdef != finlist - || (definedef != dnone && definedef != dignorerest))) + || definedef != dnone)) { if (midtoken) { @@ -1714,19 +1742,37 @@ case ';': if (definedef != dnone) break; - if (cblev == 0 && typdef == tend) - { - typdef = tnone; - MAKE_TAG_FROM_OTH_LB (FALSE); - } + if (cblev == 0) + switch (typdef) + { + case tend: + MAKE_TAG_FROM_OTH_LB (FALSE); + /* FALLTHRU */ + default: + typdef = tnone; + } if (funcdef != fignore) funcdef = fnone; - /* FALLTHRU */ + if (structdef == stagseen) + structdef = snone; + break; case ',': - /* FALLTHRU */ + if (definedef != dnone) + break; + if (funcdef != finlist && funcdef != fignore) + funcdef = fnone; + if (structdef == stagseen) + structdef = snone; + break; case '[': if (definedef != dnone) break; + if (cblev == 0 && typdef == tend) + { + typdef = tignore; + MAKE_TAG_FROM_OTH_LB (FALSE); + break; + } if (funcdef != finlist && funcdef != fignore) funcdef = fnone; if (structdef == stagseen) @@ -1758,6 +1804,11 @@ funcdef = flistseen; break; } + if (cblev == 0 && typdef == tend) + { + typdef = tignore; + MAKE_TAG_FROM_OTH_LB (FALSE); + } } else if (parlev < 0) /* can happen due to ill-conceived #if's. */ parlev = 0; @@ -1786,6 +1837,11 @@ /* FALLTHRU */ case fignore: funcdef = fnone; + break; + case fnone: + /* Neutralize `extern "C" {' grot. + if (cblev == 0 && structdef == snone && typdef == tnone) + cblev--; */; } cblev++; break; @@ -1910,6 +1966,7 @@ { if (typedefs) typdef = ttypedseen; + funcdef = fnone; return (FALSE); } break; @@ -2015,7 +2072,8 @@ switch (toktype) { case st_C_typespec: - funcdef = fnone; /* should be useless */ + if (funcdef != finlist && funcdef != fignore) + funcdef = fnone; /* should be useless */ return (FALSE); default: if (funcdef == fnone) @@ -2176,7 +2234,7 @@ dbp++; } if (!isalpha (*dbp) - && *dbp != '_' + && *dbp != '_' && *dbp != '$') return; for (cp = dbp + 1; @@ -2364,7 +2422,7 @@ verify_tag = FALSE; } } - if ((found_tag) && (verify_tag)) /* not external proc, so make tag */ + if ((found_tag) && (verify_tag)) /* not external proc, so make tag */ { found_tag = FALSE; verify_tag = FALSE; @@ -3073,7 +3131,8 @@ fprintf (stderr, "\n"); } -/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ +/* Return a newly-allocated string whose contents + concatenate those of s1, s2, s3. */ char * concat (s1, s2, s3) @@ -3085,11 +3144,119 @@ strcpy (result, s1); strcpy (result + len1, s2); strcpy (result + len1 + len2, s3); - *(result + len1 + len2 + len3) = 0; + result[len1 + len2 + len3] = '\0'; return result; } +/* Return a newly allocated string containing the filename of FILE relative + to the absolute directory DIR (which should end with a slash). */ + +char * +relative_filename (file, dir) + char *file, *dir; +{ + char *fp, *dp, *res; + + /* Find the common root of file and dir. */ + fp = absolute_filename (file, cwd); + dp = dir; + while (*fp++ == *dp++) + continue; + do + { + fp--; + dp--; + } + while (*fp != '/'); + + /* Build a sequence of "../" strings for the resulting relative filename. */ + for (dp = etags_index (dp + 1, '/'), res = ""; + dp != NULL; + dp = etags_index (dp + 1, '/')) + { + res = concat (res, "../", ""); + } + + /* Add the filename relative to the common root of file and dir. */ + res = concat (res, fp + 1, ""); + + return res; /* temporary stub */ +} + +/* Return a newly allocated string containing the + absolute filename of FILE given CWD (which should end with a slash). */ +char * +absolute_filename (file, cwd) + char *file, *cwd; +{ + char *slashp, *cp, *res; + + if (file[0] == '/') + res = concat (file, "", ""); + else + res = concat (cwd, file, ""); + + /* Delete the "/dirname/.." and "/." substrings. */ + slashp = etags_index (res, '/'); + while (slashp != NULL && slashp[0] != '\0') + { + if (slashp[1] == '.') + { + if (slashp[2] == '.' + && (slashp[3] == '/' || slashp[3] == '\0')) + { + cp = slashp; + do + cp--; + while (cp >= res && *cp != '/'); + if (*cp == '/') + { + strcpy (cp, slashp + 3); + } + else /* else (cp == res) */ + { + if (slashp[3] != NULL) + strcpy (cp, slashp + 4); + else + return "."; + } + slashp = cp; + } + else if (slashp[2] == '/' || slashp[2] == '\0') + { + strcpy (slashp, slashp + 2); + } + } + else + { + slashp = etags_index (slashp + 1, '/'); + } + } + + return res; +} + +/* Return a newly allocated string containing the absolute filename + of dir where FILE resides given CWD (which should end with a slash). */ +char * +absolute_dirname (file, cwd) + char *file, *cwd; +{ + char *slashp, *res; + char save; + + slashp = etags_rindex (file, '/'); + if (slashp == NULL) + return cwd; + save = slashp[1]; + slashp[1] = '\0'; + res = absolute_filename (file, cwd); + slashp[1] = save; + + return res; +} + /* Like malloc but get fatal error if memory is exhausted. */ char *