bug-global
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Following Symbolic Links


From: Leo L. Schwab
Subject: Following Symbolic Links
Date: Fri, 26 Jun 2009 17:51:53 -0700
User-agent: Mutt/1.5.20 (2009-06-14)

        A colleague had trouble running 'gtags' in a source tree with
recursive symlinks.  Next thing I knew, I was bashing this out.

        This patch adds a new argument to gtags: --follow-links.  Note that
I completely wrote this before I found last month's email thread on the
subject, so my embodiment may not be precisely what everyone had in mind.

        I hacked this together in a few hours, and it has received minimal
testing.  At the very least it should be good as a basis for discussion.
All feedback welcome.

                                        Thanks,
                                        Schwab
----
diff -ur --exclude='*.o' global-5.7.5/doc/gtags.ref 
global-5.7.5-hacking/doc/gtags.ref
--- global-5.7.5/doc/gtags.ref  2009-03-13 17:30:38.000000000 -0700
+++ global-5.7.5-hacking/doc/gtags.ref  2009-06-26 15:56:43.000000000 -0700
@@ -4,7 +4,7 @@
 @unnumberedsubsec SYNOPSIS
 @noindent
 @quotation
-gtags [-ciIOqvw][-f file][-n address@hidden
+gtags [-ciIOqvw][-f file][-n number][-l address@hidden
 @end quotation
 @unnumberedsubsec DESCRIPTION
 Gtags recursively collect the source files under
@@ -52,6 +52,14 @@
 @item @samp{-i}, @samp{--incremental}
 Update tag files incrementally. You had better use
 global(1) with the -u option.
address@hidden @samp{-l}, @samp{--follow-links} dirs|files|both|none
+Control how symbolic links are followed.
+By default, gtags will follow all symbolic links.  Depending on
+how your source tree is arranged, this may not be desirable.
+The argument dirs will cause gtags to only follow symbolic
+links that point to directories, files will only follow
+links to files, both will follow all links, and none
+will ignore all symbolic links.
 @item @samp{-n}, @samp{--max-args} number
 Maximum number of arguments for gtags-parser(1).
 By default, gtags invokes gtags-parser with arguments
diff -ur --exclude='*.o' global-5.7.5/gtags/const.h 
global-5.7.5-hacking/gtags/const.h
--- global-5.7.5/gtags/const.h  2009-03-13 17:30:38.000000000 -0700
+++ global-5.7.5-hacking/gtags/const.h  2009-06-26 15:56:43.000000000 -0700
@@ -1,6 +1,6 @@
 /* This file is generated automatically by convert.pl from gtags/manual.in. */
 const char *progname = "gtags";
-const char *usage_const = "Usage: gtags [-ciIOqvw][-f file][-n 
number][dbpath]\n";
+const char *usage_const = "Usage: gtags [-ciIOqvw][-f file][-n number][-l 
arg][dbpath]\n";
 const char *help_const = "Options:\n\
 -c, --compact\n\
        Make GTAGS in compact format.\n\
@@ -26,6 +26,14 @@
 -i, --incremental\n\
        Update tag files incrementally. You had better use\n\
        global(1) with the -u option.\n\
+-l, --follow-links dirs|files|both|none\n\
+       Control how symbolic links are followed.\n\
+       By default, gtags will follow all symbolic links.  Depending on\n\
+       how your source tree is arranged, this may not be desirable.\n\
+       The argument dirs will cause gtags to only follow symbolic\n\
+       links that point to directories, files will only follow\n\
+       links to files, both will follow all links, and none\n\
+       will ignore all symbolic links.\n\
 -n, --max-args number\n\
        Maximum number of arguments for gtags-parser(1).\n\
        By default, gtags invokes gtags-parser with arguments\n\
diff -ur --exclude='*.o' global-5.7.5/gtags/gtags.1 
global-5.7.5-hacking/gtags/gtags.1
--- global-5.7.5/gtags/gtags.1  2009-03-13 17:30:38.000000000 -0700
+++ global-5.7.5-hacking/gtags/gtags.1  2009-06-26 15:56:43.000000000 -0700
@@ -3,7 +3,7 @@
 .SH NAME
 gtags \- create tag files for global.
 .SH SYNOPSIS
-\fBgtags\fP [-ciIOqvw][-f \fIfile\fP][-n \fInumber\fP][\fIdbpath\fP]
+\fBgtags\fP [-ciIOqvw][-f \fIfile\fP][-n \fInumber\fP][-l 
\fIarg\fP][\fIdbpath\fP]
 .br
 .SH DESCRIPTION
 \fBGtags\fP recursively collect the source files under
@@ -58,6 +58,15 @@
 Update tag files incrementally. You had better use
 \fBglobal\fP(1) with the -u option.
 .TP
