[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: |
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_ */
- Following Symbolic Links,
Leo L. Schwab <=