From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4429 invoked by alias); 6 Apr 2010 21:58:07 -0000 Received: (qmail 4408 invoked by uid 22791); 6 Apr 2010 21:58:02 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_PASS,TW_RG,T_FILL_THIS_FORM_SHORT,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 06 Apr 2010 21:57:55 +0000 Received: from wpaz21.hot.corp.google.com (wpaz21.hot.corp.google.com [172.24.198.85]) by smtp-out.google.com with ESMTP id o36Lvqui017159 for ; Tue, 6 Apr 2010 14:57:52 -0700 Received: from ruffy.mtv.corp.google.com (ruffy.mtv.corp.google.com [172.18.118.116]) by wpaz21.hot.corp.google.com with ESMTP id o36LvpSv022025 for ; Tue, 6 Apr 2010 14:57:52 -0700 Received: by ruffy.mtv.corp.google.com (Postfix, from userid 67641) id 7EC1784397; Tue, 6 Apr 2010 14:57:51 -0700 (PDT) To: gdb-patches@sourceware.org Subject: [RFA] Add -s option to source command. Message-Id: <20100406215751.7EC1784397@ruffy.mtv.corp.google.com> Date: Tue, 06 Apr 2010 21:58:00 -0000 From: dje@google.com (Doug Evans) X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-04/txt/msg00110.txt.bz2 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 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 . + +# 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.