Hi,
ctags(1) has some crazy system(3) call I want to remove, that are in -u
logic (update 'tags' file).
Instead of switch from system(3) to fork(2)/exec(2), I think changing
the logic for -u would be better.
Currently, when updating, the logic is:
- generate tags in memory for passed filenames (as usual)
- take the 'tags' file, and using system(3), "mv + fgrep -v + rm" in
order to strip off every reference for all filenames in arguments
from 'tags' file
- append the tags we have in memory to the file
- call system(3) to sort the file
The proposed patch do the following:
- when updating, preload the 'tags' entries (except the ones on
arguments). so we populate the tags in memory with the tags on disk
for every file we don't want to reread.
- and continue normally
- generate tags in memory (so it adds new tags to preloaded ones)
- write to disk (so the preloaded and the new entries, ordered)
For that, I had to parse the 'tags' file, and populate some globals in
order pfnote() take the good values (filename + pattern).
I have one drawback for the filename. The current code expects it is
static memory (in normal process, the string comes from argv). But with
my parsing, I dynamically allocate it using strdup(3): so it wouldn't
be freed.
So I had added a new member to NODE in order to mark if 'file' need to
be freed (if it comes from 'preload').
Comments ? OK ?
--
Sebastien Marie
Index: ctags.c
===================================================================
RCS file: /cvs/src/usr.bin/ctags/ctags.c,v
retrieving revision 1.15
diff -u -p -r1.15 ctags.c
--- ctags.c 8 Feb 2015 23:40:34 -0000 1.15
+++ ctags.c 19 Aug 2015 18:15:04 -0000
@@ -65,6 +65,7 @@ char lbuf[LINE_MAX];
void init(void);
void find_entries(char *);
+void preload_entries(char *, int, char *[]);
int
main(int argc, char *argv[])
@@ -75,7 +76,6 @@ main(int argc, char *argv[])
int exit_val; /* exit value */
int step; /* step through args */
int ch; /* getopts char */
- char *cmd;
aflag = uflag = NO;
while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
@@ -122,6 +122,8 @@ usage: (void)fprintf(stderr,
}
init();
+ if (uflag)
+ preload_entries(outfile, argc, argv);
for (exit_val = step = 0; step < argc; ++step)
if (!(inf = fopen(argv[step], "r"))) {
@@ -138,30 +140,10 @@ usage: (void)fprintf(stderr,
if (xflag)
put_entries(head);
else {
- if (uflag) {
- for (step = 0; step < argc; step++) {
- if (asprintf(&cmd,
- "mv %s OTAGS; fgrep -v '\t%s\t'
OTAGS >%s; rm OTAGS",
- outfile, argv[step], outfile) == -1)
- err(1, "out of space");
- system(cmd);
- free(cmd);
- cmd = NULL;
- }
- aflag = 1;
- }
if (!(outf = fopen(outfile, aflag ? "a" : "w")))
err(exit_val, "%s", outfile);
put_entries(head);
(void)fclose(outf);
- if (uflag) {
- if (asprintf(&cmd, "sort -o %s %s",
- outfile, outfile) == -1)
- err(1, "out of space");
- system(cmd);
- free(cmd);
- cmd = NULL;
- }
}
}
exit(exit_val);
@@ -252,4 +234,80 @@ find_entries(char *file)
}
}
/* C */ c_entries();
+}
+
+void
+preload_entries(char *tagsfile, int argc, char *argv[])
+{
+ FILE *fp;
+ char line[LINE_MAX];
+ char *entry = NULL;
+ char *file = NULL;
+ char *pattern = NULL;
+ char *eol;
+ int i;
+
+ in_preload = YES;
+
+ if ((fp = fopen(tagsfile, "r")) == NULL)
+ err(1, "preload_entries: %s", tagsfile);
+
+ while (1) {
+next:
+ if (fgets(line, sizeof(line), fp) == NULL)
+ break;
+
+ if (ferror(fp))
+ err(1, "preload_entries: fgets");
+
+ if ((eol = strchr(line, '\n')) == NULL)
+ errx(1, "preload_entries: line too long");
+ *eol = '\0';
+
+ /* extract entry */
+ entry = line;
+ if ((file = strchr(line, '\t')) == NULL)
+ errx(1, "preload_entries: couldn't parse entry: %s",
+ tagsfile);
+ *file = '\0';
+
+ /* extract file */
+ file++;
+ if ((pattern = strchr(file, '\t')) == NULL)
+ errx(1, "preload_entries: couldn't parse filename: %s",
+ tagsfile);
+ *pattern = '\0';
+
+ /* next is pattern */
+ pattern++;
+
+ /* don't keep "/^" and "/" around pattern */
+ if (pattern[0] == '/' && pattern[1] == '^') {
+ pattern += 2;
+ i = strlen(pattern);
+ if (pattern[i-1] == '/')
+ pattern[i-1] = '\0';
+ else
+ errx(1, "preload_entries: couldn't parse "
+ "pattern: %s", tagsfile);
+ }
+
+ /* skip this file ? */
+ for(i = 0; i < argc; i++)
+ if (strcmp(file, argv[i]) == 0)
+ goto next;
+
+ /* add entry */
+ if ((curfile = strdup(file)) == NULL)
+ err(1, "preload_entries: strdup");
+ (void)strlcpy(lbuf, pattern, sizeof(lbuf));
+ pfnote(entry, 0);
+ }
+ if (ferror(fp))
+ err(1, "preload_entries: fgets");
+
+ if (fclose(fp) == EOF)
+ err(1, "preload_entries: fclose");
+
+ in_preload = NO;
}
Index: ctags.h
===================================================================
RCS file: /cvs/src/usr.bin/ctags/ctags.h,v
retrieving revision 1.8
diff -u -p -r1.8 ctags.h
--- ctags.h 10 Dec 2014 19:44:21 -0000 1.8
+++ ctags.h 19 Aug 2015 18:15:04 -0000
@@ -56,6 +56,7 @@ typedef struct nd_st { /* sorting stru
*pat; /* search pattern */
int lno; /* for -x option */
bool been_warned; /* set if noticed dup */
+ bool dynfile; /* set if file will need freed */
} NODE;
extern char *curfile; /* current input file name */
@@ -72,6 +73,7 @@ extern bool _wht[], _itk[], _btk[];
extern char lbuf[LINE_MAX];
extern char *lbp;
extern char searchar; /* ex search character */
+extern bool in_preload;
extern int cicmp(char *);
extern void get_line(void);
Index: tree.c
===================================================================
RCS file: /cvs/src/usr.bin/ctags/tree.c,v
retrieving revision 1.10
diff -u -p -r1.10 tree.c
--- tree.c 27 Oct 2009 23:59:37 -0000 1.10
+++ tree.c 19 Aug 2015 18:15:04 -0000
@@ -39,6 +39,8 @@
#include "ctags.h"
+bool in_preload = NO;
+
static void add_node(NODE *, NODE *);
static void free_tree(NODE *);
@@ -79,6 +81,7 @@ pfnote(char *name, int ln)
np->lno = ln;
np->left = np->right = 0;
np->been_warned = NO;
+ np->dynfile = in_preload;
if (!(np->pat = strdup(lbuf)))
err(1, NULL);
if (!head)
@@ -128,6 +131,8 @@ free_tree(NODE *node)
free(node->entry);
free(node->pat);
+ if (node->dynfile == YES)
+ free(node->file);
free(node);
}
}