[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Following Symbolic Links
From: |
Leo L. Schwab |
Subject: |
Following Symbolic Links |
Date: |
Mon, 18 Jan 2010 17:43:08 -0800 |
User-agent: |
Mutt/1.5.20 (2009-06-14) |
I posted this patch about six months ago, receiving one favorable
response. I'm reposting it, updated for global v5.7.7.
This patch adds a new argument to gtags: --follow-links. This
allows the user to control how gtags will follow symbolic links -- follow
only links to files, only links to directories, links to both, or follow no
links at all. The default behavior of gtags (follow all links) is not
changed.
This patch is offered freely without encumbrance.
The patch has received only modest testing, but has worked well so
far. At the very least it can serve as a jumping-off point for discussion.
Let me know what you think.
Thanks,
Schwab
----
diff -ur --exclude='*.o' global-5.7.7/doc/global.info
global-5.7.7-hacking/doc/global.info
--- global-5.7.7/doc/global.info 2009-12-19 02:50:04.000000000 -0800
+++ global-5.7.7-hacking/doc/global.info 2010-01-18 13:45:12.000000000
-0800
@@ -2042,7 +2042,7 @@
- gtags [-ciIOqvw][-d tag-file][-f file][-n number][dbpath]
+ gtags [-ciIOqvw][-d tag-file][-f file][-n number][-l arg][dbpath]
DESCRIPTION
-----------
@@ -2099,6 +2099,14 @@
Update tag files incrementally. You had better use global(1) with
the -u option.
+`-l', `--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.
+
`-n', `--max-args' number
Maximum number of arguments for gtags-parser(1). By default,
gtags invokes gtags-parser with arguments as many as possible to
@@ -3774,10 +3782,10 @@
* -r <2>: Plug-in. (line 28)
* -r <3>: Usage(Vim). (line 44)
* -r: Usage(Elvis). (line 13)
-* -s <1>: Usage(Elvis). (line 17)
-* -s <2>: Usage(Vim). (line 48)
-* -s <3>: Plug-in. (line 28)
-* -s: Basic usage. (line 97)
+* -s <1>: Basic usage. (line 97)
+* -s <2>: Usage(Elvis). (line 17)
+* -s <3>: Usage(Vim). (line 48)
+* -s: Plug-in. (line 28)
* -t: Preparation(Elvis). (line 9)
* -u: Incremental updating.
(line 7)
@@ -3832,15 +3840,15 @@
Node: Reference54586
Node: global55168
Node: gtags62679
-Node: htags69891
-Node: gtags-parser82159
-Node: gozilla85659
-Node: gtags-cscope88661
-Node: Copying This Manual91166
-Node: GNU Free Documentation License91412
-Node: Business Model113822
-Node: The BOKIN Model Definition114117
-Node: Frequently Asked Questions118315
-Node: Index121728
+Node: htags70342
+Node: gtags-parser82610
+Node: gozilla86110
+Node: gtags-cscope89112
+Node: Copying This Manual91617
+Node: GNU Free Documentation License91863
+Node: Business Model114273
+Node: The BOKIN Model Definition114568
+Node: Frequently Asked Questions118766
+Node: Index122179
End Tag Table
diff -ur --exclude='*.o' global-5.7.7/doc/gtags.ref
global-5.7.7-hacking/doc/gtags.ref
--- global-5.7.7/doc/gtags.ref 2009-12-19 02:49:28.000000000 -0800
+++ global-5.7.7-hacking/doc/gtags.ref 2010-01-18 13:44:45.000000000 -0800
@@ -4,7 +4,7 @@
@unnumberedsubsec SYNOPSIS
@noindent
@quotation
-gtags [-ciIOqvw][-d tag-file][-f file][-n address@hidden
+gtags [-ciIOqvw][-d tag-file][-f file][-n number][-l address@hidden
@end quotation
@unnumberedsubsec DESCRIPTION
Gtags recursively collect the source files under
@@ -55,6 +55,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.7/gtags/const.h
global-5.7.7-hacking/gtags/const.h
--- global-5.7.7/gtags/const.h 2009-12-19 02:49:28.000000000 -0800
+++ global-5.7.7-hacking/gtags/const.h 2010-01-18 13:44:45.000000000 -0800
@@ -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][-d tag-file][-f file][-n
number][dbpath]\n";
+const char *usage_const = "Usage: gtags [-ciIOqvw][-d tag-file][-f file][-n
number][-l arg][dbpath]\n";
const char *help_const = "Options:\n\
-c, --compact\n\
Make GTAGS in compact format.\n\
@@ -29,6 +29,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.7/gtags/gtags.1
global-5.7.7-hacking/gtags/gtags.1
--- global-5.7.7/gtags/gtags.1 2009-12-19 02:49:28.000000000 -0800
+++ global-5.7.7-hacking/gtags/gtags.1 2010-01-18 13:44:45.000000000 -0800
@@ -3,7 +3,7 @@
.SH NAME
gtags \- create tag files for global.
.SH SYNOPSIS
-\fBgtags\fP [-ciIOqvw][-d \fItag-file\fP][-f \fIfile\fP][-n
\fInumber\fP][\fIdbpath\fP]
+\fBgtags\fP [-ciIOqvw][-d \fItag-file\fP][-f \fIfile\fP][-n \fInumber\fP][-l
\fIarg\fP][\fIdbpath\fP]
.br
.SH DESCRIPTION
\fBGtags\fP recursively collect the source files under
@@ -62,6 +62,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.7/gtags/gtags.c
global-5.7.7-hacking/gtags/gtags.c
--- global-5.7.7/gtags/gtags.c 2009-12-19 02:49:27.000000000 -0800
+++ global-5.7.7-hacking/gtags/gtags.c 2010-01-18 13:54:25.000000000 -0800
@@ -88,6 +88,7 @@
*/
int do_path;
int convert_type = PATH_RELATIVE;
+int followflags = FOLLOWF_BOTH;
int extractmethod;
int total;
@@ -126,6 +127,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.
@@ -163,7 +165,7 @@
int option_index = 0;
STATISTICS_TIME *tim;
- while ((optchar = getopt_long(argc, argv, "cd:f:iIn:oOqvwse",
long_options, &option_index)) != EOF) {
+ while ((optchar = getopt_long(argc, argv, "cd:f:iIl:n:oOqvwse",
long_options, &option_index)) != EOF) {
switch (optchar) {
case 0:
/* already flags set */
@@ -209,6 +211,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-links argument: %s",
optarg);
+ break;
case 'n':
max_args = atoi(optarg);
if (max_args <= 0)
@@ -585,7 +599,7 @@
if (file_list)
find_open_filelist(file_list, root);
else
- find_open(NULL);
+ find_open(NULL, followflags);
while ((path = find_read()) != NULL) {
const char *fid;
int n_fid = 0;
@@ -888,7 +902,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.7/gtags/manual.in
global-5.7.7-hacking/gtags/manual.in
--- global-5.7.7/gtags/manual.in 2009-12-19 02:49:27.000000000 -0800
+++ global-5.7.7-hacking/gtags/manual.in 2010-01-18 13:18:56.000000000
-0800
@@ -25,7 +25,7 @@
@HEADER GTAGS,1,September 2009,GNU Project
@NAME gtags - create tag files for global.
@SYNOPSIS
- @name{gtags} [-ciIOqvw][-d @arg{tag-file}][-f @arg{file}][-n
@address@hidden
+ @name{gtags} [-ciIOqvw][-d @arg{tag-file}][-f @arg{file}][-n
@arg{number}][-l @address@hidden
@DESCRIPTION
@name{Gtags} recursively collect the source files under
the current directory,
@@ -75,6 +75,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.7/libutil/find.c
global-5.7.7-hacking/libutil/find.c
--- global-5.7.7/libutil/find.c 2009-12-19 02:49:27.000000000 -0800
+++ global-5.7.7-hacking/libutil/find.c 2010-01-18 13:54:52.000000000 -0800
@@ -91,6 +91,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;
@@ -385,8 +386,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)
@@ -394,6 +396,7 @@
DIR *dirp;
struct dirent *dp;
struct stat st;
+ char islink;
if ((dirp = opendir(dir)) == NULL)
return -1;
@@ -402,14 +405,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);
@@ -425,14 +438,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.
*/
@@ -544,6 +561,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))
@@ -554,6 +582,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.7/libutil/find.h
global-5.7.7-hacking/libutil/find.h
--- global-5.7.7/libutil/find.h 2009-12-19 02:49:27.000000000 -0800
+++ global-5.7.7-hacking/libutil/find.h 2010-01-18 13:16:19.000000000 -0800
@@ -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_ */
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may
contain
confidential information. Any unauthorized review, use, disclosure or
distribution
is prohibited. If you are not the intended recipient, please contact the
sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
- Following Symbolic Links,
Leo L. Schwab <=