This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFA] Add -s option to source command.
- From: dje at google dot com (Doug Evans)
- To: gdb-patches at sourceware dot org
- Date: Tue, 6 Apr 2010 14:57:51 -0700 (PDT)
- Subject: [RFA] Add -s option to source command.
Hi.
In a big source tree with multiple disparate components it's useful to be
able to load scripts without having to type full path names.
This patch adds a -s option to the source command to make it search
for the script in the source search path even if the script name specifies
a directory.
For example, adding the top level source directory to the source search path
lets one load scripts from any component by only typing the path from
the top directory.
I thought of simply extending the source command to do the search anyway
but the current code explicitly doesn't do that to make "./foo" only mean
"foo" in the current directory. Granted, the comment (see openp) is
referring to executables, but it's not clear to me it shouldn't also
apply to scripts. Plus, "source /absolute/path" should probably not
scan the search path by default.
So I went with adding an option.
This patch also does a minor reorg of find_and_open_script so that
it's useful in a subsequent patch I'll be submitting.
I think the reorg is useful in itself, e.g. removing the from_tty
arg to find_and_open_script, so I've including it here.
Included are doc and testcase additions.
Ok to check in?
2010-04-06 Doug Evans <dje@google.com>
Add -s option to source command.
* cli/cli-cmds.c (find_and_open_script): Add function comment.
Delete from_tty and cleanupp args. Split filep arg into file and
full_pathp. New arg search_path.
(source_script_from_stream): New function.
(source_script_with_search): New function.
(source_script): Rewrite.
(source_command): Parse "-s" option.
(init_cli_cmds): Add "-s" docs to source command help.
* python/python.c (source_python_script): Make file arg a const char *.
Don't call fclose, leave for caller.
* python/python.h (source_python_script): Update.
testsuite/
* gdb.base/source-test.gdb: New file.
* gdb.base/source.exp: Add tests for "source -v" and "source -s".
doc/
* gdb.texinfo (Command Files): Add docs for new "source -s" option.
Index: cli/cli-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v
retrieving revision 1.98
diff -u -p -r1.98 cli-cmds.c
--- cli/cli-cmds.c 5 Mar 2010 20:18:15 -0000 1.98
+++ cli/cli-cmds.c 6 Apr 2010 21:23:23 -0000
@@ -470,62 +470,59 @@ Script filename extension recognition is
value);
}
+/* Try to open SCRIPT_FILE.
+ If successful, the full path name is stored in *FULL_PATHP,
+ the stream is stored in *STREAMP, and return 1.
+ The caller is responsible for freeing *FULL_PATHP.
+ If not successful, return 0; errno is set for the last file
+ we tried to open.
+
+ If SEARCH_PATH is non-zero, and the file isn't found in cwd,
+ search for it in the source search path.
+
+ NOTE: This calls openp which uses xfullpath to compute the full path
+ instead of gdb_realpath. Symbolic links are not resolved. */
+
static int
-find_and_open_script (int from_tty, char **filep, FILE **streamp,
- struct cleanup **cleanupp)
+find_and_open_script (const char *script_file, int search_path,
+ FILE **streamp, char **full_pathp)
{
- char *file = *filep;
- char *full_pathname = NULL;
+ char *file;
int fd;
struct cleanup *old_cleanups;
+ int search_flags = OPF_TRY_CWD_FIRST;
- file = tilde_expand (file);
+ file = tilde_expand (script_file);
old_cleanups = make_cleanup (xfree, file);
+ if (search_path)
+ search_flags |= OPF_SEARCH_IN_PATH;
+
/* Search for and open 'file' on the search path used for source
files. Put the full location in 'full_pathname'. */
- fd = openp (source_path, OPF_TRY_CWD_FIRST,
- file, O_RDONLY, &full_pathname);
- make_cleanup (xfree, full_pathname);
-
- /* Use the full path name, if it is found. */
- if (full_pathname != NULL && fd != -1)
- {
- file = full_pathname;
- }
+ fd = openp (source_path, search_flags,
+ file, O_RDONLY, full_pathp);
if (fd == -1)
{
- if (from_tty)
- perror_with_name (file);
- else
- {
- do_cleanups (old_cleanups);
- return 0;
- }
+ int save_errno = errno;
+ do_cleanups (old_cleanups);
+ errno = save_errno;
+ return 0;
}
- *streamp = fdopen (fd, FOPEN_RT);
- *filep = file;
- *cleanupp = old_cleanups;
+ do_cleanups (old_cleanups);
+ *streamp = fdopen (fd, FOPEN_RT);
return 1;
}
-void
-source_script (char *file, int from_tty)
-{
- FILE *stream;
- struct cleanup *old_cleanups;
-
- if (file == NULL || *file == 0)
- {
- error (_("source command requires file name of file to source."));
- }
-
- if (!find_and_open_script (from_tty, &file, &stream, &old_cleanups))
- return;
+/* Load script FILE, which has already been opened as STREAM.
+ STREAM is closed before we return. */
+static void
+source_script_from_stream (FILE *stream, const char *file)
+{
if (script_ext_mode != script_ext_off
&& strlen (file) > 3 && !strcmp (&file[strlen (file) - 3], ".py"))
{
@@ -541,22 +538,64 @@ source_script (char *file, int from_tty)
if (script_ext_mode == script_ext_soft
&& e.reason == RETURN_ERROR && e.error == UNSUPPORTED_ERROR)
{
- if (!find_and_open_script (from_tty, &file, &stream, &old_cleanups))
- return;
-
- script_from_file (stream, file);
+ fseek (stream, 0, SEEK_SET);
+ script_from_file (stream, (char*) file);
}
else
- /* Nope, just punt. */
- throw_exception (e);
+ {
+ /* Nope, just punt. */
+ fclose (stream);
+ throw_exception (e);
+ }
}
+ else
+ fclose (stream);
}
else
script_from_file (stream, file);
+}
+/* Worker to perform the "source" command.
+ Load script FILE.
+ If SEARCH_PATH is non-zero, and the file isn't found in cwd,
+ search for it in the source search path. */
+
+static void
+source_script_with_search (const char *file, int from_tty, int search_path)
+{
+ FILE *stream;
+ char *full_path;
+ struct cleanup *old_cleanups;
+
+ if (file == NULL || *file == 0)
+ error (_("source command requires file name of file to source."));
+
+ if (!find_and_open_script (file, search_path, &stream, &full_path))
+ {
+ /* The script wasn't found, or was otherwise inaccessible.
+ If the source command was invoked interactively, throw an error.
+ Otherwise (e.g. if it was invoked by a script), silently ignore
+ the error. */
+ if (from_tty)
+ perror_with_name (file);
+ else
+ return;
+ }
+
+ old_cleanups = make_cleanup (xfree, full_path);
+ source_script_from_stream (stream, file);
do_cleanups (old_cleanups);
}
+/* Wrapper around source_script_with_search to export it to main.c
+ for use in loading .gdbinit scripts. */
+
+void
+source_script (char *file, int from_tty)
+{
+ source_script_with_search (file, from_tty, 0);
+}
+
/* Return the source_verbose global variable to its previous state
on exit from the source command, by whatever means. */
static void
@@ -572,33 +611,52 @@ source_command (char *args, int from_tty
struct cleanup *old_cleanups;
char *file = args;
int *old_source_verbose = xmalloc (sizeof(int));
+ int search_path = 0;
*old_source_verbose = source_verbose;
old_cleanups = make_cleanup (source_verbose_cleanup, old_source_verbose);
/* -v causes the source command to run in verbose mode.
+ -s causes the file to be searched in the source search path,
+ even if the file name contains a '/'.
We still have to be able to handle filenames with spaces in a
backward compatible way, so buildargv is not appropriate. */
if (args)
{
- /* Make sure leading white space does not break the comparisons. */
- while (isspace(args[0]))
- args++;
-
- /* Is -v the first thing in the string? */
- if (args[0] == '-' && args[1] == 'v' && isspace (args[2]))
+ while (args[0] != '\0')
{
- source_verbose = 1;
+ /* Make sure leading white space does not break the comparisons. */
+ while (isspace(args[0]))
+ args++;
+
+ if (args[0] != '-')
+ break;
+
+ if (args[1] == 'v' && isspace (args[2]))
+ {
+ source_verbose = 1;
+
+ /* Skip passed -v. */
+ args = &args[3];
+ }
+ else if (args[1] == 's' && isspace (args[2]))
+ {
+ search_path = 1;
- /* Trim -v and whitespace from the filename. */
- file = &args[3];
- while (isspace (file[0]))
- file++;
+ /* Skip passed -s. */
+ args = &args[3];
+ }
+ else
+ break;
}
+
+ while (isspace (args[0]))
+ args++;
+ file = args;
}
- source_script (file, from_tty);
+ source_script_with_search (file, from_tty, search_path);
}
@@ -1379,6 +1437,8 @@ Commands defined in this way may have up
Read commands from a file named FILE.\n\
Optional -v switch (before the filename) causes each command in\n\
FILE to be echoed as it is executed.\n\
+Optional -s switch (before the filename) causes gdb to search for\n\
+the script in the source search path, even if FILE contains directories.\n\
Note that the file \"%s\" is read automatically in this way\n\
when GDB is started."), gdbinit);
c = add_cmd ("source", class_support, source_command,
Index: python/python.c
===================================================================
RCS file: /cvs/src/src/gdb/python/python.c,v
retrieving revision 1.27
diff -u -p -r1.27 python.c
--- python/python.c 5 Mar 2010 20:18:17 -0000 1.27
+++ python/python.c 6 Apr 2010 21:23:24 -0000
@@ -362,10 +362,11 @@ gdbpy_parse_and_eval (PyObject *self, Py
}
/* Read a file as Python code. STREAM is the input file; FILE is the
- name of the file. */
+ name of the file.
+ STREAM is not closed, that is the caller's responsibility. */
void
-source_python_script (FILE *stream, char *file)
+source_python_script (FILE *stream, const char *file)
{
PyGILState_STATE state;
@@ -373,7 +374,6 @@ source_python_script (FILE *stream, char
PyRun_SimpleFile (stream, file);
- fclose (stream);
PyGILState_Release (state);
}
@@ -560,9 +560,8 @@ eval_python_from_control_command (struct
}
void
-source_python_script (FILE *stream, char *file)
+source_python_script (FILE *stream, const char *file)
{
- fclose (stream);
throw_error (UNSUPPORTED_ERROR,
_("Python scripting is not supported in this copy of GDB."));
}
Index: python/python.h
===================================================================
RCS file: /cvs/src/src/gdb/python/python.h,v
retrieving revision 1.7
diff -u -p -r1.7 python.h
--- python/python.h 18 Jan 2010 06:25:22 -0000 1.7
+++ python/python.h 6 Apr 2010 21:23:24 -0000
@@ -24,7 +24,7 @@
void eval_python_from_control_command (struct command_line *);
-void source_python_script (FILE *stream, char *file);
+void source_python_script (FILE *stream, const char *file);
int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
Index: testsuite/gdb.base/source-test.gdb
===================================================================
RCS file: testsuite/gdb.base/source-test.gdb
diff -N testsuite/gdb.base/source-test.gdb
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/source-test.gdb 6 Apr 2010 21:23:24 -0000
@@ -0,0 +1,20 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test GDB's "source -v" and "source -s" commands.
+
+echo test source options\n
Index: testsuite/gdb.base/source.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/source.exp,v
retrieving revision 1.9
diff -u -p -r1.9 source.exp
--- testsuite/gdb.base/source.exp 7 Jan 2010 20:07:18 -0000 1.9
+++ testsuite/gdb.base/source.exp 6 Apr 2010 21:23:24 -0000
@@ -34,5 +34,14 @@ gdb_start
gdb_test "source ${srcdir}/${subdir}/source-error.gdb" \
"source-error.gdb:21: Error in sourced command file:\[\r\n\]*Cannot access memory at address 0x0.*" \
"script contains error"
+
+gdb_test "source -v ${srcdir}/${subdir}/source-test.gdb" \
+ "echo test source options.*" \
+ "source -v"
+
+gdb_test "dir ${srcdir}/${subdir}" ""
+gdb_test "source -s ./source-test.gdb" \
+ "test source options" \
+ "source -s"
gdb_exit
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.696
diff -u -p -r1.696 gdb.texinfo
--- doc/gdb.texinfo 5 Apr 2010 17:14:57 -0000 1.696
+++ doc/gdb.texinfo 6 Apr 2010 21:28:53 -0000
@@ -19373,7 +19373,7 @@ using the @code{script-extension} settin
@table @code
@kindex source
@cindex execute commands from a file
-@item source [@code{-v}] @var{filename}
+@item source [@code{-s}] [@code{-v}] @var{filename}
Execute the command file @var{filename}.
@end table
@@ -19390,6 +19390,9 @@ directory, then @value{GDBN} also looks
except that @file{$cdir} is not searched because the compilation directory
is not relevant to scripts.
+If @code{-s} is specified, then @value{GDBN} searches for @var{filename}
+on the search path even if @var{filename} specifies a directory.
+
If @code{-v}, for verbose mode, is given then @value{GDBN} displays
each command as it is executed. The option must be given before
@var{filename}, and is interpreted as part of the filename anywhere else.