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);
        }
 }

Reply via email to