[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Following Symbolic Links
From: |
Petr Uzel |
Subject: |
Re: Following Symbolic Links |
Date: |
Mon, 29 Jun 2009 10:15:06 +0200 |
User-agent: |
Mutt/1.5.19 (2009-01-05) |
Hi,
On Fri, Jun 26, 2009 at 05:51:53PM -0700, Leo L. Schwab wrote:
> 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.
I did a simple test with a quilt usecase (as described in [1]) and
'gtags -l files' works OK. Many thanks for the patch!
[1] http://www.mail-archive.com/address@hidden/msg00523.html
>
> 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_ */
>
>
> _______________________________________________
> Bug-global mailing list
> address@hidden
> http://lists.gnu.org/mailman/listinfo/bug-global
--
Best regards / s pozdravem
Petr Uzel, Packages maintainer
---------------------------------------------------------------------
SUSE LINUX, s.r.o. e-mail: address@hidden
Lihovarská 1060/12 http://www.suse.cz
190 00 Prague 9
Czech Republic