+\fB-l\fP, \fB--follow-links\fP \fIdirs|files|both|none\fP
+Control how symbolic links are followed.
+By default, gtags will follow all symbolic links.  Depending on
+how your source tree is arranged, this may not be desirable.
+The argument \fIdirs\fP will cause gtags to only follow symbolic
+links that point to directories, \fIfiles\fP will only follow
+links to files, \fIboth\fP will follow all links, and \fInone\fP
+will ignore all symbolic links.
+.TP
 \fB-n\fP, \fB--max-args\fP \fInumber\fP
 Maximum number of arguments for \fBgtags-parser\fP(1).
 By default, gtags invokes \fBgtags-parser\fP with arguments
diff -ur --exclude='*.o' global-5.7.5/gtags/gtags.c 
global-5.7.5-hacking/gtags/gtags.c
--- global-5.7.5/gtags/gtags.c  2009-03-13 17:30:37.000000000 -0700
+++ global-5.7.5-hacking/gtags/gtags.c  2009-06-26 16:09:59.000000000 -0700
@@ -85,6 +85,7 @@
  */
 int do_path;
 int convert_type = PATH_RELATIVE;
+int followflags = FOLLOWF_BOTH;
 
 int extractmethod;
 int total;
@@ -122,6 +123,7 @@
        {"quiet", no_argument, NULL, 'q'},
        {"verbose", no_argument, NULL, 'v'},
        {"warning", no_argument, NULL, 'w'},
+       {"follow-links", required_argument, NULL, 'l'},
 
        /*
         * The following are long name only.
@@ -162,7 +164,7 @@
        int optchar;
        int option_index = 0;
 
-       while ((optchar = getopt_long(argc, argv, "cf:iIn:oOqvwse", 
long_options, &option_index)) != EOF) {
+       while ((optchar = getopt_long(argc, argv, "cf:iIl:n:oOqvwse", 
long_options, &option_index)) != EOF) {
                switch (optchar) {
                case 0:
                        /* already flags set */
@@ -201,6 +203,18 @@
                case 'I':
                        Iflag++;
                        break;
+               case 'l':
+                       if (!strncmp (optarg, "files", 5))
+                               followflags = FOLLOWF_FILE;
+                       else if (!strncmp (optarg, "dirs", 4))
+                               followflags = FOLLOWF_DIR;
+                       else if (!strncmp (optarg, "both", 4))
+                               followflags = FOLLOWF_BOTH;
+                       else if (!strncmp (optarg, "none", 4))
+                               followflags = FOLLOWF_NONE;
+                       else
+                               die ("Unknown --follow-flags argument: %s", 
optarg);
+                       break;
                case 'n':
                        max_args = atoi(optarg);
                        if (max_args <= 0)
@@ -502,7 +516,7 @@
        if (file_list)
                find_open_filelist(file_list, root);
        else
-               find_open(NULL);
+               find_open(NULL, followflags);
        total = 0;
        while ((path = find_read()) != NULL) {
                const char *fid;
@@ -806,7 +820,7 @@
        if (file_list)
                find_open_filelist(file_list, root);
        else
-               find_open(NULL);
+               find_open(NULL, followflags);
        /*
         * Add tags.
         */
diff -ur --exclude='*.o' global-5.7.5/gtags/manual.in 
global-5.7.5-hacking/gtags/manual.in
--- global-5.7.5/gtags/manual.in        2009-03-13 17:30:37.000000000 -0700
+++ global-5.7.5-hacking/gtags/manual.in        2009-06-26 15:35:25.000000000 
-0700
@@ -25,7 +25,7 @@
 @HEADER        GTAGS,1,January 2009,GNU Project
 @NAME  gtags - create tag files for global.
 @SYNOPSIS
-       @name{gtags} [-ciIOqvw][-f @arg{file}][-n @address@hidden
+       @name{gtags} [-ciIOqvw][-f @arg{file}][-n @arg{number}][-l 
@address@hidden
 @DESCRIPTION
        @name{Gtags} recursively collect the source files under
        the current directory,
@@ -72,6 +72,14 @@
        @address@hidden, @option{--incremental}}
                Update tag files incrementally. You had better use
                @xref{global,1} with the -u option.
+       @address@hidden, @option{--follow-links} @arg{dirs|files|both|none}}
+               Control how symbolic links are followed.
+               By default, gtags will follow all symbolic links.  Depending on
+               how your source tree is arranged, this may not be desirable.
+               The argument @arg{dirs} will cause gtags to only follow symbolic
+               links that point to directories, @arg{files} will only follow
+               links to files, @arg{both} will follow all links, and @arg{none}
+               will ignore all symbolic links.
        @address@hidden, @option{--max-args} @arg{number}}
                Maximum number of arguments for @xref{gtags-parser,1}.
                By default, gtags invokes @name{gtags-parser} with arguments
