From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) by sourceware.org (Postfix) with ESMTPS id B64F43858D1E for ; Mon, 30 Jan 2023 14:53:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B64F43858D1E Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wr1-f51.google.com with SMTP id t7so2966757wrp.5 for ; Mon, 30 Jan 2023 06:53:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:content-language:in-reply-to:mime-version :user-agent:date:message-id:from:references:to:subject :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=MNUteSdbvNnvG4KqiqI/YI2w89Pmh9/5CDHZiLQn+EU=; b=Vweh4LaK5263A1zog0Nkrg1045VWcplbL1RCYpJ3R+ahBH3s7/ktK29aknGByLEmnT bTmOQmtXPiqtY5augaYDaoje89EQqiiH9SgqCIau3AnR1B6GQumlWntCWeWeajLkBrAI zLXEJbQslZXorvQ/netQHE8jFg07olvG/yyVwVw5Cq9ejkC6XNoAx4qmWZer9UOqfUHy QZonPIAMq9EuoFf7TIxPcKPqy0vhy3DY2RzzHjR6sPXkHASi5CsoBf1M+p3MSp4H+BNi E6g9vwQknLhSFT+sAe+s9yBJpQmUSbkfb1BApz+yqvPnppmPTjdsxuHelH2REurpvqqq 5Dqw== X-Gm-Message-State: AFqh2kqejDKJCawqOHQI1canh8Qw8t3d2rAgZSdgF35/XqMQcOYKMYdd 0aLY2eCLZ4EoAbRxZoO/5pBqnvcrq0TKBA== X-Google-Smtp-Source: AMrXdXsTKj8CMq6oAA1Z5mGoLa1M9faArB5Sh5IHHOpAENMiMRdy0fPK5U3GwZlDK2PUaIUBUCcUuQ== X-Received: by 2002:adf:fa43:0:b0:2bd:c225:1fe8 with SMTP id y3-20020adffa43000000b002bdc2251fe8mr44328317wrr.14.1675090435263; Mon, 30 Jan 2023 06:53:55 -0800 (PST) Received: from ?IPv6:2001:8a0:f92b:9e00::1fe? ([2001:8a0:f92b:9e00::1fe]) by smtp.gmail.com with ESMTPSA id g8-20020adfe408000000b002bdda9856b5sm12244038wrm.50.2023.01.30.06.53.54 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 30 Jan 2023 06:53:54 -0800 (PST) Subject: Re: [PATCH 3/5] Add "save user" command To: Tom Tromey , gdb-patches@sourceware.org References: <20230129162105.526266-1-tom@tromey.com> <20230129162105.526266-4-tom@tromey.com> From: Pedro Alves Message-ID: <1daf98a0-8568-8eac-310f-8688a611677d@palves.net> Date: Mon, 30 Jan 2023 14:53:53 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.10.1 MIME-Version: 1.0 In-Reply-To: <20230129162105.526266-4-tom@tromey.com> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,KAM_DMARC_STATUS,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 2023-01-29 4:21 p.m., Tom Tromey wrote: > PR cli/19395 points out that it would sometimes be convenient to save > one's user-defined commands to a file. This patch implements this > feature. > > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=19395 Could we have a testcase for this? Pedro Alves > --- > gdb/NEWS | 3 ++ > gdb/cli/cli-cmds.c | 72 +++++++++++++++++++++++++++++++++++++-------- > gdb/doc/gdb.texinfo | 6 ++++ > 3 files changed, 68 insertions(+), 13 deletions(-) > > diff --git a/gdb/NEWS b/gdb/NEWS > index 2bc1672632a..3b7d768732c 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -17,6 +17,9 @@ maintenance print record-instruction [ N ] > prints how GDB would undo the N-th previous instruction, and if N is > positive, it prints how GDB will redo the N-th following instruction. > > +save user FILENAME > + Save all user-defined commands to the given file. > + > * MI changes > > ** mi now reports 'no-history' as a stop reason when hitting the end of the > diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c > index 61f890a7dae..3f488d1a544 100644 > --- a/gdb/cli/cli-cmds.c > +++ b/gdb/cli/cli-cmds.c > @@ -51,6 +51,7 @@ > #include "cli/cli-style.h" > #include "cli/cli-utils.h" > #include "cli/cli-style.h" > +#include "cli-out.h" > > #include "extension.h" > #include "gdbsupport/pathstuff.h" > @@ -1646,24 +1647,41 @@ make_command (const char *arg, int from_tty) > /* Print the definition of user command C to STREAM. Or, if C is a > prefix command, show the definitions of all user commands under C > (recursively). PREFIX and NAME combined are the name of the > - current command. */ > + current command. DEF is true if the output should be written as a > + source-able script. */ > static void > show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name, > - struct ui_file *stream) > + struct ui_file *stream, struct ui_out *uiout, bool def) > { > if (cli_user_command_p (c)) > { > struct command_line *cmdlines = c->user_commands.get (); > > - gdb_printf (stream, "User %scommand \"", > - c->is_prefix () ? "prefix" : ""); > - fprintf_styled (stream, title_style.style (), "%s%s", > - prefix, name); > - gdb_printf (stream, "\":\n"); > + if (def) > + gdb_printf (stream, "define%s %s%s\n", > + c->is_prefix () ? "-prefix" : "", > + prefix, name); > + else > + { > + gdb_printf (stream, "User %scommand \"", > + c->is_prefix () ? "prefix" : ""); > + fprintf_styled (stream, title_style.style (), "%s%s", > + prefix, name); > + gdb_printf (stream, "\":\n"); > + } > if (cmdlines) > { > - print_command_lines (current_uiout, cmdlines, 1); > - gdb_puts ("\n", stream); > + print_command_lines (uiout, cmdlines, 1); > + if (!def) > + gdb_puts ("\n", stream); > + } > + if (def) > + { > + gdb_puts ("end\n", stream); > + > + if (!c->is_prefix () && !streq (c->doc, "User-defined.")) > + gdb_printf (stream, "document %s%s\n%s\nend\n", > + prefix, name, c->doc); > } > } > > @@ -1673,9 +1691,8 @@ show_user_1 (struct cmd_list_element *c, const char *prefix, const char *name, > > for (c = *c->subcommands; c != NULL; c = c->next) > if (c->theclass == class_user || c->is_prefix ()) > - show_user_1 (c, prefixname.c_str (), c->name, gdb_stdout); > + show_user_1 (c, prefixname.c_str (), c->name, stream, uiout, def); > } > - > } > > static void > @@ -1690,18 +1707,40 @@ show_user (const char *args, int from_tty) > c = lookup_cmd (&comname, cmdlist, "", NULL, 0, 1); > if (!cli_user_command_p (c)) > error (_("Not a user command.")); > - show_user_1 (c, "", args, gdb_stdout); > + show_user_1 (c, "", args, gdb_stdout, current_uiout, false); > } > else > { > for (c = cmdlist; c; c = c->next) > { > if (cli_user_command_p (c) || c->is_prefix ()) > - show_user_1 (c, "", c->name, gdb_stdout); > + show_user_1 (c, "", c->name, gdb_stdout, current_uiout, false); > } > } > } > > +/* The "save user" command. */ > + > +static void > +save_user_command (const char *filename, int from_tty) > +{ > + if (filename == nullptr || *filename == '\0') > + error (_("Argument required (file name in which to save)")); > + > + gdb::unique_xmalloc_ptr expanded_filename (tilde_expand (filename)); > + stdio_file fp; > + if (!fp.open (expanded_filename.get (), "w")) > + error (_("Unable to open file '%s' for saving (%s)"), > + expanded_filename.get (), safe_strerror (errno)); > + > + cli_ui_out uiout (&fp); > + for (struct cmd_list_element *c = cmdlist; c != nullptr; c = c->next) > + { > + if (cli_user_command_p (c) || c->is_prefix ()) > + show_user_1 (c, "", c->name, &fp, &uiout, true); > + } > +} > + > /* Return true if COMMAND or any of its sub-commands is a user defined command. > This is a helper function for show_user_completer. */ > > @@ -2762,6 +2801,13 @@ Usage: apropos [-v] REGEXP\n\ > Flag -v indicates to produce a verbose output, showing full documentation\n\ > of the matching commands.")); > > + c = add_cmd ("user", no_class, save_user_command, _("\ > +Save current user-defined commands as a script.\n\ > +Usage: save user FILE\n\ > +Use the 'source' command in another debug session to restore them."), > + &save_cmdlist); > + set_cmd_completer (c, filename_completer); > + > add_setshow_uinteger_cmd ("max-user-call-depth", no_class, > &max_user_call_depth, _("\ > Set the max call depth for non-python/scheme user-defined commands."), _("\ > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index b5fad2cb16e..37db4785fd2 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -28230,6 +28230,12 @@ The value of @code{max-user-call-depth} controls how many recursion > levels are allowed in user-defined commands before @value{GDBN} suspects an > infinite recursion and aborts the command. > This does not apply to user-defined python commands. > + > +@kindex save user > +@item save user @var{filename} > +Save all user-defined commands to the file @var{filename}. This > +command writes out the user-defined commands as a script that can be > +re-read into @value{GDBN} using the @code{source} command. > @end table > > In addition to the above commands, user-defined commands frequently >