diff -ur --exclude='*.o' global-5.7.5/libutil/find.c 
global-5.7.5-hacking/libutil/find.c
--- global-5.7.5/libutil/find.c 2009-03-13 17:30:37.000000000 -0700
+++ global-5.7.5-hacking/libutil/find.c 2009-06-26 16:11:32.000000000 -0700
@@ -78,6 +78,7 @@
 static regex_t *suff = &suff_area;     /* regex for suffixes */
 static STRBUF *list;
 static int list_count;
+static int follow_flags;
 static char **listarray;               /* list for skipping full path */
 static FILE *ip;
 static FILE *temp;
@@ -372,8 +373,9 @@
  *     r)              -1: error, 0: normal
  *
  * format of directory list:
- * |ddir1\0ffile1\0llink\0|
- * means directory 'dir1', file 'file1' and symbolic link 'link'.
+ * |ddir1\0ffile1\0Dlinkeddir\0Flinkedfile\0llink\0|
+ * means directory 'dir1', file 'file1', symbolic link to 'linkeddir',
+ * symbolic link to 'linkedfile', and symbolic link 'link'.
  */
 static int
 getdirs(const char *dir, STRBUF *sb)
@@ -381,6 +383,7 @@
        DIR *dirp;
        struct dirent *dp;
        struct stat st;
+       char islink;
 
        if ((dirp = opendir(dir)) == NULL)
                return -1;
@@ -389,14 +392,24 @@
                        continue;
                if (!strcmp(dp->d_name, ".."))
                        continue;
-               if (stat(makepath(dir, dp->d_name, NULL), &st) < 0) {
-                       warning("cannot stat '%s'. (Ignored)", dp->d_name);
+               if (lstat(makepath(dir, dp->d_name, NULL), &st) < 0) {
+                       warning("cannot lstat '%s'. (Ignored)", dp->d_name);
                        continue;
                }
+
+               if (S_ISLNK(st.st_mode)) {
+                       if (stat(makepath(dir, dp->d_name, NULL), &st) < 0) {
+                               warning("cannot stat '%s'. (Ignored)", 
dp->d_name);
+                               continue;
+                       }
+                       islink = 1;
+               } else
+                       islink = 0;
+
                if (S_ISDIR(st.st_mode))
-                       strbuf_putc(sb, 'd');
+                       strbuf_putc(sb, islink ? 'D' : 'd');
                else if (S_ISREG(st.st_mode))
-                       strbuf_putc(sb, 'f');
+                       strbuf_putc(sb, islink ? 'F' : 'f');
                else
                        strbuf_putc(sb, ' ');
                strbuf_puts(sb, dp->d_name);
@@ -412,14 +425,18 @@
  *                     If NULL, assumed '.' directory.
  */
 void
-find_open(const char *start)
+find_open(const char *start, int cl_follow_flags)
 {
        struct stack_entry *curp;
+
        assert(find_mode == 0);
        find_mode = FIND_OPEN;
 
        if (!start)
                start = "./";
+
+       follow_flags = cl_follow_flags;
+
        /*
         * setup stack.
         */
@@ -531,6 +548,17 @@
                         */
                                /* makepath() returns unsafe module local area. 
*/
                        strlimcpy(path, makepath(dir, unit, NULL), 
sizeof(path));
+                       if (type == 'D') {
+                               /*  Softlink to dir.  */
+                               if (!(follow_flags & FOLLOWF_DIR))
+                                       continue;
+                               type = 'd';
+                       } else if (type == 'F') {
+                               /*  Softlink to file.  */
+                               if (!(follow_flags & FOLLOWF_FILE))
+                                       continue;
+                               type = 'f';
+                       }
                        if (type == 'd')
                                strcat(path, "/");
                        if (skipthisfile(path))
@@ -541,6 +569,7 @@
                                 * o directory
                                 * o file which does not exist
                                 * o dead symbolic link
+                                * XXX ewhac: Is this test necessary?  Is 
stat(2) known to lie?
                                 */
                                if (!test("f", path)) {
                                        if (test("d", path))
diff -ur --exclude='*.o' global-5.7.5/libutil/find.h 
global-5.7.5-hacking/libutil/find.h
--- global-5.7.5/libutil/find.h 2009-03-13 17:30:37.000000000 -0700
+++ global-5.7.5-hacking/libutil/find.h 2009-06-26 14:58:31.000000000 -0700
@@ -21,9 +21,15 @@
 #ifndef _FIND_H_
 #define _FIND_H_
 
-void find_open(const char *);
+void find_open(const char *, int follow_flags);
 void find_open_filelist(const char *, const char *);
 char *find_read(void);
 void find_close(void);
 
+/*  follow_flags  */
+#define FOLLOWF_NONE    0
+#define FOLLOWF_FILE    1
+#define FOLLOWF_DIR     2
+#define FOLLOWF_BOTH    (FOLLOWF_FILE | FOLLOWF_DIR)
+
 #endif /* ! _FIND_H_ */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]