public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v5 0/8] gdb: split array and string limiting options
@ 2022-03-30 10:23 Maciej W. Rozycki
  2022-03-30 10:23 ` [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages Maciej W. Rozycki
                   ` (18 more replies)
  0 siblings, 19 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:23 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

Hi,

 Sadly I have received no feedback for v4 of the series other than the 
docs (thank you, Eli!), so here is v5 with the documentation parts updated 
only for Andrew's original proposal to split the `set/show print elements' 
options into two, so that there are separate `set/show print characters' 
options to control how many characters of a string are printed.

 Following earlier discussion for compatibility with existing setups I 
have implemented a mechanism to make the `set print characters' setting 
follow that of `set print elements' by default.  Consequently what was a 
single change has now grown into a patch series.

 In this series I fix some preexisting issues in the area first, implement 
the general framework for extra literals used with integer settings second 
and then add the original change for `set print characters' from Andrew, 
adjusted accordingly, followed by a testsuite update as a separate change. 
This is so as to ensure the semantics of the existing `set print elements' 
knob hasn't changed in the default `set print characters' state (a small 
update for the test suite is nevertheless included with the `set print 
characters' command proper, because inevitably the relevant commands that 
list commands now print additional entries, plus there's been a minimal 
test case update included for the verification of setting defaults).

 Since I have noticed some v4 hunks to apply with significant line number 
changes (meaning larger code rearrangements) and also Python 2 support to 
have been removed (my original builds used it) I have re-regression-tested 
the changes (with the build switched to Python 3), again with a native 
`x86_64-linux-gnu' configuration.  I have also visually examined the 
result of the updated changes to the GDB manual in the info and PDF 
formats.

 See individual change descriptions for details.

 OK to apply?

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
@ 2022-03-30 10:23 ` Maciej W. Rozycki
  2022-06-24 14:32   ` Andrew Burgess
  2022-03-30 10:23 ` [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited' Maciej W. Rozycki
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:23 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

With errors given for bad commands such as `set annotate' or `set width' 
we produce an extraneous full stop within parentheses:

(gdb) set annotate
Argument required (integer to set it to.).
(gdb) set width
Argument required (integer to set it to, or "unlimited".).
(gdb)

This is grammatically incorrect, so remove the full stop and adjust the 
testsuite accordingly.
---
No change from v4.

New change in v4.
---
 gdb/cli/cli-setshow.c           |   10 +++++-----
 gdb/testsuite/gdb.base/with.exp |    8 ++++----
 2 files changed, 9 insertions(+), 9 deletions(-)

gdb-parse-cli-var-integer-msg-stop.diff
Index: src/gdb/cli/cli-setshow.c
===================================================================
--- src.orig/gdb/cli/cli-setshow.c
+++ src/gdb/cli/cli-setshow.c
@@ -195,9 +195,9 @@ parse_cli_var_uinteger (var_types var_ty
   if (*arg == nullptr || **arg == '\0')
     {
       if (var_type == var_uinteger)
-	error_no_arg (_("integer to set it to, or \"unlimited\"."));
+	error_no_arg (_("integer to set it to, or \"unlimited\""));
       else
-	error_no_arg (_("integer to set it to."));
+	error_no_arg (_("integer to set it to"));
     }
 
   if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
@@ -228,7 +228,7 @@ parse_cli_var_zuinteger_unlimited (const
   LONGEST val;
 
   if (*arg == nullptr || **arg == '\0')
-    error_no_arg (_("integer to set it to, or \"unlimited\"."));
+    error_no_arg (_("integer to set it to, or \"unlimited\""));
 
   if (is_unlimited_literal (arg, expression))
     val = -1;
@@ -418,9 +418,9 @@ do_set_command (const char *arg, int fro
 	if (*arg == '\0')
 	  {
 	    if (c->var->type () == var_integer)
-	      error_no_arg (_("integer to set it to, or \"unlimited\"."));
+	      error_no_arg (_("integer to set it to, or \"unlimited\""));
 	    else
-	      error_no_arg (_("integer to set it to."));
+	      error_no_arg (_("integer to set it to"));
 	  }
 
 	if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
Index: src/gdb/testsuite/gdb.base/with.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/with.exp
+++ src/gdb/testsuite/gdb.base/with.exp
@@ -99,14 +99,14 @@ with_test_prefix "maint" {
     test_with_error "boolean" "2" "\"on\" or \"off\" expected\\."
     test_with_error "uinteger" "-1" "integer -1 out of range"
     test_with_error "uinteger" "" \
-	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
     test_with_error "zuinteger" "-1" "integer -1 out of range"
     test_with_error "zuinteger" "" \
-	"Argument required \\(integer to set it to\\.\\)\\."
+	"Argument required \\(integer to set it to\\)\\."
     test_with_error "zuinteger-unlimited" "-2" \
 	"only -1 is allowed to set as unlimited"
     test_with_error "zuinteger-unlimited" "" \
-	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
     test_with_error "filename" "" \
 	"Argument required \\(filename to set it to\\.\\)\\."
     test_with_error "enum" "" \
@@ -243,7 +243,7 @@ with_test_prefix "errors" {
 	"Cannot use this setting with the \"with\" command"
 
     gdb_test "with print elements -- p 1" \
-	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
+	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
 
     gdb_test "with -- p 1" \
 	"Missing setting before '--' delimiter"

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
  2022-03-30 10:23 ` [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages Maciej W. Rozycki
@ 2022-03-30 10:23 ` Maciej W. Rozycki
  2022-03-30 10:35   ` Simon Sobisch
  2022-06-24 14:40   ` Andrew Burgess
  2022-03-30 10:24 ` [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands Maciej W. Rozycki
                   ` (16 subsequent siblings)
  18 siblings, 2 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:23 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

Consistently with the `var_integer' and `var_uinteger' parameters return 
the special value of None for a `var_zuinteger_unlimited' parameter set 
to `unlimited' by using the Py_RETURN_NONE macro in this case, fixing 
commit 0489430a0e1a ("Handle var_zuinteger and var_zuinteger_unlimited 
from Python"); cf. PR python/20084.  Adjust the testsuite accordingly. 
---
No change from v4.

New change in v4.
---
 gdb/python/python.c                       |   10 +++++++++-
 gdb/testsuite/gdb.python/py-parameter.exp |    4 ++--
 2 files changed, 11 insertions(+), 3 deletions(-)

gdb-python-var-zuinteger-unlimited-none.diff
Index: src/gdb/python/python.c
===================================================================
--- src.orig/gdb/python/python.c
+++ src/gdb/python/python.c
@@ -507,9 +507,17 @@ gdbpy_parameter_value (const setting &va
 	Py_RETURN_NONE;
       /* Fall through.  */
     case var_zinteger:
-    case var_zuinteger_unlimited:
       return gdb_py_object_from_longest (var.get<int> ()).release ();
 
+    case var_zuinteger_unlimited:
+      {
+	int val = var.get<int> ();
+
+	if (val == -1)
+	  Py_RETURN_NONE;
+	return gdb_py_object_from_longest (val).release ();
+      }
+
     case var_uinteger:
       {
 	unsigned int val = var.get<unsigned int> ();
Index: src/gdb/testsuite/gdb.python/py-parameter.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-parameter.exp
+++ src/gdb/testsuite/gdb.python/py-parameter.exp
@@ -343,8 +343,8 @@ proc_with_prefix test_integer_parameter
 	} elseif {$kind == "PARAM_ZUINTEGER_UNLIMITED"} {
 	    gdb_test_no_output "python test_param_$kind.value = -1" \
 		"check that PARAM_ZUINTEGER value can be set to -1"
-	    gdb_test "python print(gdb.parameter('test-$kind'))" "-1" \
-		"check that PARAM_ZUINTEGER value is -1 after setting"
+	    gdb_test "python print(gdb.parameter('test-$kind'))" "None" \
+		"check that PARAM_ZUINTEGER value is None after setting"
 	} else {
 	    error "invalid kind: $kind"
 	}

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
  2022-03-30 10:23 ` [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages Maciej W. Rozycki
  2022-03-30 10:23 ` [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited' Maciej W. Rozycki
@ 2022-03-30 10:24 ` Maciej W. Rozycki
  2022-05-25 18:36   ` Bruno Larsen
  2022-06-24 15:08   ` Andrew Burgess
  2022-03-30 10:24 ` [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check Maciej W. Rozycki
                   ` (15 subsequent siblings)
  18 siblings, 2 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

Fix a completion consistency issue with `set' commands accepting integer 
values and the special `unlimited' keyword:

(gdb) complete print -elements
print -elements NUMBER
print -elements unlimited
(gdb)

vs:

(gdb) complete set print elements
set print elements unlimited
(gdb)

(there is a space entered at the end of both commands, not shown here) 
which also means if you strike <Tab> with `set print elements ' input, 
it will, annoyingly, complete to `set print elements unlimited' right 
away rather than showing a choice between `NUMBER' and `unlimited'.

Add `NUMBER' then as an available completion for such `set' commands:

(gdb) complete set print elements
set print elements NUMBER
set print elements unlimited
(gdb)
  
Adjust the testsuite accordingly.
---
No change from v4.

New change in v4.
---
 gdb/cli/cli-decode.c                |    2 ++
 gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

gdb-integer-complete-number.diff
Index: src/gdb/cli/cli-decode.c
===================================================================
--- src.orig/gdb/cli/cli-decode.c
+++ src/gdb/cli/cli-decode.c
@@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
       NULL,
     };
 
+  if (*text == '\0')
+    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
   complete_on_enum (tracker, keywords, text, word);
 }
 
Index: src/gdb/testsuite/gdb.base/settings.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/settings.exp
+++ src/gdb/testsuite/gdb.base/settings.exp
@@ -215,8 +215,14 @@ proc test-integer {variant} {
 	test_gdb_complete_none \
 	    "$set_cmd "
     } else {
+	test_gdb_complete_multiple "$set_cmd " "" "" {
+	    "NUMBER"
+	    "unlimited"
+	}
+	test_gdb_complete_none \
+	    "$set_cmd 1"
 	test_gdb_complete_unique \
-	    "$set_cmd " \
+	    "$set_cmd u" \
 	    "$set_cmd unlimited"
     }
 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (2 preceding siblings ...)
  2022-03-30 10:24 ` [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands Maciej W. Rozycki
@ 2022-03-30 10:24 ` Maciej W. Rozycki
  2022-06-24 15:09   ` Andrew Burgess
  2022-03-30 10:24 ` [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command Maciej W. Rozycki
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

Match the whole error message expected to be given rather than omitting 
the part about the "unlimited" keyword.  There's no point in omitting 
the missing part first, and second with an upcoming change the part in 
parentheses will no longer be a fixed string, so doing a full match will 
ensure the algorithm correctly builds the message expected here.  Also 
avoid any wildcard matches.
---
No change from v4.

New change in v4.
---
 gdb/testsuite/gdb.base/default.exp |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

gdb-test-set-print-elements-tightening.diff
Index: src/gdb/testsuite/gdb.base/default.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/default.exp
+++ src/gdb/testsuite/gdb.base/default.exp
@@ -525,7 +525,8 @@ gdb_test_no_output "set print asm-demang
 #test set print demangle
 gdb_test_no_output "set print demangle" "set print demangle"
 #test set print elements
-gdb_test "set print elements" "Argument required .integer to set it to.*"
+gdb_test "set print elements" \
+	 "Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
 #test set print object
 gdb_test_no_output "set print object" "set print object"
 #test set print pretty

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (3 preceding siblings ...)
  2022-03-30 10:24 ` [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check Maciej W. Rozycki
@ 2022-03-30 10:24 ` Maciej W. Rozycki
  2022-06-24 15:57   ` Andrew Burgess
  2022-03-30 10:24 ` [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands Maciej W. Rozycki
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

We currently have no coverage for the `print -elements ...' command (or 
`p -elements ...' in the shortened form), so add a couple of test cases 
mimicking ones using corresponding `set print elements ...' values.
---
No change from v4.

New change in v4.
---
 gdb/testsuite/gdb.base/printcmds.exp |    9 +++++++++
 1 file changed, 9 insertions(+)

gdb-test-printcmd-options.diff
Index: src/gdb/testsuite/gdb.base/printcmds.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/printcmds.exp
+++ src/gdb/testsuite/gdb.base/printcmds.exp
@@ -538,6 +538,15 @@ proc test_print_strings {} {
     gdb_test "p teststring" \
 	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 20"
 
+    gdb_test "p -elements 1 -- teststring" \
+	" = (.unsigned char .. )?\"t\"\\.\\.\\."
+    gdb_test "p -elements 5 -- teststring" \
+	" = (.unsigned char .. )?\"tests\"\\.\\.\\."
+    gdb_test "p -elements 19 -- teststring" \
+	" = (.unsigned char .. )?\"teststring contents\""
+    gdb_test "p -elements 20 -- teststring" \
+	" = (.unsigned char .. )?\"teststring contents\""
+
     gdb_test "print teststring2" \
 	" = \\(charptr\\) \"more contents\""
 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (4 preceding siblings ...)
  2022-03-30 10:24 ` [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command Maciej W. Rozycki
@ 2022-03-30 10:24 ` Maciej W. Rozycki
  2022-03-30 10:42   ` Simon Sobisch
  2022-06-28 14:04   ` Andrew Burgess
  2022-03-30 10:24 ` [PATCH v5 7/8] GDB: Add a character string limiting option Maciej W. Rozycki
                   ` (12 subsequent siblings)
  18 siblings, 2 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

Rather than just `unlimited' allow the integer set commands (or command 
options) to define arbitrary keywords for the user to use, removing 
hardcoded arrangements for the `unlimited' keyword.

Make obsolete the confusingly named `var_zinteger', `var_zuinteger' and 
`var_zuinteger_unlimited' `set'/`show' command variable types redefining 
them in terms of `var_uinteger', `var_integer' and `var_pinteger', which 
have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.

Following existing practice `var_pinteger' allows extra negative values 
to be used, however unlike `var_zuinteger_unlimited' any number of such 
values can be defined rather than just `-1'.

The "p" in `var_pinteger' stands for "positive", for the lack of a more 
appropriate unambiguous letter, even though 0 obviously is not positive; 
"n" would be confusing as to whether it stands for "non-negative" or 
"negative".

Add a new structure, `literal_def', the entries of which define extra 
keywords allowed for a command and numerical values they correspond to.  
Those values are not verified against the basic range supported by the 
underlying variable type, allowing extra values to be allowed outside 
that range, which may or may not be individually made visible to the 
user.  An optional value translation is possible with the structure to 
follow the existing practice for some commands where user-entered 0 is 
internally translated to UINT_MAX or INT_MAX.  Such translation can now 
be arbitrary.  Literals defined by this structure are automatically used 
for completion as necessary.

So for example:

const literal_def integer_unlimited_literals[] =
  {
    { "unlimited", 0, INT_MAX, true },
    { nullptr }
  };

defines an extra `unlimited' keyword and a user-visible 0 value, both of 
which get translated to INT_MAX for the setting to be used with.

Similarly:

const literal_def zuinteger_unlimited_literals[] =
  {
    { "unlimited", -1, -1, true },
    { nullptr }
  };

defines the same keyword and a corresponding user-visible -1 value that is 
used for the requested setting.  If the last member was set to `false' 
here, then only the keyword would be allowed for the user to enter and 
while -1 would still be used internally trying to enter it as a part of a 
command would result in an "integer -1 out of range" error.

The obsolete command variable types still remain for Guile and Python 
use.  Eventually they need to be removed, however that would require a 
further rework of our Guile and Python support code.  Given that these 
variable types have been exported as keywords for those languages, those 
definitions have to stay, however it would be better to redefine them in 
terms of the modern variable types and overall export a better interface 
that reflects the flexibility of our core code now.

There is no user-visible change from this rework, so no documentation or
testsuite updates.
---
Hi,

 NB I have observed that the value of INT_MIN is not correctly handled: 
internally -2147483648 is interpreted as 2147483648 and consequently such 
a value is rejected, e.g:

(gdb) show heuristic-fence-post
The distance searched for the start of a function is 0.
(gdb) set heuristic-fence-post -2147483647
(gdb) show heuristic-fence-post
The distance searched for the start of a function is -2147483647.
(gdb) set heuristic-fence-post -2147483648
integer 2147483648 out of range
(gdb)

umm... (not that it makes sense to set negative values for the heuristic 
fence post, but that's irrelevant here).  I haven't tried to track the 
root cause for this.

  Maciej

No change from v4.

New change in v4.
---
 gdb/cli/cli-cmds.c       |   56 ++++----
 gdb/cli/cli-decode.c     |  302 ++++++++++++++++++++++++++++++++++++++---------
 gdb/cli/cli-option.c     |  116 +++++++++++-------
 gdb/cli/cli-option.h     |   34 +++--
 gdb/cli/cli-setshow.c    |  249 ++++++++++++++++++--------------------
 gdb/cli/cli-setshow.h    |   20 +--
 gdb/command.h            |  108 ++++++++++++++--
 gdb/guile/scm-param.c    |  102 +++++++++------
 gdb/maint-test-options.c |    4 
 gdb/python/py-param.c    |   39 ++++--
 gdb/python/python.c      |   49 +++----
 gdb/valprint.c           |    9 -
 12 files changed, 716 insertions(+), 372 deletions(-)

gdb-setshow-cmd-extra-literals.diff
Index: src/gdb/cli/cli-cmds.c
===================================================================
--- src.orig/gdb/cli/cli-cmds.c
+++ src/gdb/cli/cli-cmds.c
@@ -2200,22 +2200,37 @@ value_from_setting (const setting &var,
 {
   switch (var.type ())
     {
+    case var_uinteger:
     case var_integer:
-      if (var.get<int> () == INT_MAX)
-	return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				   0);
-      else
-	return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				   var.get<int> ());
-    case var_zinteger:
-      return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				 var.get<int> ());
+    case var_pinteger:
+      {
+	LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
+
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		value = l->val;
+		break;
+	      }
+
+	if (var.type () == var_uinteger)
+	  return
+	    value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
+				 static_cast<const unsigned int> (value));
+	else
+	  return
+	    value_from_longest (builtin_type (gdbarch)->builtin_int,
+				static_cast<const int> (value));
+      }
     case var_boolean:
       return value_from_longest (builtin_type (gdbarch)->builtin_int,
 				 var.get<bool> () ? 1 : 0);
-    case var_zuinteger_unlimited:
-      return value_from_longest (builtin_type (gdbarch)->builtin_int,
-				 var.get<int> ());
     case var_auto_boolean:
       {
 	int val;
@@ -2237,17 +2252,6 @@ value_from_setting (const setting &var,
 	return value_from_longest (builtin_type (gdbarch)->builtin_int,
 				   val);
       }
-    case var_uinteger:
-      if (var.get<unsigned int> () == UINT_MAX)
-	return value_from_ulongest
-	  (builtin_type (gdbarch)->builtin_unsigned_int, 0);
-      else
-	return value_from_ulongest
-	  (builtin_type (gdbarch)->builtin_unsigned_int,
-	   var.get<unsigned int> ());
-    case var_zuinteger:
-      return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
-				  var.get<unsigned int> ());
     case var_string:
     case var_string_noescape:
     case var_optional_filename:
@@ -2317,13 +2321,11 @@ str_value_from_setting (const setting &v
 {
   switch (var.type ())
     {
+    case var_uinteger:
     case var_integer:
-    case var_zinteger:
+    case var_pinteger:
     case var_boolean:
-    case var_zuinteger_unlimited:
     case var_auto_boolean:
-    case var_uinteger:
-    case var_zuinteger:
       {
 	std::string cmd_val = get_setshow_command_value_string (var);
 
Index: src/gdb/cli/cli-decode.c
===================================================================
--- src.orig/gdb/cli/cli-decode.c
+++ src/gdb/cli/cli-decode.c
@@ -580,11 +580,51 @@ add_setshow_cmd_full_erased (const char
   return {set, show};
 }
 
+/* Completes on integer commands that support extra literals.  */
+
+static void
+integer_literals_completer (struct cmd_list_element *c,
+			    completion_tracker &tracker,
+			    const char *text, const char *word)
+{
+  const literal_def *extra_literals = c->var->extra_literals ();
+
+  if (*text == '\0')
+    {
+      tracker.add_completion (make_unique_xstrdup ("NUMBER"));
+      for (const literal_def *l = extra_literals;
+	   l->literal != nullptr;
+	   l++)
+	tracker.add_completion (make_unique_xstrdup (l->literal));
+    }
+  else
+    for (const literal_def *l = extra_literals;
+	 l->literal != nullptr;
+	 l++)
+      if (startswith (l->literal, text))
+	tracker.add_completion (make_unique_xstrdup (l->literal));
+}
+
+/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
+   THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are
+   setting.  VAR is address of the variable being controlled by this
+   command.  EXTRA_LITERALS if non-NULL define extra literals to be
+   accepted in lieu of a number for integer variables.  If nullptr is
+   given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must
+   be provided. SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks
+   used to access and modify the underlying property, whatever its
+   storage is.  SET_FUNC and SHOW_FUNC are the callback functions
+   (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the
+   documentation strings.
+
+   Return the newly created set and show commands.  */
+
 template<typename T>
 static set_show_commands
 add_setshow_cmd_full (const char *name,
 		      enum command_class theclass,
 		      var_types var_type, T *var,
+		      const literal_def *extra_literals,
 		      const char *set_doc, const char *show_doc,
 		      const char *help_doc,
 		      typename setting_func_types<T>::set set_setting_func,
@@ -595,18 +635,44 @@ add_setshow_cmd_full (const char *name,
 		      struct cmd_list_element **show_list)
 {
   auto erased_args
-    = setting::erase_args (var_type, var,
+    = setting::erase_args (var_type, var, extra_literals,
 			   set_setting_func, get_setting_func);
+  auto cmds = add_setshow_cmd_full_erased (name,
+					   theclass,
+					   var_type, erased_args,
+					   set_doc, show_doc,
+					   help_doc,
+					   set_func,
+					   show_func,
+					   set_list,
+					   show_list);
 
-  return add_setshow_cmd_full_erased (name,
-				      theclass,
-				      var_type, erased_args,
-				      set_doc, show_doc,
-				      help_doc,
-				      set_func,
-				      show_func,
-				      set_list,
-				      show_list);
+  if (extra_literals != nullptr)
+    set_cmd_completer (cmds.set, integer_literals_completer);
+
+  return cmds;
+}
+
+/* Same as above but omitting EXTRA_LITERALS.  */
+
+template<typename T>
+static set_show_commands
+add_setshow_cmd_full (const char *name,
+		      enum command_class theclass,
+		      var_types var_type, T *var,
+		      const char *set_doc, const char *show_doc,
+		      const char *help_doc,
+		      typename setting_func_types<T>::set set_setting_func,
+		      typename setting_func_types<T>::get get_setting_func,
+		      cmd_func_ftype *set_func,
+		      show_value_ftype *show_func,
+		      struct cmd_list_element **set_list,
+		      struct cmd_list_element **show_list)
+{
+  return add_setshow_cmd_full (name, theclass, var_type, var, nullptr,
+			       set_doc, show_doc, help_doc,
+			       set_setting_func, get_setting_func,
+			       set_func, show_func, set_list, show_list);
 }
 
 /* Add element named NAME to command list LIST (the list for set or
@@ -975,25 +1041,6 @@ add_setshow_optional_filename_cmd (const
   return cmds;
 }
 
-/* Completes on literal "unlimited".  Used by integer commands that
-   support a special "unlimited" value.  */
-
-static void
-integer_unlimited_completer (struct cmd_list_element *ignore,
-			     completion_tracker &tracker,
-			     const char *text, const char *word)
-{
-  static const char * const keywords[] =
-    {
-      "unlimited",
-      NULL,
-    };
-
-  if (*text == '\0')
-    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
-  complete_on_enum (tracker, keywords, text, word);
-}
-
 /* Add element named NAME to both the set and show command LISTs (the
    list for set/show or some sublist thereof).  CLASS is as in
    add_cmd.  VAR is address of the variable which will contain the
@@ -1002,6 +1049,55 @@ integer_unlimited_completer (struct cmd_
 
 set_show_commands
 add_setshow_integer_cmd (const char *name, enum command_class theclass,
+			 int *var, const literal_def *extra_literals,
+			 const char *set_doc, const char *show_doc,
+			 const char *help_doc,
+			 cmd_func_ftype *set_func,
+			 show_value_ftype *show_func,
+			 struct cmd_list_element **set_list,
+			 struct cmd_list_element **show_list)
+{
+  set_show_commands commands
+    = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
+				 extra_literals, set_doc, show_doc,
+				 help_doc, nullptr, nullptr, set_func,
+				 show_func, set_list, show_list);
+  return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_integer_cmd (const char *name, command_class theclass,
+			 const literal_def *extra_literals,
+			 const char *set_doc, const char *show_doc,
+			 const char *help_doc,
+			 setting_func_types<int>::set set_func,
+			 setting_func_types<int>::get get_func,
+			 show_value_ftype *show_func,
+			 cmd_list_element **set_list,
+			 cmd_list_element **show_list)
+{
+  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
+					 extra_literals, set_doc, show_doc,
+					 help_doc, set_func, get_func, nullptr,
+					 show_func, set_list, show_list);
+  return cmds;
+}
+
+/* Accept `unlimited' or 0, translated internally to INT_MAX.  */
+const literal_def integer_unlimited_literals[] =
+  {
+    { "unlimited", 0, INT_MAX, true },
+    { nullptr }
+  };
+
+/* Same as above but using `integer_unlimited_literals', with a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_integer_cmd (const char *name, enum command_class theclass,
 			 int *var,
 			 const char *set_doc, const char *show_doc,
 			 const char *help_doc,
@@ -1012,12 +1108,10 @@ add_setshow_integer_cmd (const char *nam
 {
   set_show_commands commands
     = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
+				 integer_unlimited_literals,
 				 set_doc, show_doc, help_doc,
 				 nullptr, nullptr, set_func,
 				 show_func, set_list, show_list);
-
-  set_cmd_completer (commands.set, integer_unlimited_completer);
-
   return commands;
 }
 
@@ -1035,12 +1129,54 @@ add_setshow_integer_cmd (const char *nam
 			 cmd_list_element **show_list)
 {
   auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
+					 integer_unlimited_literals,
 					 set_doc, show_doc, help_doc, set_func,
 					 get_func, nullptr, show_func, set_list,
 					 show_list);
+  return cmds;
+}
 
-  set_cmd_completer (cmds.set, integer_unlimited_completer);
+/* Add element named NAME to both the set and show command LISTs (the
+   list for set/show or some sublist thereof).  CLASS is as in
+   add_cmd.  VAR is address of the variable which will contain the
+   value.  SET_DOC and SHOW_DOC are the documentation strings.  */
+
+set_show_commands
+add_setshow_pinteger_cmd (const char *name, enum command_class theclass,
+			  int *var, const literal_def *extra_literals,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  cmd_func_ftype *set_func,
+			  show_value_ftype *show_func,
+			  struct cmd_list_element **set_list,
+			  struct cmd_list_element **show_list)
+{
+  set_show_commands commands
+    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
+				 extra_literals, set_doc, show_doc,
+				 help_doc, nullptr, nullptr, set_func,
+				 show_func, set_list, show_list);
+  return commands;
+}
 
+/* Same as above but using a getter and a setter function instead of a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_pinteger_cmd (const char *name, command_class theclass,
+			  const literal_def *extra_literals,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  setting_func_types<int>::set set_func,
+			  setting_func_types<int>::get get_func,
+			  show_value_ftype *show_func,
+			  cmd_list_element **set_list,
+			  cmd_list_element **show_list)
+{
+  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
+					 extra_literals, set_doc, show_doc,
+					 help_doc, set_func, get_func, nullptr,
+					 show_func, set_list, show_list);
   return cmds;
 }
 
@@ -1051,7 +1187,7 @@ add_setshow_integer_cmd (const char *nam
 
 set_show_commands
 add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
-			  unsigned int *var,
+			  unsigned int *var, const literal_def *extra_literals,
 			  const char *set_doc, const char *show_doc,
 			  const char *help_doc,
 			  cmd_func_ftype *set_func,
@@ -1061,12 +1197,9 @@ add_setshow_uinteger_cmd (const char *na
 {
   set_show_commands commands
     = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
-					  set_doc, show_doc, help_doc,
-					  nullptr, nullptr, set_func,
+					  extra_literals, set_doc, show_doc,
+					  help_doc, nullptr, nullptr, set_func,
 					  show_func, set_list, show_list);
-
-  set_cmd_completer (commands.set, integer_unlimited_completer);
-
   return commands;
 }
 
@@ -1075,6 +1208,7 @@ add_setshow_uinteger_cmd (const char *na
 
 set_show_commands
 add_setshow_uinteger_cmd (const char *name, command_class theclass,
+			  const literal_def *extra_literals,
 			  const char *set_doc, const char *show_doc,
 			  const char *help_doc,
 			  setting_func_types<unsigned int>::set set_func,
@@ -1084,13 +1218,63 @@ add_setshow_uinteger_cmd (const char *na
 			  cmd_list_element **show_list)
 {
   auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
-						  nullptr, set_doc, show_doc,
-						  help_doc, set_func, get_func,
-						  nullptr, show_func, set_list,
+						  nullptr, extra_literals,
+						  set_doc, show_doc, help_doc,
+						  set_func, get_func, nullptr,
+						  show_func, set_list,
 						  show_list);
+  return cmds;
+}
 
-  set_cmd_completer (cmds.set, integer_unlimited_completer);
+/* Accept `unlimited' or 0, translated internally to UINT_MAX.  */
+const literal_def uinteger_unlimited_literals[] =
+  {
+    { "unlimited", 0, UINT_MAX, true },
+    { nullptr }
+  };
+
+/* Same as above but using `uinteger_unlimited_literals', with a pointer
+   to a global storage buffer.  */
+
+set_show_commands
+add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
+			  unsigned int *var,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  cmd_func_ftype *set_func,
+			  show_value_ftype *show_func,
+			  struct cmd_list_element **set_list,
+			  struct cmd_list_element **show_list)
+{
+  set_show_commands commands
+    = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
+					  uinteger_unlimited_literals,
+					  set_doc, show_doc, help_doc, nullptr,
+					  nullptr, set_func, show_func,
+					  set_list, show_list);
+  return commands;
+}
+
+/* Same as above but using a getter and a setter function instead of a pointer
+   to a global storage buffer.  */
 
+set_show_commands
+add_setshow_uinteger_cmd (const char *name, command_class theclass,
+			  const char *set_doc, const char *show_doc,
+			  const char *help_doc,
+			  setting_func_types<unsigned int>::set set_func,
+			  setting_func_types<unsigned int>::get get_func,
+			  show_value_ftype *show_func,
+			  cmd_list_element **set_list,
+			  cmd_list_element **show_list)
+{
+  auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
+						  nullptr,
+						  uinteger_unlimited_literals,
+						  set_doc, show_doc, help_doc,
+						  set_func, get_func, nullptr,
+						  show_func, set_list,
+						  show_list);
   return cmds;
 }
 
@@ -1109,7 +1293,7 @@ add_setshow_zinteger_cmd (const char *na
 			  struct cmd_list_element **set_list,
 			  struct cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, var,
+  return add_setshow_cmd_full<int> (name, theclass, var_integer, var,
 				    set_doc, show_doc, help_doc,
 				    nullptr, nullptr, set_func,
 				    show_func, set_list, show_list);
@@ -1128,12 +1312,22 @@ add_setshow_zinteger_cmd (const char *na
 			  cmd_list_element **set_list,
 			  cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, nullptr,
+  return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
 				    set_doc, show_doc, help_doc, set_func,
 				    get_func, nullptr, show_func, set_list,
 				    show_list);
 }
 
+/* Accept `unlimited' or -1, using -1 internally.  */
+const literal_def zuinteger_unlimited_literals[] =
+  {
+    { "unlimited", -1, -1, true },
+    { nullptr }
+  };
+
+/* Same as above but using `zuinteger_unlimited_literals', with a pointer
+   to a global storage buffer.  */
+
 set_show_commands
 add_setshow_zuinteger_unlimited_cmd (const char *name,
 				     enum command_class theclass,
@@ -1147,13 +1341,11 @@ add_setshow_zuinteger_unlimited_cmd (con
 				     struct cmd_list_element **show_list)
 {
   set_show_commands commands
-    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, var,
+    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
+				 zuinteger_unlimited_literals,
 				 set_doc, show_doc, help_doc, nullptr,
 				 nullptr, set_func, show_func, set_list,
 				 show_list);
-
-  set_cmd_completer (commands.set, integer_unlimited_completer);
-
   return commands;
 }
 
@@ -1171,13 +1363,11 @@ add_setshow_zuinteger_unlimited_cmd (con
 				     cmd_list_element **show_list)
 {
   auto cmds
-    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited,
-				 nullptr, set_doc, show_doc, help_doc, set_func,
+    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
+				 zuinteger_unlimited_literals,
+				 set_doc, show_doc, help_doc, set_func,
 				 get_func, nullptr, show_func, set_list,
 				 show_list);
-
-  set_cmd_completer (cmds.set, integer_unlimited_completer);
-
   return cmds;
 }
 
@@ -1196,7 +1386,7 @@ add_setshow_zuinteger_cmd (const char *n
 			   struct cmd_list_element **set_list,
 			   struct cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
+  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
 					     var, set_doc, show_doc, help_doc,
 					     nullptr, nullptr, set_func,
 					     show_func, set_list, show_list);
@@ -1215,7 +1405,7 @@ add_setshow_zuinteger_cmd (const char *n
 			   cmd_list_element **set_list,
 			   cmd_list_element **show_list)
 {
-  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
+  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
 					     nullptr, set_doc, show_doc,
 					     help_doc, set_func, get_func,
 					     nullptr, show_func, set_list,
Index: src/gdb/cli/cli-option.c
===================================================================
--- src.orig/gdb/cli/cli-option.c
+++ src/gdb/cli/cli-option.c
@@ -38,7 +38,7 @@ union option_value
   /* For var_uinteger options.  */
   unsigned int uinteger;
 
-  /* For var_zuinteger_unlimited options.  */
+  /* For var_integer and var_pinteger options.  */
   int integer;
 
   /* For var_enum options.  */
@@ -356,42 +356,55 @@ parse_option (gdb::array_view<const opti
 	return option_def_and_value {*match, match_ctx, val};
       }
     case var_uinteger:
-    case var_zuinteger_unlimited:
+    case var_integer:
+    case var_pinteger:
       {
 	if (completion != nullptr)
 	  {
-	    if (**args == '\0')
-	      {
-		/* Convenience to let the user know what the option
-		   can accept.  Note there's no common prefix between
-		   the strings on purpose, so that readline doesn't do
-		   a partial match.  */
-		completion->tracker.add_completion
-		  (make_unique_xstrdup ("NUMBER"));
-		completion->tracker.add_completion
-		  (make_unique_xstrdup ("unlimited"));
-		return {};
-	      }
-	    else if (startswith ("unlimited", *args))
+	    if (match->extra_literals != nullptr)
 	      {
-		completion->tracker.add_completion
-		  (make_unique_xstrdup ("unlimited"));
-		return {};
+		/* Convenience to let the user know what the option can
+		   accept.  Make sure there's no common prefix between
+		   "NUMBER" and all the strings when adding new ones,
+		   so that readline doesn't do a partial match.  */
+		if (**args == '\0')
+		  {
+		    completion->tracker.add_completion
+		      (make_unique_xstrdup ("NUMBER"));
+		    for (const literal_def *l = match->extra_literals;
+			 l->literal != nullptr;
+			 l++)
+		      completion->tracker.add_completion
+			(make_unique_xstrdup (l->literal));
+		    return {};
+		  }
+		else
+		  {
+		    bool completions = false;
+		    for (const literal_def *l = match->extra_literals;
+			 l->literal != nullptr;
+			 l++)
+		      if (startswith (l->literal, *args))
+			{
+			  completion->tracker.add_completion
+			    (make_unique_xstrdup (l->literal));
+			  completions = true;
+			}
+		    if (completions)
+		      return {};
+		  }
 	      }
 	  }
 
-	if (match->type == var_zuinteger_unlimited)
-	  {
-	    option_value val;
-	    val.integer = parse_cli_var_zuinteger_unlimited (args, false);
-	    return option_def_and_value {*match, match_ctx, val};
-	  }
+	LONGEST v = parse_cli_var_integer (match->type,
+					   match->extra_literals,
+					   args, false);
+	option_value val;
+	if (match->type == var_uinteger)
+	  val.uinteger = v;
 	else
-	  {
-	    option_value val;
-	    val.uinteger = parse_cli_var_uinteger (match->type, args, false);
-	    return option_def_and_value {*match, match_ctx, val};
-	  }
+	  val.integer = v;
+	return option_def_and_value {*match, match_ctx, val};
       }
     case var_enum:
       {
@@ -593,7 +606,7 @@ save_option_value_in_ctx (gdb::optional<
       *ov->option.var_address.uinteger (ov->option, ov->ctx)
 	= ov->value->uinteger;
       break;
-    case var_zuinteger_unlimited:
+    case var_integer:
       *ov->option.var_address.integer (ov->option, ov->ctx)
 	= ov->value->integer;
       break;
@@ -664,8 +677,20 @@ get_val_type_str (const option_def &opt,
     case var_boolean:
       return "[on|off]";
     case var_uinteger:
-    case var_zuinteger_unlimited:
-      return "NUMBER|unlimited";
+    case var_integer:
+    case var_pinteger:
+      {
+	buffer = "NUMBER";
+	if (opt.extra_literals != nullptr)
+	  for (const literal_def *l = opt.extra_literals;
+	       l->literal != nullptr;
+	       l++)
+	    {
+	      buffer += '|';
+	      buffer += l->literal;
+	    }
+	return buffer.c_str ();
+      }
     case var_enum:
       {
 	buffer = "";
@@ -789,20 +814,31 @@ add_setshow_cmds_for_options (command_cl
 	{
 	  add_setshow_uinteger_cmd (option.name, cmd_class,
 				    option.var_address.uinteger (option, data),
+				    option.extra_literals,
 				    option.set_doc, option.show_doc,
 				    option.help_doc,
 				    nullptr, option.show_cmd_cb,
 				    set_list, show_list);
 	}
-      else if (option.type == var_zuinteger_unlimited)
+      else if (option.type == var_integer)
 	{
-	  add_setshow_zuinteger_unlimited_cmd
-	    (option.name, cmd_class,
-	     option.var_address.integer (option, data),
-	     option.set_doc, option.show_doc,
-	     option.help_doc,
-	     nullptr, option.show_cmd_cb,
-	     set_list, show_list);
+	  add_setshow_integer_cmd (option.name, cmd_class,
+				   option.var_address.integer (option, data),
+				   option.extra_literals,
+				   option.set_doc, option.show_doc,
+				   option.help_doc,
+				   nullptr, option.show_cmd_cb,
+				   set_list, show_list);
+	}
+      else if (option.type == var_pinteger)
+	{
+	  add_setshow_pinteger_cmd (option.name, cmd_class,
+				    option.var_address.integer (option, data),
+				    option.extra_literals,
+				    option.set_doc, option.show_doc,
+				    option.help_doc,
+				    nullptr, option.show_cmd_cb,
+				    set_list, show_list);
 	}
       else if (option.type == var_enum)
 	{
Index: src/gdb/cli/cli-option.h
===================================================================
--- src.orig/gdb/cli/cli-option.h
+++ src/gdb/cli/cli-option.h
@@ -49,12 +49,13 @@ struct option_def
      used to create the option's "set/show" commands.  */
   constexpr option_def (const char *name_,
 			var_types var_type_,
+			const literal_def *extra_literals_,
 			erased_get_var_address_ftype *erased_get_var_address_,
 			show_value_ftype *show_cmd_cb_,
 			const char *set_doc_,
 			const char *show_doc_,
 			const char *help_doc_)
-    : name (name_), type (var_type_),
+    : name (name_), type (var_type_), extra_literals (extra_literals_),
       erased_get_var_address (erased_get_var_address_),
       var_address {},
       show_cmd_cb (show_cmd_cb_),
@@ -68,6 +69,9 @@ struct option_def
   /* The option's type.  */
   var_types type;
 
+  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
+  const literal_def *extra_literals;
+
   /* A function that gets the controlling variable's address, type
      erased.  */
   erased_get_var_address_ftype *erased_get_var_address;
@@ -160,7 +164,7 @@ struct boolean_option_def : option_def
 		      const char *set_doc_,
 		      const char *show_doc_ = nullptr,
 		      const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_boolean,
+    : option_def (long_option_, var_boolean, nullptr,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
@@ -207,11 +211,12 @@ struct uinteger_option_def : option_def
 {
   uinteger_option_def (const char *long_option_,
 		       unsigned int *(*get_var_address_cb_) (Context *),
+		       const literal_def *extra_literals_,
 		       show_value_ftype *show_cmd_cb_,
 		       const char *set_doc_,
 		       const char *show_doc_ = nullptr,
 		       const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_uinteger,
+    : option_def (long_option_, var_uinteger, extra_literals_,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
@@ -220,18 +225,19 @@ struct uinteger_option_def : option_def
   }
 };
 
-/* A var_zuinteger_unlimited command line option.  */
+/* A var_integer command line option.  */
 
 template<typename Context>
-struct zuinteger_unlimited_option_def : option_def
+struct integer_option_def : option_def
 {
-  zuinteger_unlimited_option_def (const char *long_option_,
-				  int *(*get_var_address_cb_) (Context *),
-				  show_value_ftype *show_cmd_cb_,
-				  const char *set_doc_,
-				  const char *show_doc_ = nullptr,
-				  const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_zuinteger_unlimited,
+  integer_option_def (const char *long_option_,
+		      int *(*get_var_address_cb_) (Context *),
+		      const literal_def *extra_literals_,
+		      show_value_ftype *show_cmd_cb_,
+		      const char *set_doc_,
+		      const char *show_doc_ = nullptr,
+		      const char *help_doc_ = nullptr)
+    : option_def (long_option_, var_integer, extra_literals_,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
@@ -252,7 +258,7 @@ struct enum_option_def : option_def
 		   const char *set_doc_,
 		   const char *show_doc_ = nullptr,
 		   const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_enum,
+    : option_def (long_option_, var_enum, nullptr,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
@@ -273,7 +279,7 @@ struct string_option_def : option_def
 		     const char *set_doc_,
 		     const char *show_doc_ = nullptr,
 		     const char *help_doc_ = nullptr)
-    : option_def (long_option_, var_string,
+    : option_def (long_option_, var_string, nullptr,
 		  (erased_get_var_address_ftype *) get_var_address_cb_,
 		  show_cmd_cb_,
 		  set_doc_, show_doc_, help_doc_)
Index: src/gdb/cli/cli-setshow.c
===================================================================
--- src.orig/gdb/cli/cli-setshow.c
+++ src/gdb/cli/cli-setshow.c
@@ -149,10 +149,11 @@ deprecated_show_value_hack (struct ui_fi
     }
 }
 
-/* Returns true if ARG is "unlimited".  */
+/* Returns true and the value in VAL if ARG is an accepted literal.  */
 
 static bool
-is_unlimited_literal (const char **arg, bool expression)
+get_literal_val (LONGEST &val, const literal_def *extra_literals,
+		 const char **arg, bool expression)
 {
   *arg = skip_spaces (*arg);
 
@@ -162,85 +163,108 @@ is_unlimited_literal (const char **arg,
 
   size_t len = p - *arg;
 
-  if (len > 0 && strncmp ("unlimited", *arg, len) == 0)
-    {
-      *arg += len;
-
-      /* If parsing an expression (i.e., parsing for a "set" command),
-	 anything after "unlimited" is junk.  For options, anything
-	 after "unlimited" might be a command argument or another
-	 option.  */
-      if (expression)
+  if (len > 0 && extra_literals != nullptr)
+    for (const literal_def *l = extra_literals;
+	 l->literal != nullptr;
+	 l++)
+      if (strncmp (l->literal, *arg, len) == 0)
 	{
-	  const char *after = skip_spaces (*arg);
-	  if (*after != '\0')
-	    error (_("Junk after \"%.*s\": %s"),
-		   (int) len, unl_start, after);
-	}
+	  *arg += len;
 
-      return true;
-    }
+	  /* If parsing an expression (i.e., parsing for a "set" command),
+	     anything after the literal is junk.  For options, anything
+	     after the literal might be a command argument or another
+	     option.  */
+	  if (expression)
+	    {
+	      const char *after = skip_spaces (*arg);
+	      if (*after != '\0')
+		error (_("Junk after \"%.*s\": %s"),
+		       (int) len, unl_start, after);
+	    }
+
+	  val = l->use;
+	  return true;
+	}
 
   return false;
 }
 
 /* See cli-setshow.h.  */
 
-unsigned int
-parse_cli_var_uinteger (var_types var_type, const char **arg,
-			bool expression)
+LONGEST
+parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
+		       const char **arg, bool expression)
 {
   LONGEST val;
 
   if (*arg == nullptr || **arg == '\0')
     {
-      if (var_type == var_uinteger)
-	error_no_arg (_("integer to set it to, or \"unlimited\""));
-      else
+      if (extra_literals == nullptr)
 	error_no_arg (_("integer to set it to"));
-    }
-
-  if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
-    val = 0;
-  else if (expression)
-    val = parse_and_eval_long (*arg);
-  else
-    val = get_ulongest (arg);
-
-  if (var_type == var_uinteger && val == 0)
-    val = UINT_MAX;
-  else if (val < 0
-	   /* For var_uinteger, don't let the user set the value
-	      to UINT_MAX directly, as that exposes an
-	      implementation detail to the user interface.  */
-	   || (var_type == var_uinteger && val >= UINT_MAX)
-	   || (var_type == var_zuinteger && val > UINT_MAX))
-    error (_("integer %s out of range"), plongest (val));
-
-  return val;
-}
-
-/* See cli-setshow.h.  */
+      else
+	{
+	  std::string buffer = "";
+	  size_t count = 0;
 
-int
-parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
-{
-  LONGEST val;
+	  for (const literal_def *l = extra_literals;
+	       l->literal != nullptr;
+	       l++, count++)
+	    {
+	      if (count != 0)
+		buffer += ", ";
+	      buffer = buffer + '"' + l->literal + '"';
+	    }
+	  if (count > 1)
+	    error_no_arg
+	      (string_printf (_("integer to set it to, or one of: %s"),
+			      buffer.c_str ()).c_str ());
+	  else
+	    error_no_arg
+	      (string_printf (_("integer to set it to, or %s"),
+			      buffer.c_str ()).c_str ());
+	}
+    }
 
-  if (*arg == nullptr || **arg == '\0')
-    error_no_arg (_("integer to set it to, or \"unlimited\""));
+  if (!get_literal_val (val, extra_literals, arg, expression))
+    {
+      if (expression)
+	val = parse_and_eval_long (*arg);
+      else
+	val = get_ulongest (arg);
 
-  if (is_unlimited_literal (arg, expression))
-    val = -1;
-  else if (expression)
-    val = parse_and_eval_long (*arg);
-  else
-    val = get_ulongest (arg);
+      enum tribool allowed = TRIBOOL_UNKNOWN;
+      if (extra_literals != nullptr)
+	{
+	  for (const literal_def *l = extra_literals;
+	       l->literal != nullptr;
+	       l++)
+	    if (val == l->val)
+	      {
+		allowed = l->allow ? TRIBOOL_TRUE : TRIBOOL_FALSE;
+		val = l->use;
+		break;
+	      }
+	    else if (val == l->use)
+	      {
+		allowed = TRIBOOL_FALSE;
+		break;
+	      }
+	}
 
-  if (val > INT_MAX)
-    error (_("integer %s out of range"), plongest (val));
-  else if (val < -1)
-    error (_("only -1 is allowed to set as unlimited"));
+      if (allowed == TRIBOOL_UNKNOWN)
+	{
+	  if (var_type == var_pinteger && val < 0)
+	    error (_("only -1 is allowed to set as unlimited"));
+	  else if (val > UINT_MAX || val < INT_MIN
+		   || (var_type == var_uinteger && val < 0)
+		   || (var_type == var_integer && val > INT_MAX)
+		   || (var_type == var_pinteger && val > INT_MAX))
+	    allowed = TRIBOOL_FALSE;
+	}
+      if (allowed == TRIBOOL_FALSE)
+	error (_("integer %s out of range"), plongest (val));
+    }
 
   return val;
 }
@@ -405,41 +429,18 @@ do_set_command (const char *arg, int fro
       option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg));
       break;
     case var_uinteger:
-    case var_zuinteger:
       option_changed
-	= c->var->set<unsigned int> (parse_cli_var_uinteger (c->var->type (),
-							     &arg, true));
+	= c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (),
+							    c->var->
+							    extra_literals (),
+							    &arg, true));
       break;
     case var_integer:
-    case var_zinteger:
-      {
-	LONGEST val;
-
-	if (*arg == '\0')
-	  {
-	    if (c->var->type () == var_integer)
-	      error_no_arg (_("integer to set it to, or \"unlimited\""));
-	    else
-	      error_no_arg (_("integer to set it to"));
-	  }
-
-	if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
-	  val = 0;
-	else
-	  val = parse_and_eval_long (arg);
-
-	if (val == 0 && c->var->type () == var_integer)
-	  val = INT_MAX;
-	else if (val < INT_MIN
-		 /* For var_integer, don't let the user set the value
-		    to INT_MAX directly, as that exposes an
-		    implementation detail to the user interface.  */
-		 || (c->var->type () == var_integer && val >= INT_MAX)
-		 || (c->var->type () == var_zinteger && val > INT_MAX))
-	  error (_("integer %s out of range"), plongest (val));
-
-	option_changed = c->var->set<int> (val);
-      }
+    case var_pinteger:
+      option_changed
+	= c->var->set<int> (parse_cli_var_integer (c->var->type (),
+						   c->var->extra_literals (),
+						   &arg, true));
       break;
     case var_enum:
       {
@@ -454,10 +455,6 @@ do_set_command (const char *arg, int fro
 	option_changed = c->var->set<const char *> (match);
       }
       break;
-    case var_zuinteger_unlimited:
-      option_changed = c->var->set<int>
-	(parse_cli_var_zuinteger_unlimited (&arg, true));
-      break;
     default:
       error (_("gdb internal error: bad var_type in do_setshow_command"));
     }
@@ -551,7 +548,6 @@ do_set_command (const char *arg, int fro
 	  }
 	  break;
 	case var_uinteger:
-	case var_zuinteger:
 	  {
 	    char s[64];
 
@@ -560,8 +556,7 @@ do_set_command (const char *arg, int fro
 	  }
 	  break;
 	case var_integer:
-	case var_zinteger:
-	case var_zuinteger_unlimited:
+	case var_pinteger:
 	  {
 	    char s[64];
 
@@ -623,36 +618,32 @@ get_setshow_command_value_string (const
 	}
       break;
     case var_uinteger:
-    case var_zuinteger:
-      {
-	const unsigned int value = var.get<unsigned int> ();
-
-	if (var.type () == var_uinteger
-	    && value == UINT_MAX)
-	  stb.puts ("unlimited");
-	else
-	  stb.printf ("%u", value);
-      }
-      break;
     case var_integer:
-    case var_zinteger:
+    case var_pinteger:
       {
-	const int value = var.get<int> ();
+	bool printed = false;
+	const LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
 
-	if (var.type () == var_integer
-	    && value == INT_MAX)
-	  stb.puts ("unlimited");
-	else
-	  stb.printf ("%d", value);
-      }
-      break;
-    case var_zuinteger_unlimited:
-      {
-	const int value = var.get<int> ();
-	if (value == -1)
-	  stb.puts ("unlimited");
-	else
-	  stb.printf ("%d", value);
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		stb.puts (l->literal);
+		printed = true;
+		break;
+	      }
+	if (!printed)
+	  {
+	    if (var.type () == var_uinteger)
+	      stb.printf ("%u", static_cast<const unsigned int> (value));
+	    else
+	      stb.printf ("%d", static_cast<const int> (value));
+	  }
       }
       break;
     default:
Index: src/gdb/cli/cli-setshow.h
===================================================================
--- src.orig/gdb/cli/cli-setshow.h
+++ src/gdb/cli/cli-setshow.h
@@ -29,21 +29,19 @@ extern int parse_cli_boolean_value (cons
    past a successfully parsed value.  */
 extern int parse_cli_boolean_value (const char **arg);
 
-/* Parse ARG, an option to a var_uinteger or var_zuinteger variable.
-   Either returns the parsed value on success or throws an error.  If
-   EXPRESSION is true, *ARG is parsed as an expression; otherwise, it
-   is parsed with get_ulongest.  It's not possible to parse the
+/* Parse ARG, an option to a var_uinteger, var_integer or var_pinteger
+   variable.  Return the parsed value on success or throw an error.  If
+   EXTRA_LITERALS is non-null, then interpret those literals accordingly.
+   If EXPRESSION is true, *ARG is parsed as an expression; otherwise,
+   it is parsed with get_ulongest.  It's not possible to parse the
    integer as an expression when there may be valid input after the
    integer, such as when parsing command options.  E.g., "print
    -elements NUMBER -obj --".  In such case, parsing as an expression
    would parse "-obj --" as part of the expression as well.  */
-extern unsigned int parse_cli_var_uinteger (var_types var_type,
-					    const char **arg,
-					    bool expression);
-
-/* Like parse_cli_var_uinteger, for var_zuinteger_unlimited.  */
-extern int parse_cli_var_zuinteger_unlimited (const char **arg,
-					      bool expression);
+extern LONGEST parse_cli_var_integer (var_types var_type,
+				      const literal_def *extra_literals,
+				      const char **arg,
+				      bool expression);
 
 /* Parse ARG, an option to a var_enum variable.  ENUM is a
    null-terminated array of possible values. Either returns the parsed
Index: src/gdb/command.h
===================================================================
--- src.orig/gdb/command.h
+++ src/gdb/command.h
@@ -84,16 +84,18 @@ typedef enum var_types
        value.  */
     var_auto_boolean,
 
-    /* Unsigned Integer.  *VAR is an unsigned int.  The user can type
-       0 to mean "unlimited", which is stored in *VAR as UINT_MAX.  */
+    /* Unsigned Integer.  *VAR is an unsigned int.  In the Guile and Python
+       APIs 0 means unlimited, which is stored in *VAR as UINT_MAX.  */
     var_uinteger,
 
-    /* Like var_uinteger but signed.  *VAR is an int.  The user can
-       type 0 to mean "unlimited", which is stored in *VAR as
-       INT_MAX.  The only remaining use of it is the Python API.
-       Don't use it elsewhere.  */
+    /* Like var_uinteger but signed.  *VAR is an int.  In the Guile and
+       Python APIs 0 means unlimited, which is stored in *VAR as INT_MAX.  */
     var_integer,
 
+    /* Like var_integer but negative numbers are not allowed,
+       except for special values.  *VAR is an int.  */
+    var_pinteger,
+
     /* String which the user enters with escapes (e.g. the user types
        \n and it is a real newline in the stored string).
        *VAR is a std::string, "" if the string is empty.  */
@@ -106,15 +108,16 @@ typedef enum var_types
     var_optional_filename,
     /* String which stores a filename.  (*VAR) is a std::string.  */
     var_filename,
-    /* ZeroableInteger.  *VAR is an int.  Like var_integer except
-       that zero really means zero.  */
+    /* Like var_integer.  *VAR is an int.  The only remaining uses
+       of it are the Guile and Python APIs.  Don't use it elsewhere.  */
     var_zinteger,
-    /* ZeroableUnsignedInteger.  *VAR is an unsigned int.  Zero really
-       means zero.  */
+    /* Like var_uinteger.  *VAR is an unsigned int.  The only remaining
+       uses of it are the Guile and Python APIs.  Don't use it elsewhere.  */
     var_zuinteger,
-    /* ZeroableUnsignedInteger with unlimited value.  *VAR is an int,
-       but its range is [0, INT_MAX].  -1 stands for unlimited and
-       other negative numbers are not allowed.  */
+    /* Like var_pinteger.  *VAR is an int, but its range is [-1, INT_MAX].
+       -1 stands for unlimited and other negative numbers are not allowed.
+       The only remaining uses of it are the Guile and Python APIs.  Don't
+       use it elsewhere.  */
     var_zuinteger_unlimited,
     /* Enumerated type.  Can only have one of the specified values.
        *VAR is a char pointer to the name of the element that we
@@ -123,6 +126,22 @@ typedef enum var_types
   }
 var_types;
 
+/* A structure describing an extra literal accepted and shown in place
+   of a number.  */
+typedef struct literal_defs
+  {
+    /* The literal to define, e.g. "unlimited".  */
+    const char *literal;
+    /* A number optionally accepted that stands for the literal.  */
+    LONGEST val;
+    /* The number to substitute internally for LITERAL or VAL;
+       the use of this number is not allowed (unless the same as VAL).  */
+    LONGEST use;
+    /* True if the use of VAL is allowed; otherwise only the literal is.  */
+    bool allow;
+  }
+literal_def;
+
 /* Return true if a setting of type VAR_TYPE is backed with type T.
 
    This function is left without definition intentionally.  This template is
@@ -153,15 +172,14 @@ inline bool var_type_uses<enum auto_bool
 template<>
 inline bool var_type_uses<unsigned int> (var_types t)
 {
-  return (t == var_uinteger || t == var_zinteger || t == var_zuinteger);
+  return t == var_uinteger;
 }
 
 /* Return true if a setting of type T is backed by an int variable.  */
 template<>
 inline bool var_type_uses<int> (var_types t)
 {
-  return (t == var_integer || t == var_zinteger
-	  || t == var_zuinteger_unlimited);
+  return t == var_integer || t == var_pinteger;
 }
 
 /* Return true if a setting of type T is backed by a std::string variable.  */
@@ -233,6 +251,7 @@ struct setting
   struct erased_args
   {
     void *var;
+    const void *extra_literals;
     erased_func setter;
     erased_func getter;
   };
@@ -240,6 +259,7 @@ struct setting
   template<typename T>
   static erased_args erase_args (var_types var_type,
 				 T *var,
+				 const literal_def *extra_literals,
 				 typename setting_func_types<T>::set set_setting_func,
 				 typename setting_func_types<T>::get get_setting_func)
   {
@@ -254,6 +274,7 @@ struct setting
 
     return {
 	var,
+	extra_literals,
 	reinterpret_cast<erased_func> (set_setting_func),
 	reinterpret_cast<erased_func> (get_setting_func)
     };
@@ -265,6 +286,7 @@ struct setting
   setting (var_types var_type, const erased_args &args)
     : m_var_type (var_type),
       m_var (args.var),
+      m_extra_literals (args.extra_literals),
       m_getter (args.getter),
       m_setter (args.setter)
   {
@@ -295,6 +317,10 @@ struct setting
   var_types type () const
   { return m_var_type; }
 
+  /* Access any extra literals accepted.  */
+  const literal_def *extra_literals () const
+  { return static_cast<const literal_def *> (m_extra_literals); }
+
   /* Return the current value.
 
      The template parameter T is the type of the variable used to store the
@@ -357,6 +383,9 @@ struct setting
      non-nullptr.  */
   void *m_var = nullptr;
 
+  /* Any extra literals accepted.  */
+  const void *m_extra_literals = nullptr;
+
   /* Pointer to a user provided getter.  */
   erased_func m_getter = nullptr;
 
@@ -652,6 +681,11 @@ typedef void (show_value_ftype) (struct
    instead print the value out directly.  */
 extern show_value_ftype deprecated_show_value_hack;
 
+/* Various sets of extra literals accepted.  */
+extern const literal_def integer_unlimited_literals[];
+extern const literal_def uinteger_unlimited_literals[];
+extern const literal_def zuinteger_unlimited_literals[];
+
 extern set_show_commands add_setshow_enum_cmd
   (const char *name, command_class theclass, const char *const *enumlist,
    const char **var, const char *set_doc, const char *show_doc,
@@ -748,6 +782,20 @@ extern set_show_commands add_setshow_opt
    cmd_list_element **show_list);
 
 extern set_show_commands add_setshow_integer_cmd
+  (const char *name, command_class theclass, int *var,
+   const literal_def *extra_literals, const char *set_doc,
+   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
+   show_value_ftype *show_func, cmd_list_element **set_list,
+   cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_integer_cmd
+  (const char *name, command_class theclass, const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   setting_func_types<int>::set set_func,
+   setting_func_types<int>::get get_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_integer_cmd
   (const char *name, command_class theclass, int *var, const char *set_doc,
    const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
    show_value_ftype *show_func, cmd_list_element **set_list,
@@ -760,6 +808,34 @@ extern set_show_commands add_setshow_int
    setting_func_types<int>::get get_func, show_value_ftype *show_func,
    cmd_list_element **set_list, cmd_list_element **show_list);
 
+extern set_show_commands add_setshow_pinteger_cmd
+  (const char *name, command_class theclass, int *var,
+   const literal_def *extra_literals, const char *set_doc,
+   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
+   show_value_ftype *show_func, cmd_list_element **set_list,
+   cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_pinteger_cmd
+  (const char *name, command_class theclass, const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   setting_func_types<int>::set set_func,
+   setting_func_types<int>::get get_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_uinteger_cmd
+  (const char *name, command_class theclass, unsigned int *var,
+   const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   cmd_func_ftype *set_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
+extern set_show_commands add_setshow_uinteger_cmd
+  (const char *name, command_class theclass, const literal_def *extra_literals,
+   const char *set_doc, const char *show_doc, const char *help_doc,
+   setting_func_types<unsigned int>::set set_func,
+   setting_func_types<unsigned int>::get get_func, show_value_ftype *show_func,
+   cmd_list_element **set_list, cmd_list_element **show_list);
+
 extern set_show_commands add_setshow_uinteger_cmd
   (const char *name, command_class theclass, unsigned int *var,
    const char *set_doc, const char *show_doc, const char *help_doc,
Index: src/gdb/guile/scm-param.c
===================================================================
--- src.orig/gdb/guile/scm-param.c
+++ src/gdb/guile/scm-param.c
@@ -117,18 +117,33 @@ struct param_smob
 static setting
 make_setting (param_smob *s)
 {
-  if (var_type_uses<bool> (s->type))
-    return setting (s->type, &s->value.boolval);
-  else if (var_type_uses<int> (s->type))
-    return setting (s->type, &s->value.intval);
-  else if (var_type_uses<auto_boolean> (s->type))
-    return setting (s->type, &s->value.autoboolval);
-  else if (var_type_uses<unsigned int> (s->type))
-    return setting (s->type, &s->value.uintval);
-  else if (var_type_uses<std::string> (s->type))
-    return setting (s->type, s->value.stringval);
-  else if (var_type_uses<const char *> (s->type))
-    return setting (s->type, &s->value.cstringval);
+  enum var_types type = s->type;
+
+  switch (type)
+    {
+    case var_zinteger:
+      type = var_integer;
+      break;
+    case var_zuinteger:
+      type = var_uinteger;
+      break;
+    case var_zuinteger_unlimited:
+      type = var_pinteger;
+      break;
+    }
+
+  if (var_type_uses<bool> (type))
+    return setting (type, &s->value.boolval);
+  else if (var_type_uses<int> (type))
+    return setting (type, &s->value.intval);
+  else if (var_type_uses<auto_boolean> (type))
+    return setting (type, &s->value.autoboolval);
+  else if (var_type_uses<unsigned int> (type))
+    return setting (type, &s->value.uintval);
+  else if (var_type_uses<std::string> (type))
+    return setting (type, s->value.stringval);
+  else if (var_type_uses<const char *> (type))
+    return setting (type, &s->value.cstringval);
   else
     gdb_assert_not_reached ("unhandled var type");
 }
@@ -588,10 +603,6 @@ pascm_param_type_name (enum var_types pa
 static SCM
 pascm_param_value (const setting &var, int arg_pos, const char *func_name)
 {
-  /* Note: We *could* support var_integer here in case someone is trying to get
-     the value of a Python-created parameter (which is the only place that
-     still supports var_integer).  To further discourage its use we do not.  */
-
   switch (var.type ())
     {
     case var_string:
@@ -631,20 +642,35 @@ pascm_param_value (const setting &var, i
 	  return auto_keyword;
       }
 
-    case var_zuinteger_unlimited:
-      if (var.get<int> () == -1)
-	return unlimited_keyword;
-      gdb_assert (var.get<int> () >= 0);
-      /* Fall through.  */
-    case var_zinteger:
-      return scm_from_int (var.get<int> ());
-
     case var_uinteger:
-      if (var.get<unsigned int> ()== UINT_MAX)
-	return unlimited_keyword;
-      /* Fall through.  */
-    case var_zuinteger:
-      return scm_from_uint (var.get<unsigned int> ());
+    case var_integer:
+    case var_pinteger:
+      {
+	LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
+
+	bool literal = false;
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		if (strcmp (l->literal, "unlimited") == 0)
+		  return unlimited_keyword;
+		value = l->val;
+		literal = true;
+	      }
+	if (var.type () == var_pinteger && !literal)
+	  gdb_assert (value >= 0);
+
+	if (var.type () == var_uinteger)
+	  return scm_from_uint (static_cast<const unsigned int> (value));
+	else
+	  return scm_from_int (static_cast<const int> (value));
+      }
 
     default:
       break;
@@ -666,14 +692,14 @@ pascm_set_param_value_x (param_smob *p_s
 {
   setting var = make_setting (p_smob);
 
-  switch (var.type ())
+  switch (p_smob->type)
     {
     case var_string:
     case var_string_noescape:
     case var_optional_filename:
     case var_filename:
       SCM_ASSERT_TYPE (scm_is_string (value)
-		       || (var.type () != var_filename
+		       || (p_smob->type != var_filename
 			   && gdbscm_is_false (value)),
 		       value, arg_pos, func_name,
 		       _("string or #f for non-PARAM_FILENAME parameters"));
@@ -739,8 +765,8 @@ pascm_set_param_value_x (param_smob *p_s
     case var_uinteger:
     case var_zuinteger:
     case var_zuinteger_unlimited:
-      if (var.type () == var_uinteger
-	  || var.type () == var_zuinteger_unlimited)
+      if (p_smob->type == var_uinteger
+	  || p_smob->type == var_zuinteger_unlimited)
 	{
 	  SCM_ASSERT_TYPE (gdbscm_is_bool (value)
 			   || scm_is_eq (value, unlimited_keyword),
@@ -748,7 +774,7 @@ pascm_set_param_value_x (param_smob *p_s
 			   _("integer or #:unlimited"));
 	  if (scm_is_eq (value, unlimited_keyword))
 	    {
-	      if (var.type () == var_uinteger)
+	      if (p_smob->type == var_uinteger)
 		var.set<unsigned int> (UINT_MAX);
 	      else
 		var.set<int> (-1);
@@ -761,12 +787,12 @@ pascm_set_param_value_x (param_smob *p_s
 			   _("integer"));
 	}
 
-      if (var.type () == var_uinteger
-	  || var.type () == var_zuinteger)
+      if (p_smob->type == var_uinteger
+	  || p_smob->type == var_zuinteger)
 	{
 	  unsigned int u = scm_to_uint (value);
 
-	  if (var.type () == var_uinteger && u == 0)
+	  if (p_smob->type == var_uinteger && u == 0)
 	    u = UINT_MAX;
 	  var.set<unsigned int> (u);
 	}
@@ -774,7 +800,7 @@ pascm_set_param_value_x (param_smob *p_s
 	{
 	  int i = scm_to_int (value);
 
-	  if (var.type () == var_zuinteger_unlimited && i < -1)
+	  if (p_smob->type == var_zuinteger_unlimited && i < -1)
 	    {
 	      gdbscm_out_of_range_error (func_name, arg_pos, value,
 					 _("must be >= -1"));
Index: src/gdb/maint-test-options.c
===================================================================
--- src.orig/gdb/maint-test-options.c
+++ src/gdb/maint-test-options.c
@@ -207,6 +207,7 @@ static const gdb::option::option_def tes
   gdb::option::uinteger_option_def<test_options_opts> {
     "uinteger",
     [] (test_options_opts *opts) { return &opts->uint_opt; },
+    uinteger_unlimited_literals,
     nullptr, /* show_cmd_cb */
     N_("A uinteger option."),
     nullptr, /* show_doc */
@@ -214,9 +215,10 @@ static const gdb::option::option_def tes
   },
 
   /* A zuinteger_unlimited option.  */
-  gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
+  gdb::option::integer_option_def<test_options_opts> {
     "zuinteger-unlimited",
     [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
+    zuinteger_unlimited_literals,
     nullptr, /* show_cmd_cb */
     N_("A zuinteger-unlimited option."),
     nullptr, /* show_doc */
Index: src/gdb/python/py-param.c
===================================================================
--- src.orig/gdb/python/py-param.c
+++ src/gdb/python/py-param.c
@@ -96,18 +96,33 @@ struct parmpy_object
 static setting
 make_setting (parmpy_object *s)
 {
-  if (var_type_uses<bool> (s->type))
-    return setting (s->type, &s->value.boolval);
-  else if (var_type_uses<int> (s->type))
-    return setting (s->type, &s->value.intval);
-  else if (var_type_uses<auto_boolean> (s->type))
-    return setting (s->type, &s->value.autoboolval);
-  else if (var_type_uses<unsigned int> (s->type))
-    return setting (s->type, &s->value.uintval);
-  else if (var_type_uses<std::string> (s->type))
-    return setting (s->type, s->value.stringval);
-  else if (var_type_uses<const char *> (s->type))
-    return setting (s->type, &s->value.cstringval);
+  enum var_types type = s->type;
+
+  switch (type)
+    {
+    case var_zinteger:
+      type = var_integer;
+      break;
+    case var_zuinteger:
+      type = var_uinteger;
+      break;
+    case var_zuinteger_unlimited:
+      type = var_pinteger;
+      break;
+    }
+
+  if (var_type_uses<bool> (type))
+    return setting (type, &s->value.boolval);
+  else if (var_type_uses<int> (type))
+    return setting (type, &s->value.intval);
+  else if (var_type_uses<auto_boolean> (type))
+    return setting (type, &s->value.autoboolval);
+  else if (var_type_uses<unsigned int> (type))
+    return setting (type, &s->value.uintval);
+  else if (var_type_uses<std::string> (type))
+    return setting (type, s->value.stringval);
+  else if (var_type_uses<const char *> (type))
+    return setting (type, &s->value.cstringval);
   else
     gdb_assert_not_reached ("unhandled var type");
 }
Index: src/gdb/python/python.c
===================================================================
--- src.orig/gdb/python/python.c
+++ src/gdb/python/python.c
@@ -502,35 +502,34 @@ gdbpy_parameter_value (const setting &va
 	  Py_RETURN_NONE;
       }
 
-    case var_integer:
-      if (var.get<int> () == INT_MAX)
-	Py_RETURN_NONE;
-      /* Fall through.  */
-    case var_zinteger:
-      return gdb_py_object_from_longest (var.get<int> ()).release ();
-
-    case var_zuinteger_unlimited:
-      {
-	int val = var.get<int> ();
-
-	if (val == -1)
-	  Py_RETURN_NONE;
-	return gdb_py_object_from_longest (val).release ();
-      }
-
     case var_uinteger:
+    case var_integer:
+    case var_pinteger:
       {
-	unsigned int val = var.get<unsigned int> ();
+	LONGEST value
+	  = (var.type () == var_uinteger
+	     ? static_cast<LONGEST> (var.get<unsigned int> ())
+	     : static_cast<LONGEST> (var.get<int> ()));
 
-	if (val == UINT_MAX)
-	  Py_RETURN_NONE;
-	return gdb_py_object_from_ulongest (val).release ();
-      }
+	if (var.extra_literals () != nullptr)
+	  for (const literal_def *l = var.extra_literals ();
+	       l->literal != nullptr;
+	       l++)
+	    if (value == l->use)
+	      {
+		if (strcmp (l->literal, "unlimited") == 0)
+		  Py_RETURN_NONE;
+		value = l->val;
+	      }
 
-    case var_zuinteger:
-      {
-	unsigned int val = var.get<unsigned int> ();
-	return gdb_py_object_from_ulongest (val).release ();
+	if (var.type () == var_uinteger)
+	  return
+	    gdb_py_object_from_ulongest
+	      (static_cast<const unsigned int> (value)).release ();
+	else
+	  return
+	    gdb_py_object_from_longest
+	      (static_cast<const int> (value)).release ();
       }
     }
 
Index: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -2974,8 +2974,8 @@ using boolean_option_def
   = gdb::option::boolean_option_def<value_print_options>;
 using uinteger_option_def
   = gdb::option::uinteger_option_def<value_print_options>;
-using zuinteger_unlimited_option_def
-  = gdb::option::zuinteger_unlimited_option_def<value_print_options>;
+using integer_option_def
+  = gdb::option::integer_option_def<value_print_options>;
 
 /* Definitions of options for the "print" and "compile print"
    commands.  */
@@ -3011,15 +3011,17 @@ static const gdb::option::option_def val
   uinteger_option_def {
     "elements",
     [] (value_print_options *opt) { return &opt->print_max; },
+    uinteger_unlimited_literals,
     show_print_max, /* show_cmd_cb */
     N_("Set limit on string chars or array elements to print."),
     N_("Show limit on string chars or array elements to print."),
     N_("\"unlimited\" causes there to be no limit."),
   },
 
-  zuinteger_unlimited_option_def {
+  integer_option_def {
     "max-depth",
     [] (value_print_options *opt) { return &opt->max_depth; },
+    zuinteger_unlimited_literals,
     show_print_max_depth, /* show_cmd_cb */
     N_("Set maximum print depth for nested structures, unions and arrays."),
     N_("Show maximum print depth for nested structures, unions, and arrays."),
@@ -3079,6 +3081,7 @@ pretty-printers for that value.")
   uinteger_option_def {
     "repeats",
     [] (value_print_options *opt) { return &opt->repeat_count_threshold; },
+    uinteger_unlimited_literals,
     show_repeat_count_threshold, /* show_cmd_cb */
     N_("Set threshold for repeated print elements."),
     N_("Show threshold for repeated print elements."),

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 7/8] GDB: Add a character string limiting option
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (5 preceding siblings ...)
  2022-03-30 10:24 ` [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands Maciej W. Rozycki
@ 2022-03-30 10:24 ` Maciej W. Rozycki
  2022-03-30 12:29   ` Eli Zaretskii
  2022-03-30 10:24 ` [PATCH v5 8/8] GDB/testsuite: Expand for character string limiting options Maciej W. Rozycki
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

From: Andrew Burgess <andrew.burgess@embecosm.com>

This commit splits the `set/show print elements' option into two.  We 
retain `set/show print elements' for controlling how many elements of an 
array we print, but a new `set/show print characters' setting is added 
which is used for controlling how many characters of a string are 
printed.

The motivation behind this change is to allow users a finer level of 
control over how data is printed, reflecting that, although strings can 
be thought of as arrays of characters, users often want to treat these 
two things differently.

For compatibility reasons by default the `set/show print characters' 
option is set to `elements', which makes the limit for character strings 
follow the setting of the `set/show print elements' option, as it used 
to.  Using `set print characters' with any other value makes the limit 
independent from the `set/show print elements' setting, however it can 
be restored to the default with the `set print characters elements' 
command at any time.

A corresponding `-characters' option for the `print' command is added, 
with the same semantics, i.e. one can use `elements' to make a given 
`print' invocation follow the limit of elements, be it set with the 
`-elements' option also given with the same invocation or taken from the 
`set/show print elements' setting, for characters as well regardless of 
the current setting of the `set/show print characters' option.

The GDB changes are all pretty straightforward, just changing references 
to the old 'print_max' to use a new `get_print_max_chars' helper which 
figures out which of the two of `print_max' and `print_max_chars' values 
to use.

Likewise, the documentation is just updated to reference the new setting 
where appropriate.

To make people's life easier the message shown by `show print elements' 
now indicates if the setting also applies to character strings:

(gdb) set print characters elements
(gdb) show print elements
Limit on string chars or array elements to print is 200.
(gdb) set print characters unlimited
(gdb) show print elements
Limit on array elements to print is 200.
(gdb) 

which keeps it the same as it used to be, although in other contexts the 
setting is described as applying to array elements only, e.g.:

(gdb) help set print elements
Set limit on array elements to print.
"unlimited" causes there to be no limit.
(gdb) 

In the testsuite there are two minor updates, one to add `-characters' 
to the list of completions now shown for the `print' command, and a bare 
minimum pair of checks for the right handling of `set print characters' 
and `show print characters', copied from the corresponding checks for 
`set print elements' and `show print elements' respectively.

Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
---
Changes from v4:

- move the NEWS entry past GDB 12 and describe `print -characters LIMIT'
  separately

- clarify the effect on multi-byte and wide character strings in the 
  manual (borrowing from the original NEWS entry that added support for 
  them),

- fix issues with `@ref' and `@xref' usage in the manual.

Changes from v3:

- rewrite in terms of flexible literal keyword handling added with 6/8,

- add a `set print characters elements' setting, which is also the 
  default, to make the string character limit follow that for array 
  elements in backwards-compatible manner,

- update documentation accordingly,

- remove testsuite updates delegated to 8/8, guaranteeing that the new 
  command does not influence any preexisting environment (except for 
  obvious cases where it is expected, such as command completion or help 
  messages),

- amend gdb.base/options.exp for the added completion for `print' 
  command's `-characters' option,

- expand gdb.base/default.exp with minimal test cases for `set/show print 
  characters'.

Changes from v2:

- place the new and the changed command at the right places each in NEWS.

Changes from v1:

- rename `print_smax' setting throughout to `print_max_chars', and
  likewise `show_print_smax' function to `show_print_max_chars',

- document the Python part in the manual,

- update comments for `print_max' and `print_max_chars' in
  `value_print_options',

- fix some typos.
---
 gdb/NEWS                           |   16 +++++++
 gdb/ada-valprint.c                 |    6 +-
 gdb/c-lang.c                       |    4 -
 gdb/c-valprint.c                   |    5 +-
 gdb/doc/gdb.texinfo                |   44 +++++++++++++++++--
 gdb/doc/python.texi                |    5 ++
 gdb/language.h                     |    2 
 gdb/m2-lang.c                      |    3 -
 gdb/m2-valprint.c                  |    4 +
 gdb/p-lang.c                       |    3 -
 gdb/p-valprint.c                   |    9 ++-
 gdb/printcmd.c                     |    9 ++-
 gdb/python/py-value.c              |    4 +
 gdb/testsuite/gdb.base/default.exp |    7 +++
 gdb/testsuite/gdb.base/options.exp |    1 
 gdb/tracepoint.c                   |    4 -
 gdb/valprint.c                     |   84 ++++++++++++++++++++++++++++---------
 gdb/valprint.h                     |   20 +++++++-
 18 files changed, 181 insertions(+), 49 deletions(-)

gdb-aburgess-print-elements-characters.diff
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS
+++ src/gdb/NEWS
@@ -16,6 +16,22 @@
      This is the same format that GDB uses when printing address, symbol,
      and offset information from the disassembler.
 
+* New commands
+
+set print characters LIMIT
+show print characters
+  This new setting is like 'set print elements', but controls how many
+  characters of a string are printed.  This functionality used to be
+  covered by 'set print elements', but it can be controlled separately
+  now.  LIMIT can be set to a numerical value to request that particular
+  character count, to 'unlimited' to print all characters of a string,
+  or to 'elements', which is also the default, to follow the setting of
+ 'set print elements' as it used to be.
+
+print -characters LIMIT
+  This new option to the 'print' command has the same effect as a temporary
+  use of 'set print characters'.
+
 *** Changes in GDB 12
 
 * DBX mode is deprecated, and will be removed in GDB 13
Index: src/gdb/ada-valprint.c
===================================================================
--- src.orig/gdb/ada-valprint.c
+++ src/gdb/ada-valprint.c
@@ -470,7 +470,8 @@ printstr (struct ui_file *stream, struct
       return;
     }
 
-  for (i = 0; i < length && things_printed < options->print_max; i += 1)
+  unsigned int print_max_chars = get_print_max_chars (options);
+  for (i = 0; i < length && things_printed < print_max_chars; i += 1)
     {
       /* Position of the character we are examining
 	 to see whether it is repeated.  */
@@ -706,12 +707,13 @@ ada_val_print_string (struct type *type,
      elements up to it.  */
   if (options->stop_print_at_null)
     {
+      unsigned int print_max_chars = get_print_max_chars (options);
       int temp_len;
 
       /* Look for a NULL char.  */
       for (temp_len = 0;
 	   (temp_len < len
-	    && temp_len < options->print_max
+	    && temp_len < print_max_chars
 	    && char_at (valaddr + offset_aligned,
 			temp_len, eltlen, byte_order) != 0);
 	   temp_len += 1);
Index: src/gdb/c-lang.c
===================================================================
--- src.orig/gdb/c-lang.c
+++ src/gdb/c-lang.c
@@ -185,8 +185,8 @@ language_defn::printchar (int c, struct
 /* Print the character string STRING, printing at most LENGTH
    characters.  LENGTH is -1 if the string is nul terminated.  Each
    character is WIDTH bytes long.  Printing stops early if the number
-   hits print_max; repeat counts are printed as appropriate.  Print
-   ellipses at the end if we had to stop before printing LENGTH
+   hits print_max_chars; repeat counts are printed as appropriate.
+   Print ellipses at the end if we had to stop before printing LENGTH
    characters, or if FORCE_ELLIPSES.  */
 
 void
Index: src/gdb/c-valprint.c
===================================================================
--- src.orig/gdb/c-valprint.c
+++ src/gdb/c-valprint.c
@@ -267,11 +267,12 @@ c_value_print_array (struct value *val,
 	     print elements up to it.  */
 	  if (options->stop_print_at_null)
 	    {
+	      unsigned int print_max_chars = get_print_max_chars (options);
 	      unsigned int temp_len;
 
 	      for (temp_len = 0;
 		   (temp_len < len
-		    && temp_len < options->print_max
+		    && temp_len < print_max_chars
 		    && extract_unsigned_integer (valaddr + temp_len * eltlen,
 						 eltlen, byte_order) != 0);
 		   ++temp_len)
@@ -280,7 +281,7 @@ c_value_print_array (struct value *val,
 	      /* Force printstr to print ellipses if
 		 we've printed the maximum characters and
 		 the next character is not \000.  */
-	      if (temp_len == options->print_max && temp_len < len)
+	      if (temp_len == print_max_chars && temp_len < len)
 		{
 		  ULONGEST ival
 		    = extract_unsigned_integer (valaddr + temp_len * eltlen,
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo
+++ src/gdb/doc/gdb.texinfo
@@ -10012,10 +10012,18 @@ Related setting: @ref{set print array}.
 Set printing of array indexes.
 Related setting: @ref{set print array-indexes}.
 
-@item -elements @var{number-of-elements}|@code{unlimited}
-Set limit on string chars or array elements to print.  The value
+@item -characters @var{number-of-characters}|@code{elements}|@code{unlimited}
+Set limit on string characters to print.  The value @code{elements}
+causes the limit on array elements to print to be used.  The value
 @code{unlimited} causes there to be no limit.  Related setting:
-@ref{set print elements}.
+@ref{set print characters}.
+
+@item -elements @var{number-of-elements}|@code{unlimited}
+Set limit on array elements and optionally string characters to print.
+See @ref{set print characters}, and the @code{-characters} option above
+for when this option applies to strings.  The value @code{unlimited}
+causes there to be no limit.  @xref{set print elements}, for a related
+CLI command.
 
 @item -max-depth @var{depth}|@code{unlimited}
 Set the threshold after which nested structures are replaced with
@@ -11385,6 +11393,31 @@ Stop printing element indexes when displ
 Show whether the index of each element is printed when displaying
 arrays.
 
+@anchor{set print characters}
+@item set print characters @var{number-of-characters}
+@itemx set print characters elements
+@itemx set print characters unlimited
+@cindex number of string characters to print
+@cindex limit on number of printed string characters
+Set a limit on how many characters of a string @value{GDBN} will print.
+If @value{GDBN} is printing a large string, it stops printing after it
+has printed the number of characters set by the @code{set print
+characters} command.  This equally applies to multi-byte and wide
+character strings, that is for strings whose character type is
+@code{wchar_t}, @code{char16_t}, or @code{char32_t} it is the number of
+actual characters rather than underlying bytes the encoding uses that
+this setting controls.
+Setting @var{number-of-characters} to @code{elements} means that the
+limit on the number of characters to print follows one for array
+elements; see @ref{set print elements}.
+Setting @var{number-of-characters} to @code{unlimited} means that the
+number of characters to print is unlimited.
+When @value{GDBN} starts, this limit is set to @code{elements}.
+
+@item show print characters
+Display the number of characters of a large string that @value{GDBN}
+will print.
+
 @anchor{set print elements}
 @item set print elements @var{number-of-elements}
 @itemx set print elements unlimited
@@ -11393,7 +11426,8 @@ arrays.
 Set a limit on how many elements of an array @value{GDBN} will print.
 If @value{GDBN} is printing a large array, it stops printing after it has
 printed the number of elements set by the @code{set print elements} command.
-This limit also applies to the display of strings.
+By default this limit also applies to the display of strings; see
+@ref{set print characters}.
 When @value{GDBN} starts, this limit is set to 200.
 Setting @var{number-of-elements} to @code{unlimited} or zero means
 that the number of elements to print is unlimited.
@@ -14896,7 +14930,7 @@ The optional @var{mods} changes the usua
 @code{s} requests that pointers to chars be handled as strings, in
 particular collecting the contents of the memory being pointed at, up
 to the first zero.  The upper bound is by default the value of the
-@code{print elements} variable; if @code{s} is followed by a decimal
+@code{print characters} variable; if @code{s} is followed by a decimal
 number, that is the upper bound instead.  So for instance
 @samp{collect/s25 mystr} collects as many as 25 characters at
 @samp{mystr}.
Index: src/gdb/doc/python.texi
===================================================================
--- src.orig/gdb/doc/python.texi
+++ src/gdb/doc/python.texi
@@ -1114,6 +1114,11 @@ the @emph{declared} type should be used.
 representation of a C@t{++} object, @code{False} if they shouldn't (see
 @code{set print static-members} in @ref{Print Settings}).
 
+@item max_characters
+Number of string characters to print, @code{0} to follow
+@code{max_elements}, or @code{UINT_MAX} to print an unlimited number
+of characters (see @code{set print characters} in @ref{Print Settings}).
+
 @item max_elements
 Number of array elements to print, or @code{0} to print an unlimited
 number of elements (see @code{set print elements} in @ref{Print
Index: src/gdb/language.h
===================================================================
--- src.orig/gdb/language.h
+++ src/gdb/language.h
@@ -534,7 +534,7 @@ struct language_defn
 			  struct ui_file * stream) const;
 
 /* Print the character string STRING, printing at most LENGTH characters.
-   Printing stops early if the number hits print_max; repeat counts
+   Printing stops early if the number hits print_max_chars; repeat counts
    are printed as appropriate.  Print ellipses at the end if we
    had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.  */
 
Index: src/gdb/m2-lang.c
===================================================================
--- src.orig/gdb/m2-lang.c
+++ src/gdb/m2-lang.c
@@ -169,7 +169,8 @@ m2_language::printstr (struct ui_file *s
       return;
     }
 
-  for (i = 0; i < length && things_printed < options->print_max; ++i)
+  unsigned int print_max_chars = get_print_max_chars (options);
+  for (i = 0; i < length && things_printed < print_max_chars; ++i)
     {
       /* Position of the character we are examining
 	 to see whether it is repeated.  */
Index: src/gdb/m2-valprint.c
===================================================================
--- src.orig/gdb/m2-valprint.c
+++ src/gdb/m2-valprint.c
@@ -327,12 +327,14 @@ m2_language::value_print_inner (struct v
 		 elements up to it.  */
 	      if (options->stop_print_at_null)
 		{
+		  unsigned int print_max_chars = get_print_max_chars (options);
 		  unsigned int temp_len;
 
 		  /* Look for a NULL char.  */
 		  for (temp_len = 0;
 		       (valaddr[temp_len]
-			&& temp_len < len && temp_len < options->print_max);
+			&& temp_len < len
+			&& temp_len < print_max_chars);
 		       temp_len++);
 		  len = temp_len;
 		}
Index: src/gdb/p-lang.c
===================================================================
--- src.orig/gdb/p-lang.c
+++ src/gdb/p-lang.c
@@ -253,7 +253,8 @@ pascal_language::printstr (struct ui_fil
       return;
     }
 
-  for (i = 0; i < length && things_printed < options->print_max; ++i)
+  unsigned int print_max_chars = get_print_max_chars (options);
+  for (i = 0; i < length && things_printed < print_max_chars; ++i)
     {
       /* Position of the character we are examining
 	 to see whether it is repeated.  */
Index: src/gdb/p-valprint.c
===================================================================
--- src.orig/gdb/p-valprint.c
+++ src/gdb/p-valprint.c
@@ -105,13 +105,16 @@ pascal_language::value_print_inner (stru
 		   elements up to it.  */
 		if (options->stop_print_at_null)
 		  {
+		    unsigned int print_max_chars
+		      = get_print_max_chars (options);
 		    unsigned int temp_len;
 
 		    /* Look for a NULL char.  */
 		    for (temp_len = 0;
-			 extract_unsigned_integer (valaddr + temp_len * eltlen,
-						   eltlen, byte_order)
-			   && temp_len < len && temp_len < options->print_max;
+			 (extract_unsigned_integer
+			    (valaddr + temp_len * eltlen, eltlen, byte_order)
+			  && temp_len < len
+			  && temp_len < print_max_chars);
 			 temp_len++);
 		    len = temp_len;
 		  }
Index: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c
+++ src/gdb/printcmd.c
@@ -957,17 +957,18 @@ find_string_backward (struct gdbarch *gd
 					 chars_to_read * char_size);
       chars_read /= char_size;
       read_error = (chars_read == chars_to_read) ? 0 : 1;
+      unsigned int print_max_chars = get_print_max_chars (options);
       /* Searching for '\0' from the end of buffer in backward direction.  */
       for (i = 0; i < chars_read && count > 0 ; ++i, ++chars_counted)
 	{
 	  int offset = (chars_to_read - i - 1) * char_size;
 
 	  if (integer_is_zero (&buffer[offset], char_size)
-	      || chars_counted == options->print_max)
+	      || chars_counted == print_max_chars)
 	    {
-	      /* Found '\0' or reached print_max.  As OFFSET is the offset to
-		 '\0', we add CHAR_SIZE to return the start address of
-		 a string.  */
+	      /* Found '\0' or reached `print_max_chars'.  As OFFSET
+		 is the offset to '\0', we add CHAR_SIZE to return
+		 the start address of a string.  */
 	      --count;
 	      string_start_addr = addr + offset + char_size;
 	      chars_counted = 0;
Index: src/gdb/python/py-value.c
===================================================================
--- src.orig/gdb/python/py-value.c
+++ src/gdb/python/py-value.c
@@ -645,6 +645,7 @@ valpy_format_string (PyObject *self, PyO
       "actual_objects",		/* See set print object on|off.  */
       "static_members",		/* See set print static-members on|off.  */
       /* C non-bool options.  */
+      "max_characters", 	/* See set print characters N.  */
       "max_elements", 		/* See set print elements N.  */
       "max_depth",		/* See set print max-depth N.  */
       "repeat_threshold",	/* See set print repeats.  */
@@ -691,7 +692,7 @@ valpy_format_string (PyObject *self, PyO
   char *format = NULL;
   if (!gdb_PyArg_ParseTupleAndKeywords (args,
 					kw,
-					"|O!O!O!O!O!O!O!O!O!O!O!IIIs",
+					"|O!O!O!O!O!O!O!O!O!O!O!IIIIs",
 					keywords,
 					&PyBool_Type, &raw_obj,
 					&PyBool_Type, &pretty_arrays_obj,
@@ -704,6 +705,7 @@ valpy_format_string (PyObject *self, PyO
 					&PyBool_Type, &deref_refs_obj,
 					&PyBool_Type, &actual_objects_obj,
 					&PyBool_Type, &static_members_obj,
+					&opts.print_max_chars,
 					&opts.print_max,
 					&opts.max_depth,
 					&opts.repeat_count_threshold,
Index: src/gdb/testsuite/gdb.base/default.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/default.exp
+++ src/gdb/testsuite/gdb.base/default.exp
@@ -522,6 +522,10 @@ gdb_test_no_output "set print address" "
 gdb_test_no_output "set print array" "set print array"
 #test set print asm-demangle
 gdb_test_no_output "set print asm-demangle" "set print asm-demangle"
+#test set print characters
+gdb_test "set print characters" \
+	 "Argument required \\(integer to set it to, or one of:\
+	  \"elements\", \"unlimited\"\\)\\."
 #test set print demangle
 gdb_test_no_output "set print demangle" "set print demangle"
 #test set print elements
@@ -665,6 +669,9 @@ gdb_test "show print address" "Printing
 gdb_test "show print array" "Pretty formatting of arrays is on."
 #test show print asm-demangle
 gdb_test "show print asm-demangle" "Demangling of C\[+\]+/ObjC names in disassembly listings is on."
+#test show print characters
+gdb_test "show print characters" \
+	 "Limit on string characters to print is elements\\."
 #test show print demangle
 gdb_test "show print demangle" "Demangling of encoded C\[+\]+/ObjC names when displaying symbols is on."
 #test show print elements
Index: src/gdb/testsuite/gdb.base/options.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/options.exp
+++ src/gdb/testsuite/gdb.base/options.exp
@@ -165,6 +165,7 @@ proc_with_prefix test-print {{prefix ""}
 	"-address"
 	"-array"
 	"-array-indexes"
+	"-characters"
 	"-elements"
 	"-max-depth"
 	"-memory-tag-violations"
Index: src/gdb/tracepoint.c
===================================================================
--- src.orig/gdb/tracepoint.c
+++ src/gdb/tracepoint.c
@@ -546,9 +546,9 @@ decode_agent_options (const char *exp, i
       if (target_supports_string_tracing ())
 	{
 	  /* Allow an optional decimal number giving an explicit maximum
-	     string length, defaulting it to the "print elements" value;
+	     string length, defaulting it to the "print characters" value;
 	     so "collect/s80 mystr" gets at most 80 bytes of string.  */
-	  *trace_string = opts.print_max;
+	  *trace_string = get_print_max_chars (&opts);
 	  exp++;
 	  if (*exp >= '0' && *exp <= '9')
 	    *trace_string = atoi (exp);
Index: src/gdb/valprint.c
===================================================================
--- src.orig/gdb/valprint.c
+++ src/gdb/valprint.c
@@ -97,8 +97,14 @@ static void val_print_type_code_flags (s
 				       int embedded_offset,
 				       struct ui_file *stream);
 
-#define PRINT_MAX_DEFAULT 200	/* Start print_max off at this value.  */
-#define PRINT_MAX_DEPTH_DEFAULT 20	/* Start print_max_depth off at this value. */
+/* Start print_max at this value.  */
+#define PRINT_MAX_DEFAULT 200
+
+/* Start print_max_chars at this value (meaning follow print_max).  */
+#define PRINT_MAX_CHARS_DEFAULT 0
+
+/* Start print_max_depth at this value. */
+#define PRINT_MAX_DEPTH_DEFAULT 20
 
 struct value_print_options user_print_options =
 {
@@ -110,6 +116,7 @@ struct value_print_options user_print_op
   1,				/* addressprint */
   0,				/* objectprint */
   PRINT_MAX_DEFAULT,		/* print_max */
+  PRINT_MAX_CHARS_DEFAULT,	/* print_max_chars */
   10,				/* repeat_count_threshold */
   0,				/* output_format */
   0,				/* format */
@@ -152,17 +159,31 @@ get_formatted_print_options (struct valu
   opts->format = format;
 }
 
+/* Implement 'show print elements'.  */
+
 static void
 show_print_max (struct ui_file *file, int from_tty,
 		struct cmd_list_element *c, const char *value)
 {
+  fprintf_filtered
+    (file,
+     (user_print_options.print_max_chars != 0
+      ? _("Limit on array elements to print is %s.\n")
+      : _("Limit on string chars or array elements to print is %s.\n")),
+     value);
+}
+
+/* Implement 'show print characters'.  */
+
+static void
+show_print_max_chars (struct ui_file *file, int from_tty,
+		      struct cmd_list_element *c, const char *value)
+{
   fprintf_filtered (file,
-		    _("Limit on string chars or array "
-		      "elements to print is %s.\n"),
+		    _("Limit on string characters to print is %s.\n"),
 		    value);
 }
 
-
 /* Default input and output radixes, and output format letter.  */
 
 unsigned input_radix = 10;
@@ -2594,9 +2615,9 @@ print_converted_chars_to_obstack (struct
 /* Print the character string STRING, printing at most LENGTH
    characters.  LENGTH is -1 if the string is nul terminated.  TYPE is
    the type of each character.  OPTIONS holds the printing options;
-   printing stops early if the number hits print_max; repeat counts
-   are printed as appropriate.  Print ellipses at the end if we had to
-   stop before printing LENGTH characters, or if FORCE_ELLIPSES.
+   printing stops early if the number hits print_max_chars; repeat
+   counts are printed as appropriate.  Print ellipses at the end if we
+   had to stop before printing LENGTH characters, or if FORCE_ELLIPSES.
    QUOTE_CHAR is the character to print at each end of the string.  If
    C_STYLE_TERMINATOR is true, and the last character is 0, then it is
    omitted.  */
@@ -2650,7 +2671,8 @@ generic_printstr (struct ui_file *stream
   /* Convert characters until the string is over or the maximum
      number of printed characters has been reached.  */
   i = 0;
-  while (i < options->print_max)
+  unsigned int print_max_chars = get_print_max_chars (options);
+  while (i < print_max_chars)
     {
       int r;
 
@@ -2702,7 +2724,7 @@ generic_printstr (struct ui_file *stream
 /* Print a string from the inferior, starting at ADDR and printing up to LEN
    characters, of WIDTH bytes a piece, to STREAM.  If LEN is -1, printing
    stops at the first null byte, otherwise printing proceeds (including null
-   bytes) until either print_max or LEN characters have been printed,
+   bytes) until either print_max_chars or LEN characters have been printed,
    whichever is smaller.  ENCODING is the name of the string's
    encoding.  It can be NULL, in which case the target encoding is
    assumed.  */
@@ -2724,15 +2746,17 @@ val_print_string (struct type *elttype,
   int width = TYPE_LENGTH (elttype);
 
   /* First we need to figure out the limit on the number of characters we are
-     going to attempt to fetch and print.  This is actually pretty simple.  If
-     LEN >= zero, then the limit is the minimum of LEN and print_max.  If
-     LEN is -1, then the limit is print_max.  This is true regardless of
-     whether print_max is zero, UINT_MAX (unlimited), or something in between,
-     because finding the null byte (or available memory) is what actually
-     limits the fetch.  */
+     going to attempt to fetch and print.  This is actually pretty simple.
+     If LEN >= zero, then the limit is the minimum of LEN and print_max_chars.
+     If LEN is -1, then the limit is print_max_chars.  This is true regardless
+     of whether print_max_chars is zero, UINT_MAX (unlimited), or something in
+     between, because finding the null byte (or available memory) is what
+     actually limits the fetch.  */
 
-  fetchlimit = (len == -1 ? options->print_max : std::min ((unsigned) len,
-							   options->print_max));
+  unsigned int print_max_chars = get_print_max_chars (options);
+  fetchlimit = (len == -1
+		? print_max_chars
+		: std::min ((unsigned) len, print_max_chars));
 
   err = read_string (addr, len, width, fetchlimit, byte_order,
 		     &buffer, &bytes_read);
@@ -2977,6 +3001,15 @@ using uinteger_option_def
 using integer_option_def
   = gdb::option::integer_option_def<value_print_options>;
 
+/* Extra literals supported with the `set print characters' and
+   `print -characters' commands.  */
+static const literal_def print_characters_literals[] =
+  {
+    { "elements", 0, 0, false },
+    { "unlimited", UINT_MAX, UINT_MAX, false },
+    { nullptr }
+  };
+
 /* Definitions of options for the "print" and "compile print"
    commands.  */
 static const gdb::option::option_def value_print_option_defs[] = {
@@ -3009,12 +3042,23 @@ static const gdb::option::option_def val
   },
 
   uinteger_option_def {
+    "characters",
+    [] (value_print_options *opt) { return &opt->print_max_chars; },
+    print_characters_literals,
+    show_print_max_chars, /* show_cmd_cb */
+    N_("Set limit on string chars to print."),
+    N_("Show limit on string chars to print."),
+    N_("\"elements\" causes the array element limit to be used.\n"
+       "\"unlimited\" causes there to be no limit."),
+  },
+
+  uinteger_option_def {
     "elements",
     [] (value_print_options *opt) { return &opt->print_max; },
     uinteger_unlimited_literals,
     show_print_max, /* show_cmd_cb */
-    N_("Set limit on string chars or array elements to print."),
-    N_("Show limit on string chars or array elements to print."),
+    N_("Set limit on array elements to print."),
+    N_("Show limit on array elements to print."),
     N_("\"unlimited\" causes there to be no limit."),
   },
 
Index: src/gdb/valprint.h
===================================================================
--- src.orig/gdb/valprint.h
+++ src/gdb/valprint.h
@@ -48,12 +48,15 @@ struct value_print_options
      in its vtables.  */
   bool objectprint;
 
-  /* Maximum number of chars to print for a string pointer value or vector
-     contents, or UINT_MAX for no limit.  Note that "set print elements 0"
-     stores UINT_MAX in print_max, which displays in a show command as
-     "unlimited".  */
+  /* Maximum number of elements to print for vector contents, or UINT_MAX
+     for no limit.  Note that "set print elements 0" stores UINT_MAX in
+     print_max, which displays in a show command as "unlimited".  */
   unsigned int print_max;
 
+  /* Maximum number of string chars to print for a string pointer value,
+     zero if to follow the value of print_max, or UINT_MAX for no limit.  */
+  unsigned int print_max_chars;
+
   /* Print repeat counts if there are more than this many repetitions
      of an element in an array.  */
   unsigned int repeat_count_threshold;
@@ -105,6 +108,15 @@ struct value_print_options
   bool finish_print;
 };
 
+/* Return the character count limit for printing strings.  */
+
+static inline unsigned int
+get_print_max_chars (const struct value_print_options *options)
+{
+  return (options->print_max_chars != 0
+	  ? options->print_max_chars : options->print_max);
+}
+
 /* Create an option_def_group for the value_print options, with OPTS
    as context.  */
 extern gdb::option::option_def_group make_value_print_options_def_group

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 8/8] GDB/testsuite: Expand for character string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (6 preceding siblings ...)
  2022-03-30 10:24 ` [PATCH v5 7/8] GDB: Add a character string limiting option Maciej W. Rozycki
@ 2022-03-30 10:24 ` Maciej W. Rozycki
  2022-04-13 11:20 ` [PING][PATCH v5 0/8] gdb: split array and " Maciej W. Rozycki
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:24 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

From: Andrew Burgess <andrew.burgess@embecosm.com>

Modify test cases that verify the operation of the array element limit 
with character strings such that they are executed twice, once with the 
`set print characters' option set to `elements' and the limit controlled 
with the `set print elements' option, and then again with the limit 
controlled with the `set print characters' option instead.  Similarly 
with the `-elements' and `-characters' options for the `print' command. 
Additionally verify that said `print' command options combined yield the 
expected result.

There are new tests for Ada and Pascal, as the string printing code for 
these languages is different than the generic string printing code used 
by other languages.  Modula2 also has different string printing code, 
but (a) this is similar to Pascal, and (b) there are no existing modula2 
tests written in Modula2, so I'm not sure how I'd even test the Modula2 
string printing.

Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
---
No changes from v4.

Changes from v3:

- split off from what is now 7/8; see the change log there for earlier 
  changes,

- remove test case modifications to switch from the `set print elements' 
  command to `set print characters'; instead run them twice with each of 
  the two commands verified,

- likewise with the `print -elements' and `print -characters' commands,

- also cover `print -elements ... -characters ...', i.e. both options 
  combined,

- expand the Ada and Pascal test cases to cover `set print characters
  elements' too.
---
 gdb/testsuite/gdb.ada/str_chars.exp           |   70 +++++++++++++++++++++++
 gdb/testsuite/gdb.ada/str_chars/foo.adb       |   26 ++++++++
 gdb/testsuite/gdb.base/printcmds.exp          |   77 ++++++++++++++++++--------
 gdb/testsuite/gdb.pascal/str-chars.exp        |   56 ++++++++++++++++++
 gdb/testsuite/gdb.pascal/str-chars.pas        |   28 +++++++++
 gdb/testsuite/gdb.python/py-format-string.exp |   47 ++++++++++-----
 6 files changed, 266 insertions(+), 38 deletions(-)

gdb-aburgess-print-elements-characters-test.diff
Index: src/gdb/testsuite/gdb.ada/str_chars.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.ada/str_chars.exp
@@ -0,0 +1,70 @@
+# Copyright 2022 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 'set print characters' setting works for Ada strings.
+
+load_lib "ada.exp"
+
+if { [skip_ada_tests] } { return -1 }
+
+standard_ada_testfile foo
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
+  return -1
+}
+
+clean_restart ${testfile}
+
+set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
+if ![runto "foo.adb:$bp_location" ] then {
+  return -1
+}
+
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with default settings"
+
+gdb_test_no_output "set print characters 26"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with character limit of 26"
+
+gdb_test "print -characters 11 -- Arg" \
+    " = \"abcdefghijk\"\\.\\.\\." \
+    "print with character limit of 11"
+
+gdb_test_no_output "set print characters 10"
+gdb_test "print Arg" \
+    " = \"abcdefghij\"\\.\\.\\." \
+    "print with character limit of 10"
+
+gdb_test_no_output "set print characters unlimited"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with unlimited character limit"
+
+# The 'set print elements' command used to control printing of characters
+# in a string, before we created 'set print characters'.  This test makes
+# sure that 'set print elements' doens't effect string printing any more.
+gdb_test_no_output "set print elements 12"
+gdb_test "print Arg" \
+    " = \"abcdefghijklmnopqrstuvwxyz\"" \
+    "print with unlimited character limit, but lower element limit"
+
+# Except when 'set print characters elements' has been used.
+gdb_test_no_output "set print characters elements"
+gdb_test "print Arg" \
+    " = \"abcdefghijkl\"\\.\\.\\." \
+    "print with character limit of elements"
Index: src/gdb/testsuite/gdb.ada/str_chars/foo.adb
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.ada/str_chars/foo.adb
@@ -0,0 +1,26 @@
+--  Copyright 2022 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/>.
+
+procedure Foo is
+
+   procedure Blah (Arg : String) is
+   begin
+     null; -- STOP
+   end;
+
+begin
+
+   Blah ("abcdefghijklmnopqrstuvwxyz");
+end Foo;
Index: src/gdb/testsuite/gdb.base/printcmds.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/printcmds.exp
+++ src/gdb/testsuite/gdb.base/printcmds.exp
@@ -453,11 +453,12 @@ proc test_print_all_chars {} {
 # Test interaction of the number of print elements to print and the
 # repeat count, set to the default of 10.
 
-proc test_print_repeats_10 {} {
+proc test_print_repeats_10_one { setting } {
     global gdb_prompt decimal
 
     for { set x 1 } { $x <= 16 } { incr x } {
-	gdb_test_no_output "set print elements $x" "elements $x repeats"
+	gdb_test_no_output "set print $setting $x" \
+	    "set print $setting $x repeats"
 	for { set e 1 } { $e <= 16 } {incr e } {
 	    set v [expr $e - 1]
 	    set command "p &ctable2\[${v}*16\]"
@@ -497,11 +498,19 @@ proc test_print_repeats_10 {} {
 		set xstr "${xstr}\[.\]\[.\]\[.\]"
 	    }
 	    set string " = \[(\]unsigned char \[*\]\[)\] <ctable2(\\+$decimal)?> ${a}${xstr}"
-	    gdb_test "$command" "$string" "$command with print elements set to $x"
+	    gdb_test "$command" "$string" \
+		"$command with print $setting set to $x"
 	}
     }
 }
 
+proc test_print_repeats_10 {} {
+    foreach_with_prefix setting { "elements" "characters" } {
+	test_print_repeats_10_one $setting
+    }
+    gdb_test_no_output "set print characters elements"
+}
+
 # This tests whether GDB uses the correct element content offsets
 # (relative to the complete `some_struct' value) when counting value
 # repetitions.
@@ -514,43 +523,38 @@ proc test_print_repeats_embedded_array {
 	"correct element repeats in array embedded at offset > 0"
 }
 
-proc test_print_strings {} {
+proc test_print_strings_one { setting } {
     global gdb_prompt decimal
 
     # We accept "(unsigned char *) " before the string.  char vs. unsigned char
     # is already tested elsewhere.
 
-    # Test that setting print elements unlimited doesn't completely suppress
-    # printing; this was a bug in older gdb's.
-    gdb_test_no_output "set print elements 0"
-    gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 0"
-    gdb_test_no_output "set print elements 1"
+    gdb_test_no_output "set print $setting 1"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"t\"\\.\\.\\." "p teststring with elements set to 1"
-    gdb_test_no_output "set print elements 5"
+	" = (.unsigned char .. )?\"t\"\\.\\.\\." "p teststring with $setting set to 1"
+    gdb_test_no_output "set print $setting 5"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"tests\"\\.\\.\\." "p teststring with elements set to 5"
-    gdb_test_no_output "set print elements 19"
+	" = (.unsigned char .. )?\"tests\"\\.\\.\\." "p teststring with $setting set to 5"
+    gdb_test_no_output "set print $setting 19"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 19"
-    gdb_test_no_output "set print elements 20"
+	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with $setting set to 19"
+    gdb_test_no_output "set print $setting 20"
     gdb_test "p teststring" \
-	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 20"
+	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with $setting set to 20"
 
-    gdb_test "p -elements 1 -- teststring" \
+    gdb_test "p -$setting 1 -- teststring" \
 	" = (.unsigned char .. )?\"t\"\\.\\.\\."
-    gdb_test "p -elements 5 -- teststring" \
+    gdb_test "p -$setting 5 -- teststring" \
 	" = (.unsigned char .. )?\"tests\"\\.\\.\\."
-    gdb_test "p -elements 19 -- teststring" \
+    gdb_test "p -$setting 19 -- teststring" \
 	" = (.unsigned char .. )?\"teststring contents\""
-    gdb_test "p -elements 20 -- teststring" \
+    gdb_test "p -$setting 20 -- teststring" \
 	" = (.unsigned char .. )?\"teststring contents\""
 
     gdb_test "print teststring2" \
 	" = \\(charptr\\) \"more contents\""
 
-    gdb_test_no_output "set print elements 8"
+    gdb_test_no_output "set print $setting 8"
 
     # Set the target-charset to ASCII, because the output varies from
     # different charset.
@@ -622,6 +626,35 @@ proc test_print_strings {} {
 	gdb_test "p &ctable1\[31*8\]" \
 	    " = \\(unsigned char \\*\\) <ctable1\\+$decimal> \"\\\\370\\\\371\\\\372\\\\373\\\\374\\\\375\\\\376\\\\377\"..."
     }
+
+    gdb_test_no_output "set print $setting unlimited"
+}
+
+proc test_print_strings {} {
+
+    # Test that setting print elements unlimited doesn't completely suppress
+    # printing; this was a bug in older gdb's.
+    gdb_test_no_output "set print elements 0"
+    gdb_test "p teststring" \
+	" = (.unsigned char .. )?\"teststring contents\"" \
+	"p teststring with elements set to 0"
+
+    gdb_test "set print characters 0" "integer 0 out of range"
+
+    foreach_with_prefix setting { "elements" "characters" } {
+	test_print_strings_one $setting
+    }
+
+    gdb_test "p -elements 8 -- teststring" \
+	" = (.unsigned char .. )?\"teststring contents\""
+    gdb_test "p -characters 8 -- teststring" \
+	" = (.unsigned char .. )?\"teststri\"\\.\\.\\."
+    gdb_test "p -elements 8 -characters elements -- teststring" \
+	" = (.unsigned char .. )?\"teststri\"\\.\\.\\."
+
+    with_test_prefix strings {
+	gdb_test_no_output "set print characters elements"
+    }
 }
 
 proc test_print_int_arrays {} {
Index: src/gdb/testsuite/gdb.pascal/str-chars.exp
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.pascal/str-chars.exp
@@ -0,0 +1,56 @@
+# Copyright 2022 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/>.
+
+load_lib "pascal.exp"
+
+standard_testfile .pas
+
+if {[gdb_compile_pascal "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug ]] != "" } {
+  return -1
+}
+
+clean_restart ${testfile}
+gdb_breakpoint ${srcfile}:[gdb_get_line_number "set breakpoint 1 here"]
+
+# Verify that "start" lands inside the right procedure.
+if { [gdb_start_cmd] < 0 } {
+    untested start
+    return -1
+}
+
+gdb_continue_to_breakpoint "continue to breakpoint"
+
+gdb_test "print message" " = 'abcdefghijklmnopqrstuvwxyz'" \
+    "print message with the default settings"
+
+gdb_test_no_output "set print elements 10"
+gdb_test "print message" " = 'abcdefghij'\\.\\.\\." \
+    "print message with 'print elements' set to 10"
+
+gdb_test_no_output "set print characters 20"
+gdb_test "print message" " = 'abcdefghijklmnopqrst'\\.\\.\\." \
+    "print message with 'print characters' set to 20"
+
+gdb_test_no_output "set print elements 15"
+gdb_test "print message" " = 'abcdefghijklmnopqrst'\\.\\.\\." \
+    "print message with 'print elements' set to 15"
+
+gdb_test_no_output "set print characters unlimited"
+gdb_test "print message" " = 'abcdefghijklmnopqrstuvwxyz'" \
+    "print message with 'print characters' set to unlimited"
+
+gdb_test_no_output "set print characters elements"
+gdb_test "print message" " = 'abcdefghijklmno'\\.\\.\\." \
+    "print message with 'print characters' set to elements"
Index: src/gdb/testsuite/gdb.pascal/str-chars.pas
===================================================================
--- /dev/null
+++ src/gdb/testsuite/gdb.pascal/str-chars.pas
@@ -0,0 +1,28 @@
+{
+ Copyright 2022 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/>.
+}
+
+program str_char;
+
+var
+   message : string;
+
+begin
+
+   message := 'abcdefghijklmnopqrstuvwxyz';
+   writeln (message)	{ set breakpoint 1 here }
+
+end.
Index: src/gdb/testsuite/gdb.python/py-format-string.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.python/py-format-string.exp
+++ src/gdb/testsuite/gdb.python/py-format-string.exp
@@ -632,13 +632,13 @@ proc_with_prefix test_static_members {}
 }
 
 # Test the max_elements option for gdb.Value.format_string.
-proc_with_prefix test_max_elements {} {
+proc test_max_string_one { setting unlimited } {
   global current_lang
   global default_pointer_regexp
 
   # 200 is the default maximum number of elements, so setting it should
   # not change the output.
-  set opts "max_elements=200"
+  set opts "max_$setting=200"
   with_test_prefix $opts {
     check_format_string "a_point_t" $opts
     check_format_string "a_point_t_pointer" $opts
@@ -649,8 +649,10 @@ proc_with_prefix test_max_elements {} {
     check_format_string "a_binary_string" $opts
     check_format_string "a_binary_string_array" $opts
     check_format_string "a_big_string" $opts
-    check_format_string "an_array" $opts
-    check_format_string "an_array_with_repetition" $opts
+    if { $setting == "elements"} {
+      check_format_string "an_array" $opts
+      check_format_string "an_array_with_repetition" $opts
+    }
     check_format_string "a_symbol_pointer" $opts
 
     if { $current_lang == "c++" } {
@@ -659,7 +661,7 @@ proc_with_prefix test_max_elements {} {
     }
   }
 
-  set opts "max_elements=3"
+  set opts "max_$setting=3"
   with_test_prefix $opts {
     check_format_string "a_point_t" $opts
     check_format_string "a_point_t_pointer" $opts
@@ -676,9 +678,11 @@ proc_with_prefix test_max_elements {} {
       "\"hell\"..."
     check_format_string "a_big_string" $opts \
       [get_cut_big_string 3]
-    check_format_string "an_array" $opts
-    check_format_string "an_array_with_repetition" $opts \
-      "\\{1, 3 <repeats 12 times>...\\}"
+    if { $setting == "elements"} {
+      check_format_string "an_array" $opts
+      check_format_string "an_array_with_repetition" $opts \
+	"\\{1, 3 <repeats 12 times>...\\}"
+    }
     check_format_string "a_symbol_pointer" $opts
 
     if { $current_lang == "c++" } {
@@ -687,9 +691,9 @@ proc_with_prefix test_max_elements {} {
     }
   }
 
-  # Both 1,000 (we don't have that many elements) and 0 (unlimited) should
+  # Both 1,000 (we don't have that many elements) and unlimited should
   # mean no truncation.
-  foreach opts { "max_elements=1000" "max_elements=0" } {
+  foreach opts [list "max_$setting=1000" "max_$setting=$unlimited"] {
     with_test_prefix $opts {
       check_format_string "a_point_t" $opts
       check_format_string "a_point_t_pointer" $opts
@@ -701,8 +705,10 @@ proc_with_prefix test_max_elements {} {
       check_format_string "a_binary_string_array" $opts
       check_format_string "a_big_string" $opts \
         [get_cut_big_string 1000]
-      check_format_string "an_array" $opts
-      check_format_string "an_array_with_repetition" $opts
+      if { $setting == "elements"} {
+	check_format_string "an_array" $opts
+	check_format_string "an_array_with_repetition" $opts
+      }
       check_format_string "a_symbol_pointer" $opts
 
       if { $current_lang == "c++" } {
@@ -712,15 +718,24 @@ proc_with_prefix test_max_elements {} {
     }
   }
 
-  with_temp_option "set print elements 4" "set print elements 200" {
+  with_temp_option "set print $setting 4" "set print $setting 200" {
     check_format_string "a_string" "" \
       "${default_pointer_regexp} \"hell\"..."
     check_format_string "a_binary_string" "" \
       "${default_pointer_regexp} \"hell\"..."
     check_format_string "a_binary_string_array" "" \
       "\"hell\"..."
-    check_format_string "an_array_with_repetition" "" \
-      "\\{1, 3 <repeats 12 times>...\\}"
+    if { $setting == "elements"} {
+      check_format_string "an_array_with_repetition" "" \
+	"\\{1, 3 <repeats 12 times>...\\}"
+    }
+  }
+}
+
+proc_with_prefix test_max_string {} {
+  foreach_with_prefix setting { "elements" "characters" } {
+    test_max_string_one $setting \
+      [string map {elements 0 characters 4294967295} $setting]
   }
 }
 
@@ -1013,7 +1028,7 @@ proc_with_prefix test_all_common {} {
   test_deref_refs
   test_actual_objects
   test_static_members
-  test_max_elements
+  test_max_string
   test_max_depth
   test_repeat_threshold
   test_format

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-03-30 10:23 ` [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited' Maciej W. Rozycki
@ 2022-03-30 10:35   ` Simon Sobisch
  2022-03-30 10:40     ` Maciej W. Rozycki
  2022-06-24 14:40   ` Andrew Burgess
  1 sibling, 1 reply; 51+ messages in thread
From: Simon Sobisch @ 2022-03-30 10:35 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey

That seems like it should be mentioned in NEWS as it possibly affects
existing python extensions (if the commit that was fixed landed in an
official release).

Am 30.03.2022 um 12:23 schrieb Maciej W. Rozycki:
> Consistently with the `var_integer' and `var_uinteger' parameters return
> the special value of None for a `var_zuinteger_unlimited' parameter set
> to `unlimited' by using the Py_RETURN_NONE macro in this case, fixing
> commit 0489430a0e1a ("Handle var_zuinteger and var_zuinteger_unlimited
> from Python"); cf. PR python/20084.  Adjust the testsuite accordingly.
> ---
> No change from v4.
>
> New change in v4.
> ---
>   gdb/python/python.c                       |   10 +++++++++-
>   gdb/testsuite/gdb.python/py-parameter.exp |    4 ++--
>   2 files changed, 11 insertions(+), 3 deletions(-)
>
> gdb-python-var-zuinteger-unlimited-none.diff
> Index: src/gdb/python/python.c
> ===================================================================
> --- src.orig/gdb/python/python.c
> +++ src/gdb/python/python.c
> @@ -507,9 +507,17 @@ gdbpy_parameter_value (const setting &va
>   	Py_RETURN_NONE;
>         /* Fall through.  */
>       case var_zinteger:
> -    case var_zuinteger_unlimited:
>         return gdb_py_object_from_longest (var.get<int> ()).release ();
>
> +    case var_zuinteger_unlimited:
> +      {
> +	int val = var.get<int> ();
> +
> +	if (val == -1)
> +	  Py_RETURN_NONE;
> +	return gdb_py_object_from_longest (val).release ();
> +      }
> +
>       case var_uinteger:
>         {
>   	unsigned int val = var.get<unsigned int> ();
> Index: src/gdb/testsuite/gdb.python/py-parameter.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.python/py-parameter.exp
> +++ src/gdb/testsuite/gdb.python/py-parameter.exp
> @@ -343,8 +343,8 @@ proc_with_prefix test_integer_parameter
>   	} elseif {$kind == "PARAM_ZUINTEGER_UNLIMITED"} {
>   	    gdb_test_no_output "python test_param_$kind.value = -1" \
>   		"check that PARAM_ZUINTEGER value can be set to -1"
> -	    gdb_test "python print(gdb.parameter('test-$kind'))" "-1" \
> -		"check that PARAM_ZUINTEGER value is -1 after setting"
> +	    gdb_test "python print(gdb.parameter('test-$kind'))" "None" \
> +		"check that PARAM_ZUINTEGER value is None after setting"
>   	} else {
>   	    error "invalid kind: $kind"
>   	}

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-03-30 10:35   ` Simon Sobisch
@ 2022-03-30 10:40     ` Maciej W. Rozycki
  2022-03-30 10:50       ` Simon Sobisch
  0 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:40 UTC (permalink / raw)
  To: Simon Sobisch; +Cc: gdb-patches, Andrew Burgess, Simon Marchi, Tom Tromey

On Wed, 30 Mar 2022, Simon Sobisch wrote:

> That seems like it should be mentioned in NEWS as it possibly affects
> existing python extensions (if the commit that was fixed landed in an
> official release).

 Hmm, do we mention bug fixes in NEWS?

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands
  2022-03-30 10:24 ` [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands Maciej W. Rozycki
@ 2022-03-30 10:42   ` Simon Sobisch
  2022-03-30 10:58     ` Maciej W. Rozycki
  2022-06-28 14:04   ` Andrew Burgess
  1 sibling, 1 reply; 51+ messages in thread
From: Simon Sobisch @ 2022-03-30 10:42 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey


Am 30.03.2022 um 12:24 schrieb Maciej W. Rozycki:
> Rather than just `unlimited' allow the integer set commands (or command
> options) to define arbitrary keywords for the user to use, removing
> hardcoded arrangements for the `unlimited' keyword.
>
> Make obsolete the confusingly named `var_zinteger', `var_zuinteger' and
> `var_zuinteger_unlimited' `set'/`show' command variable types redefining
> them in terms of `var_uinteger', `var_integer' and `var_pinteger', which
> have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.

Those "confusingly named" parts go into python, too; maybe someone could
create a follow-up patch or adjust this one.
I think keeping them aligned is very useful (if renamed the old python
names should stay as aliases for the new ones, and ideally the doc
should reference a "until GDB 12: named ..." entry as this helps a lot
when creating python extensions).

 From the docs:

----------------------------------------------------------------

gdb.PARAM_ZINTEGER

     The value is an integer. This is like PARAM_INTEGER, except 0 is
interpreted as itself.
gdb.PARAM_ZUINTEGER

     The value is an unsigned integer. This is like PARAM_INTEGER,
except 0 is interpreted as itself, and the value cannot be negative.
gdb.PARAM_ZUINTEGER_UNLIMITED

     The value is a signed integer. This is like PARAM_ZUINTEGER, except
the special value -1 should be interpreted to mean “unlimited”. Other
negative values are not allowed.

----------------------------------------------------------------

Simon


>
> Following existing practice `var_pinteger' allows extra negative values
> to be used, however unlike `var_zuinteger_unlimited' any number of such
> values can be defined rather than just `-1'.
>
> The "p" in `var_pinteger' stands for "positive", for the lack of a more
> appropriate unambiguous letter, even though 0 obviously is not positive;
> "n" would be confusing as to whether it stands for "non-negative" or
> "negative".
>
> Add a new structure, `literal_def', the entries of which define extra
> keywords allowed for a command and numerical values they correspond to.
> Those values are not verified against the basic range supported by the
> underlying variable type, allowing extra values to be allowed outside
> that range, which may or may not be individually made visible to the
> user.  An optional value translation is possible with the structure to
> follow the existing practice for some commands where user-entered 0 is
> internally translated to UINT_MAX or INT_MAX.  Such translation can now
> be arbitrary.  Literals defined by this structure are automatically used
> for completion as necessary.
>
> So for example:
>
> const literal_def integer_unlimited_literals[] =
>    {
>      { "unlimited", 0, INT_MAX, true },
>      { nullptr }
>    };
>
> defines an extra `unlimited' keyword and a user-visible 0 value, both of
> which get translated to INT_MAX for the setting to be used with.
>
> Similarly:
>
> const literal_def zuinteger_unlimited_literals[] =
>    {
>      { "unlimited", -1, -1, true },
>      { nullptr }
>    };
>
> defines the same keyword and a corresponding user-visible -1 value that is
> used for the requested setting.  If the last member was set to `false'
> here, then only the keyword would be allowed for the user to enter and
> while -1 would still be used internally trying to enter it as a part of a
> command would result in an "integer -1 out of range" error.
>
> The obsolete command variable types still remain for Guile and Python
> use.  Eventually they need to be removed, however that would require a
> further rework of our Guile and Python support code.  Given that these
> variable types have been exported as keywords for those languages, those
> definitions have to stay, however it would be better to redefine them in
> terms of the modern variable types and overall export a better interface
> that reflects the flexibility of our core code now.
>
> There is no user-visible change from this rework, so no documentation or
> testsuite updates.
> ---
> Hi,
>
>   NB I have observed that the value of INT_MIN is not correctly handled:
> internally -2147483648 is interpreted as 2147483648 and consequently such
> a value is rejected, e.g:
>
> (gdb) show heuristic-fence-post
> The distance searched for the start of a function is 0.
> (gdb) set heuristic-fence-post -2147483647
> (gdb) show heuristic-fence-post
> The distance searched for the start of a function is -2147483647.
> (gdb) set heuristic-fence-post -2147483648
> integer 2147483648 out of range
> (gdb)
>
> umm... (not that it makes sense to set negative values for the heuristic
> fence post, but that's irrelevant here).  I haven't tried to track the
> root cause for this.
>
>    Maciej
>
> No change from v4.
>
> New change in v4.
> ---
>   gdb/cli/cli-cmds.c       |   56 ++++----
>   gdb/cli/cli-decode.c     |  302 ++++++++++++++++++++++++++++++++++++++---------
>   gdb/cli/cli-option.c     |  116 +++++++++++-------
>   gdb/cli/cli-option.h     |   34 +++--
>   gdb/cli/cli-setshow.c    |  249 ++++++++++++++++++--------------------
>   gdb/cli/cli-setshow.h    |   20 +--
>   gdb/command.h            |  108 ++++++++++++++--
>   gdb/guile/scm-param.c    |  102 +++++++++------
>   gdb/maint-test-options.c |    4
>   gdb/python/py-param.c    |   39 ++++--
>   gdb/python/python.c      |   49 +++----
>   gdb/valprint.c           |    9 -
>   12 files changed, 716 insertions(+), 372 deletions(-)
>
> gdb-setshow-cmd-extra-literals.diff
> Index: src/gdb/cli/cli-cmds.c
> ===================================================================
> --- src.orig/gdb/cli/cli-cmds.c
> +++ src/gdb/cli/cli-cmds.c
> @@ -2200,22 +2200,37 @@ value_from_setting (const setting &var,
>   {
>     switch (var.type ())
>       {
> +    case var_uinteger:
>       case var_integer:
> -      if (var.get<int> () == INT_MAX)
> -	return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				   0);
> -      else
> -	return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				   var.get<int> ());
> -    case var_zinteger:
> -      return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				 var.get<int> ());
> +    case var_pinteger:
> +      {
> +	LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
> +
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		value = l->val;
> +		break;
> +	      }
> +
> +	if (var.type () == var_uinteger)
> +	  return
> +	    value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
> +				 static_cast<const unsigned int> (value));
> +	else
> +	  return
> +	    value_from_longest (builtin_type (gdbarch)->builtin_int,
> +				static_cast<const int> (value));
> +      }
>       case var_boolean:
>         return value_from_longest (builtin_type (gdbarch)->builtin_int,
>   				 var.get<bool> () ? 1 : 0);
> -    case var_zuinteger_unlimited:
> -      return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				 var.get<int> ());
>       case var_auto_boolean:
>         {
>   	int val;
> @@ -2237,17 +2252,6 @@ value_from_setting (const setting &var,
>   	return value_from_longest (builtin_type (gdbarch)->builtin_int,
>   				   val);
>         }
> -    case var_uinteger:
> -      if (var.get<unsigned int> () == UINT_MAX)
> -	return value_from_ulongest
> -	  (builtin_type (gdbarch)->builtin_unsigned_int, 0);
> -      else
> -	return value_from_ulongest
> -	  (builtin_type (gdbarch)->builtin_unsigned_int,
> -	   var.get<unsigned int> ());
> -    case var_zuinteger:
> -      return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
> -				  var.get<unsigned int> ());
>       case var_string:
>       case var_string_noescape:
>       case var_optional_filename:
> @@ -2317,13 +2321,11 @@ str_value_from_setting (const setting &v
>   {
>     switch (var.type ())
>       {
> +    case var_uinteger:
>       case var_integer:
> -    case var_zinteger:
> +    case var_pinteger:
>       case var_boolean:
> -    case var_zuinteger_unlimited:
>       case var_auto_boolean:
> -    case var_uinteger:
> -    case var_zuinteger:
>         {
>   	std::string cmd_val = get_setshow_command_value_string (var);
>
> Index: src/gdb/cli/cli-decode.c
> ===================================================================
> --- src.orig/gdb/cli/cli-decode.c
> +++ src/gdb/cli/cli-decode.c
> @@ -580,11 +580,51 @@ add_setshow_cmd_full_erased (const char
>     return {set, show};
>   }
>
> +/* Completes on integer commands that support extra literals.  */
> +
> +static void
> +integer_literals_completer (struct cmd_list_element *c,
> +			    completion_tracker &tracker,
> +			    const char *text, const char *word)
> +{
> +  const literal_def *extra_literals = c->var->extra_literals ();
> +
> +  if (*text == '\0')
> +    {
> +      tracker.add_completion (make_unique_xstrdup ("NUMBER"));
> +      for (const literal_def *l = extra_literals;
> +	   l->literal != nullptr;
> +	   l++)
> +	tracker.add_completion (make_unique_xstrdup (l->literal));
> +    }
> +  else
> +    for (const literal_def *l = extra_literals;
> +	 l->literal != nullptr;
> +	 l++)
> +      if (startswith (l->literal, text))
> +	tracker.add_completion (make_unique_xstrdup (l->literal));
> +}
> +
> +/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
> +   THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are
> +   setting.  VAR is address of the variable being controlled by this
> +   command.  EXTRA_LITERALS if non-NULL define extra literals to be
> +   accepted in lieu of a number for integer variables.  If nullptr is
> +   given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must
> +   be provided. SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks
> +   used to access and modify the underlying property, whatever its
> +   storage is.  SET_FUNC and SHOW_FUNC are the callback functions
> +   (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the
> +   documentation strings.
> +
> +   Return the newly created set and show commands.  */
> +
>   template<typename T>
>   static set_show_commands
>   add_setshow_cmd_full (const char *name,
>   		      enum command_class theclass,
>   		      var_types var_type, T *var,
> +		      const literal_def *extra_literals,
>   		      const char *set_doc, const char *show_doc,
>   		      const char *help_doc,
>   		      typename setting_func_types<T>::set set_setting_func,
> @@ -595,18 +635,44 @@ add_setshow_cmd_full (const char *name,
>   		      struct cmd_list_element **show_list)
>   {
>     auto erased_args
> -    = setting::erase_args (var_type, var,
> +    = setting::erase_args (var_type, var, extra_literals,
>   			   set_setting_func, get_setting_func);
> +  auto cmds = add_setshow_cmd_full_erased (name,
> +					   theclass,
> +					   var_type, erased_args,
> +					   set_doc, show_doc,
> +					   help_doc,
> +					   set_func,
> +					   show_func,
> +					   set_list,
> +					   show_list);
>
> -  return add_setshow_cmd_full_erased (name,
> -				      theclass,
> -				      var_type, erased_args,
> -				      set_doc, show_doc,
> -				      help_doc,
> -				      set_func,
> -				      show_func,
> -				      set_list,
> -				      show_list);
> +  if (extra_literals != nullptr)
> +    set_cmd_completer (cmds.set, integer_literals_completer);
> +
> +  return cmds;
> +}
> +
> +/* Same as above but omitting EXTRA_LITERALS.  */
> +
> +template<typename T>
> +static set_show_commands
> +add_setshow_cmd_full (const char *name,
> +		      enum command_class theclass,
> +		      var_types var_type, T *var,
> +		      const char *set_doc, const char *show_doc,
> +		      const char *help_doc,
> +		      typename setting_func_types<T>::set set_setting_func,
> +		      typename setting_func_types<T>::get get_setting_func,
> +		      cmd_func_ftype *set_func,
> +		      show_value_ftype *show_func,
> +		      struct cmd_list_element **set_list,
> +		      struct cmd_list_element **show_list)
> +{
> +  return add_setshow_cmd_full (name, theclass, var_type, var, nullptr,
> +			       set_doc, show_doc, help_doc,
> +			       set_setting_func, get_setting_func,
> +			       set_func, show_func, set_list, show_list);
>   }
>
>   /* Add element named NAME to command list LIST (the list for set or
> @@ -975,25 +1041,6 @@ add_setshow_optional_filename_cmd (const
>     return cmds;
>   }
>
> -/* Completes on literal "unlimited".  Used by integer commands that
> -   support a special "unlimited" value.  */
> -
> -static void
> -integer_unlimited_completer (struct cmd_list_element *ignore,
> -			     completion_tracker &tracker,
> -			     const char *text, const char *word)
> -{
> -  static const char * const keywords[] =
> -    {
> -      "unlimited",
> -      NULL,
> -    };
> -
> -  if (*text == '\0')
> -    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
> -  complete_on_enum (tracker, keywords, text, word);
> -}
> -
>   /* Add element named NAME to both the set and show command LISTs (the
>      list for set/show or some sublist thereof).  CLASS is as in
>      add_cmd.  VAR is address of the variable which will contain the
> @@ -1002,6 +1049,55 @@ integer_unlimited_completer (struct cmd_
>
>   set_show_commands
>   add_setshow_integer_cmd (const char *name, enum command_class theclass,
> +			 int *var, const literal_def *extra_literals,
> +			 const char *set_doc, const char *show_doc,
> +			 const char *help_doc,
> +			 cmd_func_ftype *set_func,
> +			 show_value_ftype *show_func,
> +			 struct cmd_list_element **set_list,
> +			 struct cmd_list_element **show_list)
> +{
> +  set_show_commands commands
> +    = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
> +				 extra_literals, set_doc, show_doc,
> +				 help_doc, nullptr, nullptr, set_func,
> +				 show_func, set_list, show_list);
> +  return commands;
> +}
> +
> +/* Same as above but using a getter and a setter function instead of a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_integer_cmd (const char *name, command_class theclass,
> +			 const literal_def *extra_literals,
> +			 const char *set_doc, const char *show_doc,
> +			 const char *help_doc,
> +			 setting_func_types<int>::set set_func,
> +			 setting_func_types<int>::get get_func,
> +			 show_value_ftype *show_func,
> +			 cmd_list_element **set_list,
> +			 cmd_list_element **show_list)
> +{
> +  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
> +					 extra_literals, set_doc, show_doc,
> +					 help_doc, set_func, get_func, nullptr,
> +					 show_func, set_list, show_list);
> +  return cmds;
> +}
> +
> +/* Accept `unlimited' or 0, translated internally to INT_MAX.  */
> +const literal_def integer_unlimited_literals[] =
> +  {
> +    { "unlimited", 0, INT_MAX, true },
> +    { nullptr }
> +  };
> +
> +/* Same as above but using `integer_unlimited_literals', with a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_integer_cmd (const char *name, enum command_class theclass,
>   			 int *var,
>   			 const char *set_doc, const char *show_doc,
>   			 const char *help_doc,
> @@ -1012,12 +1108,10 @@ add_setshow_integer_cmd (const char *nam
>   {
>     set_show_commands commands
>       = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
> +				 integer_unlimited_literals,
>   				 set_doc, show_doc, help_doc,
>   				 nullptr, nullptr, set_func,
>   				 show_func, set_list, show_list);
> -
> -  set_cmd_completer (commands.set, integer_unlimited_completer);
> -
>     return commands;
>   }
>
> @@ -1035,12 +1129,54 @@ add_setshow_integer_cmd (const char *nam
>   			 cmd_list_element **show_list)
>   {
>     auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
> +					 integer_unlimited_literals,
>   					 set_doc, show_doc, help_doc, set_func,
>   					 get_func, nullptr, show_func, set_list,
>   					 show_list);
> +  return cmds;
> +}
>
> -  set_cmd_completer (cmds.set, integer_unlimited_completer);
> +/* Add element named NAME to both the set and show command LISTs (the
> +   list for set/show or some sublist thereof).  CLASS is as in
> +   add_cmd.  VAR is address of the variable which will contain the
> +   value.  SET_DOC and SHOW_DOC are the documentation strings.  */
> +
> +set_show_commands
> +add_setshow_pinteger_cmd (const char *name, enum command_class theclass,
> +			  int *var, const literal_def *extra_literals,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  cmd_func_ftype *set_func,
> +			  show_value_ftype *show_func,
> +			  struct cmd_list_element **set_list,
> +			  struct cmd_list_element **show_list)
> +{
> +  set_show_commands commands
> +    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
> +				 extra_literals, set_doc, show_doc,
> +				 help_doc, nullptr, nullptr, set_func,
> +				 show_func, set_list, show_list);
> +  return commands;
> +}
>
> +/* Same as above but using a getter and a setter function instead of a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_pinteger_cmd (const char *name, command_class theclass,
> +			  const literal_def *extra_literals,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  setting_func_types<int>::set set_func,
> +			  setting_func_types<int>::get get_func,
> +			  show_value_ftype *show_func,
> +			  cmd_list_element **set_list,
> +			  cmd_list_element **show_list)
> +{
> +  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
> +					 extra_literals, set_doc, show_doc,
> +					 help_doc, set_func, get_func, nullptr,
> +					 show_func, set_list, show_list);
>     return cmds;
>   }
>
> @@ -1051,7 +1187,7 @@ add_setshow_integer_cmd (const char *nam
>
>   set_show_commands
>   add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
> -			  unsigned int *var,
> +			  unsigned int *var, const literal_def *extra_literals,
>   			  const char *set_doc, const char *show_doc,
>   			  const char *help_doc,
>   			  cmd_func_ftype *set_func,
> @@ -1061,12 +1197,9 @@ add_setshow_uinteger_cmd (const char *na
>   {
>     set_show_commands commands
>       = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
> -					  set_doc, show_doc, help_doc,
> -					  nullptr, nullptr, set_func,
> +					  extra_literals, set_doc, show_doc,
> +					  help_doc, nullptr, nullptr, set_func,
>   					  show_func, set_list, show_list);
> -
> -  set_cmd_completer (commands.set, integer_unlimited_completer);
> -
>     return commands;
>   }
>
> @@ -1075,6 +1208,7 @@ add_setshow_uinteger_cmd (const char *na
>
>   set_show_commands
>   add_setshow_uinteger_cmd (const char *name, command_class theclass,
> +			  const literal_def *extra_literals,
>   			  const char *set_doc, const char *show_doc,
>   			  const char *help_doc,
>   			  setting_func_types<unsigned int>::set set_func,
> @@ -1084,13 +1218,63 @@ add_setshow_uinteger_cmd (const char *na
>   			  cmd_list_element **show_list)
>   {
>     auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
> -						  nullptr, set_doc, show_doc,
> -						  help_doc, set_func, get_func,
> -						  nullptr, show_func, set_list,
> +						  nullptr, extra_literals,
> +						  set_doc, show_doc, help_doc,
> +						  set_func, get_func, nullptr,
> +						  show_func, set_list,
>   						  show_list);
> +  return cmds;
> +}
>
> -  set_cmd_completer (cmds.set, integer_unlimited_completer);
> +/* Accept `unlimited' or 0, translated internally to UINT_MAX.  */
> +const literal_def uinteger_unlimited_literals[] =
> +  {
> +    { "unlimited", 0, UINT_MAX, true },
> +    { nullptr }
> +  };
> +
> +/* Same as above but using `uinteger_unlimited_literals', with a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
> +			  unsigned int *var,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  cmd_func_ftype *set_func,
> +			  show_value_ftype *show_func,
> +			  struct cmd_list_element **set_list,
> +			  struct cmd_list_element **show_list)
> +{
> +  set_show_commands commands
> +    = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
> +					  uinteger_unlimited_literals,
> +					  set_doc, show_doc, help_doc, nullptr,
> +					  nullptr, set_func, show_func,
> +					  set_list, show_list);
> +  return commands;
> +}
> +
> +/* Same as above but using a getter and a setter function instead of a pointer
> +   to a global storage buffer.  */
>
> +set_show_commands
> +add_setshow_uinteger_cmd (const char *name, command_class theclass,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  setting_func_types<unsigned int>::set set_func,
> +			  setting_func_types<unsigned int>::get get_func,
> +			  show_value_ftype *show_func,
> +			  cmd_list_element **set_list,
> +			  cmd_list_element **show_list)
> +{
> +  auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
> +						  nullptr,
> +						  uinteger_unlimited_literals,
> +						  set_doc, show_doc, help_doc,
> +						  set_func, get_func, nullptr,
> +						  show_func, set_list,
> +						  show_list);
>     return cmds;
>   }
>
> @@ -1109,7 +1293,7 @@ add_setshow_zinteger_cmd (const char *na
>   			  struct cmd_list_element **set_list,
>   			  struct cmd_list_element **show_list)
>   {
> -  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, var,
> +  return add_setshow_cmd_full<int> (name, theclass, var_integer, var,
>   				    set_doc, show_doc, help_doc,
>   				    nullptr, nullptr, set_func,
>   				    show_func, set_list, show_list);
> @@ -1128,12 +1312,22 @@ add_setshow_zinteger_cmd (const char *na
>   			  cmd_list_element **set_list,
>   			  cmd_list_element **show_list)
>   {
> -  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, nullptr,
> +  return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
>   				    set_doc, show_doc, help_doc, set_func,
>   				    get_func, nullptr, show_func, set_list,
>   				    show_list);
>   }
>
> +/* Accept `unlimited' or -1, using -1 internally.  */
> +const literal_def zuinteger_unlimited_literals[] =
> +  {
> +    { "unlimited", -1, -1, true },
> +    { nullptr }
> +  };
> +
> +/* Same as above but using `zuinteger_unlimited_literals', with a pointer
> +   to a global storage buffer.  */
> +
>   set_show_commands
>   add_setshow_zuinteger_unlimited_cmd (const char *name,
>   				     enum command_class theclass,
> @@ -1147,13 +1341,11 @@ add_setshow_zuinteger_unlimited_cmd (con
>   				     struct cmd_list_element **show_list)
>   {
>     set_show_commands commands
> -    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, var,
> +    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
> +				 zuinteger_unlimited_literals,
>   				 set_doc, show_doc, help_doc, nullptr,
>   				 nullptr, set_func, show_func, set_list,
>   				 show_list);
> -
> -  set_cmd_completer (commands.set, integer_unlimited_completer);
> -
>     return commands;
>   }
>
> @@ -1171,13 +1363,11 @@ add_setshow_zuinteger_unlimited_cmd (con
>   				     cmd_list_element **show_list)
>   {
>     auto cmds
> -    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited,
> -				 nullptr, set_doc, show_doc, help_doc, set_func,
> +    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
> +				 zuinteger_unlimited_literals,
> +				 set_doc, show_doc, help_doc, set_func,
>   				 get_func, nullptr, show_func, set_list,
>   				 show_list);
> -
> -  set_cmd_completer (cmds.set, integer_unlimited_completer);
> -
>     return cmds;
>   }
>
> @@ -1196,7 +1386,7 @@ add_setshow_zuinteger_cmd (const char *n
>   			   struct cmd_list_element **set_list,
>   			   struct cmd_list_element **show_list)
>   {
> -  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
> +  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
>   					     var, set_doc, show_doc, help_doc,
>   					     nullptr, nullptr, set_func,
>   					     show_func, set_list, show_list);
> @@ -1215,7 +1405,7 @@ add_setshow_zuinteger_cmd (const char *n
>   			   cmd_list_element **set_list,
>   			   cmd_list_element **show_list)
>   {
> -  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
> +  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
>   					     nullptr, set_doc, show_doc,
>   					     help_doc, set_func, get_func,
>   					     nullptr, show_func, set_list,
> Index: src/gdb/cli/cli-option.c
> ===================================================================
> --- src.orig/gdb/cli/cli-option.c
> +++ src/gdb/cli/cli-option.c
> @@ -38,7 +38,7 @@ union option_value
>     /* For var_uinteger options.  */
>     unsigned int uinteger;
>
> -  /* For var_zuinteger_unlimited options.  */
> +  /* For var_integer and var_pinteger options.  */
>     int integer;
>
>     /* For var_enum options.  */
> @@ -356,42 +356,55 @@ parse_option (gdb::array_view<const opti
>   	return option_def_and_value {*match, match_ctx, val};
>         }
>       case var_uinteger:
> -    case var_zuinteger_unlimited:
> +    case var_integer:
> +    case var_pinteger:
>         {
>   	if (completion != nullptr)
>   	  {
> -	    if (**args == '\0')
> -	      {
> -		/* Convenience to let the user know what the option
> -		   can accept.  Note there's no common prefix between
> -		   the strings on purpose, so that readline doesn't do
> -		   a partial match.  */
> -		completion->tracker.add_completion
> -		  (make_unique_xstrdup ("NUMBER"));
> -		completion->tracker.add_completion
> -		  (make_unique_xstrdup ("unlimited"));
> -		return {};
> -	      }
> -	    else if (startswith ("unlimited", *args))
> +	    if (match->extra_literals != nullptr)
>   	      {
> -		completion->tracker.add_completion
> -		  (make_unique_xstrdup ("unlimited"));
> -		return {};
> +		/* Convenience to let the user know what the option can
> +		   accept.  Make sure there's no common prefix between
> +		   "NUMBER" and all the strings when adding new ones,
> +		   so that readline doesn't do a partial match.  */
> +		if (**args == '\0')
> +		  {
> +		    completion->tracker.add_completion
> +		      (make_unique_xstrdup ("NUMBER"));
> +		    for (const literal_def *l = match->extra_literals;
> +			 l->literal != nullptr;
> +			 l++)
> +		      completion->tracker.add_completion
> +			(make_unique_xstrdup (l->literal));
> +		    return {};
> +		  }
> +		else
> +		  {
> +		    bool completions = false;
> +		    for (const literal_def *l = match->extra_literals;
> +			 l->literal != nullptr;
> +			 l++)
> +		      if (startswith (l->literal, *args))
> +			{
> +			  completion->tracker.add_completion
> +			    (make_unique_xstrdup (l->literal));
> +			  completions = true;
> +			}
> +		    if (completions)
> +		      return {};
> +		  }
>   	      }
>   	  }
>
> -	if (match->type == var_zuinteger_unlimited)
> -	  {
> -	    option_value val;
> -	    val.integer = parse_cli_var_zuinteger_unlimited (args, false);
> -	    return option_def_and_value {*match, match_ctx, val};
> -	  }
> +	LONGEST v = parse_cli_var_integer (match->type,
> +					   match->extra_literals,
> +					   args, false);
> +	option_value val;
> +	if (match->type == var_uinteger)
> +	  val.uinteger = v;
>   	else
> -	  {
> -	    option_value val;
> -	    val.uinteger = parse_cli_var_uinteger (match->type, args, false);
> -	    return option_def_and_value {*match, match_ctx, val};
> -	  }
> +	  val.integer = v;
> +	return option_def_and_value {*match, match_ctx, val};
>         }
>       case var_enum:
>         {
> @@ -593,7 +606,7 @@ save_option_value_in_ctx (gdb::optional<
>         *ov->option.var_address.uinteger (ov->option, ov->ctx)
>   	= ov->value->uinteger;
>         break;
> -    case var_zuinteger_unlimited:
> +    case var_integer:
>         *ov->option.var_address.integer (ov->option, ov->ctx)
>   	= ov->value->integer;
>         break;
> @@ -664,8 +677,20 @@ get_val_type_str (const option_def &opt,
>       case var_boolean:
>         return "[on|off]";
>       case var_uinteger:
> -    case var_zuinteger_unlimited:
> -      return "NUMBER|unlimited";
> +    case var_integer:
> +    case var_pinteger:
> +      {
> +	buffer = "NUMBER";
> +	if (opt.extra_literals != nullptr)
> +	  for (const literal_def *l = opt.extra_literals;
> +	       l->literal != nullptr;
> +	       l++)
> +	    {
> +	      buffer += '|';
> +	      buffer += l->literal;
> +	    }
> +	return buffer.c_str ();
> +      }
>       case var_enum:
>         {
>   	buffer = "";
> @@ -789,20 +814,31 @@ add_setshow_cmds_for_options (command_cl
>   	{
>   	  add_setshow_uinteger_cmd (option.name, cmd_class,
>   				    option.var_address.uinteger (option, data),
> +				    option.extra_literals,
>   				    option.set_doc, option.show_doc,
>   				    option.help_doc,
>   				    nullptr, option.show_cmd_cb,
>   				    set_list, show_list);
>   	}
> -      else if (option.type == var_zuinteger_unlimited)
> +      else if (option.type == var_integer)
>   	{
> -	  add_setshow_zuinteger_unlimited_cmd
> -	    (option.name, cmd_class,
> -	     option.var_address.integer (option, data),
> -	     option.set_doc, option.show_doc,
> -	     option.help_doc,
> -	     nullptr, option.show_cmd_cb,
> -	     set_list, show_list);
> +	  add_setshow_integer_cmd (option.name, cmd_class,
> +				   option.var_address.integer (option, data),
> +				   option.extra_literals,
> +				   option.set_doc, option.show_doc,
> +				   option.help_doc,
> +				   nullptr, option.show_cmd_cb,
> +				   set_list, show_list);
> +	}
> +      else if (option.type == var_pinteger)
> +	{
> +	  add_setshow_pinteger_cmd (option.name, cmd_class,
> +				    option.var_address.integer (option, data),
> +				    option.extra_literals,
> +				    option.set_doc, option.show_doc,
> +				    option.help_doc,
> +				    nullptr, option.show_cmd_cb,
> +				    set_list, show_list);
>   	}
>         else if (option.type == var_enum)
>   	{
> Index: src/gdb/cli/cli-option.h
> ===================================================================
> --- src.orig/gdb/cli/cli-option.h
> +++ src/gdb/cli/cli-option.h
> @@ -49,12 +49,13 @@ struct option_def
>        used to create the option's "set/show" commands.  */
>     constexpr option_def (const char *name_,
>   			var_types var_type_,
> +			const literal_def *extra_literals_,
>   			erased_get_var_address_ftype *erased_get_var_address_,
>   			show_value_ftype *show_cmd_cb_,
>   			const char *set_doc_,
>   			const char *show_doc_,
>   			const char *help_doc_)
> -    : name (name_), type (var_type_),
> +    : name (name_), type (var_type_), extra_literals (extra_literals_),
>         erased_get_var_address (erased_get_var_address_),
>         var_address {},
>         show_cmd_cb (show_cmd_cb_),
> @@ -68,6 +69,9 @@ struct option_def
>     /* The option's type.  */
>     var_types type;
>
> +  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
> +  const literal_def *extra_literals;
> +
>     /* A function that gets the controlling variable's address, type
>        erased.  */
>     erased_get_var_address_ftype *erased_get_var_address;
> @@ -160,7 +164,7 @@ struct boolean_option_def : option_def
>   		      const char *set_doc_,
>   		      const char *show_doc_ = nullptr,
>   		      const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_boolean,
> +    : option_def (long_option_, var_boolean, nullptr,
>   		  (erased_get_var_address_ftype *) get_var_address_cb_,
>   		  show_cmd_cb_,
>   		  set_doc_, show_doc_, help_doc_)
> @@ -207,11 +211,12 @@ struct uinteger_option_def : option_def
>   {
>     uinteger_option_def (const char *long_option_,
>   		       unsigned int *(*get_var_address_cb_) (Context *),
> +		       const literal_def *extra_literals_,
>   		       show_value_ftype *show_cmd_cb_,
>   		       const char *set_doc_,
>   		       const char *show_doc_ = nullptr,
>   		       const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_uinteger,
> +    : option_def (long_option_, var_uinteger, extra_literals_,
>   		  (erased_get_var_address_ftype *) get_var_address_cb_,
>   		  show_cmd_cb_,
>   		  set_doc_, show_doc_, help_doc_)
> @@ -220,18 +225,19 @@ struct uinteger_option_def : option_def
>     }
>   };
>
> -/* A var_zuinteger_unlimited command line option.  */
> +/* A var_integer command line option.  */
>
>   template<typename Context>
> -struct zuinteger_unlimited_option_def : option_def
> +struct integer_option_def : option_def
>   {
> -  zuinteger_unlimited_option_def (const char *long_option_,
> -				  int *(*get_var_address_cb_) (Context *),
> -				  show_value_ftype *show_cmd_cb_,
> -				  const char *set_doc_,
> -				  const char *show_doc_ = nullptr,
> -				  const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_zuinteger_unlimited,
> +  integer_option_def (const char *long_option_,
> +		      int *(*get_var_address_cb_) (Context *),
> +		      const literal_def *extra_literals_,
> +		      show_value_ftype *show_cmd_cb_,
> +		      const char *set_doc_,
> +		      const char *show_doc_ = nullptr,
> +		      const char *help_doc_ = nullptr)
> +    : option_def (long_option_, var_integer, extra_literals_,
>   		  (erased_get_var_address_ftype *) get_var_address_cb_,
>   		  show_cmd_cb_,
>   		  set_doc_, show_doc_, help_doc_)
> @@ -252,7 +258,7 @@ struct enum_option_def : option_def
>   		   const char *set_doc_,
>   		   const char *show_doc_ = nullptr,
>   		   const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_enum,
> +    : option_def (long_option_, var_enum, nullptr,
>   		  (erased_get_var_address_ftype *) get_var_address_cb_,
>   		  show_cmd_cb_,
>   		  set_doc_, show_doc_, help_doc_)
> @@ -273,7 +279,7 @@ struct string_option_def : option_def
>   		     const char *set_doc_,
>   		     const char *show_doc_ = nullptr,
>   		     const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_string,
> +    : option_def (long_option_, var_string, nullptr,
>   		  (erased_get_var_address_ftype *) get_var_address_cb_,
>   		  show_cmd_cb_,
>   		  set_doc_, show_doc_, help_doc_)
> Index: src/gdb/cli/cli-setshow.c
> ===================================================================
> --- src.orig/gdb/cli/cli-setshow.c
> +++ src/gdb/cli/cli-setshow.c
> @@ -149,10 +149,11 @@ deprecated_show_value_hack (struct ui_fi
>       }
>   }
>
> -/* Returns true if ARG is "unlimited".  */
> +/* Returns true and the value in VAL if ARG is an accepted literal.  */
>
>   static bool
> -is_unlimited_literal (const char **arg, bool expression)
> +get_literal_val (LONGEST &val, const literal_def *extra_literals,
> +		 const char **arg, bool expression)
>   {
>     *arg = skip_spaces (*arg);
>
> @@ -162,85 +163,108 @@ is_unlimited_literal (const char **arg,
>
>     size_t len = p - *arg;
>
> -  if (len > 0 && strncmp ("unlimited", *arg, len) == 0)
> -    {
> -      *arg += len;
> -
> -      /* If parsing an expression (i.e., parsing for a "set" command),
> -	 anything after "unlimited" is junk.  For options, anything
> -	 after "unlimited" might be a command argument or another
> -	 option.  */
> -      if (expression)
> +  if (len > 0 && extra_literals != nullptr)
> +    for (const literal_def *l = extra_literals;
> +	 l->literal != nullptr;
> +	 l++)
> +      if (strncmp (l->literal, *arg, len) == 0)
>   	{
> -	  const char *after = skip_spaces (*arg);
> -	  if (*after != '\0')
> -	    error (_("Junk after \"%.*s\": %s"),
> -		   (int) len, unl_start, after);
> -	}
> +	  *arg += len;
>
> -      return true;
> -    }
> +	  /* If parsing an expression (i.e., parsing for a "set" command),
> +	     anything after the literal is junk.  For options, anything
> +	     after the literal might be a command argument or another
> +	     option.  */
> +	  if (expression)
> +	    {
> +	      const char *after = skip_spaces (*arg);
> +	      if (*after != '\0')
> +		error (_("Junk after \"%.*s\": %s"),
> +		       (int) len, unl_start, after);
> +	    }
> +
> +	  val = l->use;
> +	  return true;
> +	}
>
>     return false;
>   }
>
>   /* See cli-setshow.h.  */
>
> -unsigned int
> -parse_cli_var_uinteger (var_types var_type, const char **arg,
> -			bool expression)
> +LONGEST
> +parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
> +		       const char **arg, bool expression)
>   {
>     LONGEST val;
>
>     if (*arg == nullptr || **arg == '\0')
>       {
> -      if (var_type == var_uinteger)
> -	error_no_arg (_("integer to set it to, or \"unlimited\""));
> -      else
> +      if (extra_literals == nullptr)
>   	error_no_arg (_("integer to set it to"));
> -    }
> -
> -  if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
> -    val = 0;
> -  else if (expression)
> -    val = parse_and_eval_long (*arg);
> -  else
> -    val = get_ulongest (arg);
> -
> -  if (var_type == var_uinteger && val == 0)
> -    val = UINT_MAX;
> -  else if (val < 0
> -	   /* For var_uinteger, don't let the user set the value
> -	      to UINT_MAX directly, as that exposes an
> -	      implementation detail to the user interface.  */
> -	   || (var_type == var_uinteger && val >= UINT_MAX)
> -	   || (var_type == var_zuinteger && val > UINT_MAX))
> -    error (_("integer %s out of range"), plongest (val));
> -
> -  return val;
> -}
> -
> -/* See cli-setshow.h.  */
> +      else
> +	{
> +	  std::string buffer = "";
> +	  size_t count = 0;
>
> -int
> -parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
> -{
> -  LONGEST val;
> +	  for (const literal_def *l = extra_literals;
> +	       l->literal != nullptr;
> +	       l++, count++)
> +	    {
> +	      if (count != 0)
> +		buffer += ", ";
> +	      buffer = buffer + '"' + l->literal + '"';
> +	    }
> +	  if (count > 1)
> +	    error_no_arg
> +	      (string_printf (_("integer to set it to, or one of: %s"),
> +			      buffer.c_str ()).c_str ());
> +	  else
> +	    error_no_arg
> +	      (string_printf (_("integer to set it to, or %s"),
> +			      buffer.c_str ()).c_str ());
> +	}
> +    }
>
> -  if (*arg == nullptr || **arg == '\0')
> -    error_no_arg (_("integer to set it to, or \"unlimited\""));
> +  if (!get_literal_val (val, extra_literals, arg, expression))
> +    {
> +      if (expression)
> +	val = parse_and_eval_long (*arg);
> +      else
> +	val = get_ulongest (arg);
>
> -  if (is_unlimited_literal (arg, expression))
> -    val = -1;
> -  else if (expression)
> -    val = parse_and_eval_long (*arg);
> -  else
> -    val = get_ulongest (arg);
> +      enum tribool allowed = TRIBOOL_UNKNOWN;
> +      if (extra_literals != nullptr)
> +	{
> +	  for (const literal_def *l = extra_literals;
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (val == l->val)
> +	      {
> +		allowed = l->allow ? TRIBOOL_TRUE : TRIBOOL_FALSE;
> +		val = l->use;
> +		break;
> +	      }
> +	    else if (val == l->use)
> +	      {
> +		allowed = TRIBOOL_FALSE;
> +		break;
> +	      }
> +	}
>
> -  if (val > INT_MAX)
> -    error (_("integer %s out of range"), plongest (val));
> -  else if (val < -1)
> -    error (_("only -1 is allowed to set as unlimited"));
> +      if (allowed == TRIBOOL_UNKNOWN)
> +	{
> +	  if (var_type == var_pinteger && val < 0)
> +	    error (_("only -1 is allowed to set as unlimited"));
> +	  else if (val > UINT_MAX || val < INT_MIN
> +		   || (var_type == var_uinteger && val < 0)
> +		   || (var_type == var_integer && val > INT_MAX)
> +		   || (var_type == var_pinteger && val > INT_MAX))
> +	    allowed = TRIBOOL_FALSE;
> +	}
> +      if (allowed == TRIBOOL_FALSE)
> +	error (_("integer %s out of range"), plongest (val));
> +    }
>
>     return val;
>   }
> @@ -405,41 +429,18 @@ do_set_command (const char *arg, int fro
>         option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg));
>         break;
>       case var_uinteger:
> -    case var_zuinteger:
>         option_changed
> -	= c->var->set<unsigned int> (parse_cli_var_uinteger (c->var->type (),
> -							     &arg, true));
> +	= c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (),
> +							    c->var->
> +							    extra_literals (),
> +							    &arg, true));
>         break;
>       case var_integer:
> -    case var_zinteger:
> -      {
> -	LONGEST val;
> -
> -	if (*arg == '\0')
> -	  {
> -	    if (c->var->type () == var_integer)
> -	      error_no_arg (_("integer to set it to, or \"unlimited\""));
> -	    else
> -	      error_no_arg (_("integer to set it to"));
> -	  }
> -
> -	if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
> -	  val = 0;
> -	else
> -	  val = parse_and_eval_long (arg);
> -
> -	if (val == 0 && c->var->type () == var_integer)
> -	  val = INT_MAX;
> -	else if (val < INT_MIN
> -		 /* For var_integer, don't let the user set the value
> -		    to INT_MAX directly, as that exposes an
> -		    implementation detail to the user interface.  */
> -		 || (c->var->type () == var_integer && val >= INT_MAX)
> -		 || (c->var->type () == var_zinteger && val > INT_MAX))
> -	  error (_("integer %s out of range"), plongest (val));
> -
> -	option_changed = c->var->set<int> (val);
> -      }
> +    case var_pinteger:
> +      option_changed
> +	= c->var->set<int> (parse_cli_var_integer (c->var->type (),
> +						   c->var->extra_literals (),
> +						   &arg, true));
>         break;
>       case var_enum:
>         {
> @@ -454,10 +455,6 @@ do_set_command (const char *arg, int fro
>   	option_changed = c->var->set<const char *> (match);
>         }
>         break;
> -    case var_zuinteger_unlimited:
> -      option_changed = c->var->set<int>
> -	(parse_cli_var_zuinteger_unlimited (&arg, true));
> -      break;
>       default:
>         error (_("gdb internal error: bad var_type in do_setshow_command"));
>       }
> @@ -551,7 +548,6 @@ do_set_command (const char *arg, int fro
>   	  }
>   	  break;
>   	case var_uinteger:
> -	case var_zuinteger:
>   	  {
>   	    char s[64];
>
> @@ -560,8 +556,7 @@ do_set_command (const char *arg, int fro
>   	  }
>   	  break;
>   	case var_integer:
> -	case var_zinteger:
> -	case var_zuinteger_unlimited:
> +	case var_pinteger:
>   	  {
>   	    char s[64];
>
> @@ -623,36 +618,32 @@ get_setshow_command_value_string (const
>   	}
>         break;
>       case var_uinteger:
> -    case var_zuinteger:
> -      {
> -	const unsigned int value = var.get<unsigned int> ();
> -
> -	if (var.type () == var_uinteger
> -	    && value == UINT_MAX)
> -	  stb.puts ("unlimited");
> -	else
> -	  stb.printf ("%u", value);
> -      }
> -      break;
>       case var_integer:
> -    case var_zinteger:
> +    case var_pinteger:
>         {
> -	const int value = var.get<int> ();
> +	bool printed = false;
> +	const LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
>
> -	if (var.type () == var_integer
> -	    && value == INT_MAX)
> -	  stb.puts ("unlimited");
> -	else
> -	  stb.printf ("%d", value);
> -      }
> -      break;
> -    case var_zuinteger_unlimited:
> -      {
> -	const int value = var.get<int> ();
> -	if (value == -1)
> -	  stb.puts ("unlimited");
> -	else
> -	  stb.printf ("%d", value);
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		stb.puts (l->literal);
> +		printed = true;
> +		break;
> +	      }
> +	if (!printed)
> +	  {
> +	    if (var.type () == var_uinteger)
> +	      stb.printf ("%u", static_cast<const unsigned int> (value));
> +	    else
> +	      stb.printf ("%d", static_cast<const int> (value));
> +	  }
>         }
>         break;
>       default:
> Index: src/gdb/cli/cli-setshow.h
> ===================================================================
> --- src.orig/gdb/cli/cli-setshow.h
> +++ src/gdb/cli/cli-setshow.h
> @@ -29,21 +29,19 @@ extern int parse_cli_boolean_value (cons
>      past a successfully parsed value.  */
>   extern int parse_cli_boolean_value (const char **arg);
>
> -/* Parse ARG, an option to a var_uinteger or var_zuinteger variable.
> -   Either returns the parsed value on success or throws an error.  If
> -   EXPRESSION is true, *ARG is parsed as an expression; otherwise, it
> -   is parsed with get_ulongest.  It's not possible to parse the
> +/* Parse ARG, an option to a var_uinteger, var_integer or var_pinteger
> +   variable.  Return the parsed value on success or throw an error.  If
> +   EXTRA_LITERALS is non-null, then interpret those literals accordingly.
> +   If EXPRESSION is true, *ARG is parsed as an expression; otherwise,
> +   it is parsed with get_ulongest.  It's not possible to parse the
>      integer as an expression when there may be valid input after the
>      integer, such as when parsing command options.  E.g., "print
>      -elements NUMBER -obj --".  In such case, parsing as an expression
>      would parse "-obj --" as part of the expression as well.  */
> -extern unsigned int parse_cli_var_uinteger (var_types var_type,
> -					    const char **arg,
> -					    bool expression);
> -
> -/* Like parse_cli_var_uinteger, for var_zuinteger_unlimited.  */
> -extern int parse_cli_var_zuinteger_unlimited (const char **arg,
> -					      bool expression);
> +extern LONGEST parse_cli_var_integer (var_types var_type,
> +				      const literal_def *extra_literals,
> +				      const char **arg,
> +				      bool expression);
>
>   /* Parse ARG, an option to a var_enum variable.  ENUM is a
>      null-terminated array of possible values. Either returns the parsed
> Index: src/gdb/command.h
> ===================================================================
> --- src.orig/gdb/command.h
> +++ src/gdb/command.h
> @@ -84,16 +84,18 @@ typedef enum var_types
>          value.  */
>       var_auto_boolean,
>
> -    /* Unsigned Integer.  *VAR is an unsigned int.  The user can type
> -       0 to mean "unlimited", which is stored in *VAR as UINT_MAX.  */
> +    /* Unsigned Integer.  *VAR is an unsigned int.  In the Guile and Python
> +       APIs 0 means unlimited, which is stored in *VAR as UINT_MAX.  */
>       var_uinteger,
>
> -    /* Like var_uinteger but signed.  *VAR is an int.  The user can
> -       type 0 to mean "unlimited", which is stored in *VAR as
> -       INT_MAX.  The only remaining use of it is the Python API.
> -       Don't use it elsewhere.  */
> +    /* Like var_uinteger but signed.  *VAR is an int.  In the Guile and
> +       Python APIs 0 means unlimited, which is stored in *VAR as INT_MAX.  */
>       var_integer,
>
> +    /* Like var_integer but negative numbers are not allowed,
> +       except for special values.  *VAR is an int.  */
> +    var_pinteger,
> +
>       /* String which the user enters with escapes (e.g. the user types
>          \n and it is a real newline in the stored string).
>          *VAR is a std::string, "" if the string is empty.  */
> @@ -106,15 +108,16 @@ typedef enum var_types
>       var_optional_filename,
>       /* String which stores a filename.  (*VAR) is a std::string.  */
>       var_filename,
> -    /* ZeroableInteger.  *VAR is an int.  Like var_integer except
> -       that zero really means zero.  */
> +    /* Like var_integer.  *VAR is an int.  The only remaining uses
> +       of it are the Guile and Python APIs.  Don't use it elsewhere.  */
>       var_zinteger,
> -    /* ZeroableUnsignedInteger.  *VAR is an unsigned int.  Zero really
> -       means zero.  */
> +    /* Like var_uinteger.  *VAR is an unsigned int.  The only remaining
> +       uses of it are the Guile and Python APIs.  Don't use it elsewhere.  */
>       var_zuinteger,
> -    /* ZeroableUnsignedInteger with unlimited value.  *VAR is an int,
> -       but its range is [0, INT_MAX].  -1 stands for unlimited and
> -       other negative numbers are not allowed.  */
> +    /* Like var_pinteger.  *VAR is an int, but its range is [-1, INT_MAX].
> +       -1 stands for unlimited and other negative numbers are not allowed.
> +       The only remaining uses of it are the Guile and Python APIs.  Don't
> +       use it elsewhere.  */
>       var_zuinteger_unlimited,
>       /* Enumerated type.  Can only have one of the specified values.
>          *VAR is a char pointer to the name of the element that we
> @@ -123,6 +126,22 @@ typedef enum var_types
>     }
>   var_types;
>
> +/* A structure describing an extra literal accepted and shown in place
> +   of a number.  */
> +typedef struct literal_defs
> +  {
> +    /* The literal to define, e.g. "unlimited".  */
> +    const char *literal;
> +    /* A number optionally accepted that stands for the literal.  */
> +    LONGEST val;
> +    /* The number to substitute internally for LITERAL or VAL;
> +       the use of this number is not allowed (unless the same as VAL).  */
> +    LONGEST use;
> +    /* True if the use of VAL is allowed; otherwise only the literal is.  */
> +    bool allow;
> +  }
> +literal_def;
> +
>   /* Return true if a setting of type VAR_TYPE is backed with type T.
>
>      This function is left without definition intentionally.  This template is
> @@ -153,15 +172,14 @@ inline bool var_type_uses<enum auto_bool
>   template<>
>   inline bool var_type_uses<unsigned int> (var_types t)
>   {
> -  return (t == var_uinteger || t == var_zinteger || t == var_zuinteger);
> +  return t == var_uinteger;
>   }
>
>   /* Return true if a setting of type T is backed by an int variable.  */
>   template<>
>   inline bool var_type_uses<int> (var_types t)
>   {
> -  return (t == var_integer || t == var_zinteger
> -	  || t == var_zuinteger_unlimited);
> +  return t == var_integer || t == var_pinteger;
>   }
>
>   /* Return true if a setting of type T is backed by a std::string variable.  */
> @@ -233,6 +251,7 @@ struct setting
>     struct erased_args
>     {
>       void *var;
> +    const void *extra_literals;
>       erased_func setter;
>       erased_func getter;
>     };
> @@ -240,6 +259,7 @@ struct setting
>     template<typename T>
>     static erased_args erase_args (var_types var_type,
>   				 T *var,
> +				 const literal_def *extra_literals,
>   				 typename setting_func_types<T>::set set_setting_func,
>   				 typename setting_func_types<T>::get get_setting_func)
>     {
> @@ -254,6 +274,7 @@ struct setting
>
>       return {
>   	var,
> +	extra_literals,
>   	reinterpret_cast<erased_func> (set_setting_func),
>   	reinterpret_cast<erased_func> (get_setting_func)
>       };
> @@ -265,6 +286,7 @@ struct setting
>     setting (var_types var_type, const erased_args &args)
>       : m_var_type (var_type),
>         m_var (args.var),
> +      m_extra_literals (args.extra_literals),
>         m_getter (args.getter),
>         m_setter (args.setter)
>     {
> @@ -295,6 +317,10 @@ struct setting
>     var_types type () const
>     { return m_var_type; }
>
> +  /* Access any extra literals accepted.  */
> +  const literal_def *extra_literals () const
> +  { return static_cast<const literal_def *> (m_extra_literals); }
> +
>     /* Return the current value.
>
>        The template parameter T is the type of the variable used to store the
> @@ -357,6 +383,9 @@ struct setting
>        non-nullptr.  */
>     void *m_var = nullptr;
>
> +  /* Any extra literals accepted.  */
> +  const void *m_extra_literals = nullptr;
> +
>     /* Pointer to a user provided getter.  */
>     erased_func m_getter = nullptr;
>
> @@ -652,6 +681,11 @@ typedef void (show_value_ftype) (struct
>      instead print the value out directly.  */
>   extern show_value_ftype deprecated_show_value_hack;
>
> +/* Various sets of extra literals accepted.  */
> +extern const literal_def integer_unlimited_literals[];
> +extern const literal_def uinteger_unlimited_literals[];
> +extern const literal_def zuinteger_unlimited_literals[];
> +
>   extern set_show_commands add_setshow_enum_cmd
>     (const char *name, command_class theclass, const char *const *enumlist,
>      const char **var, const char *set_doc, const char *show_doc,
> @@ -748,6 +782,20 @@ extern set_show_commands add_setshow_opt
>      cmd_list_element **show_list);
>
>   extern set_show_commands add_setshow_integer_cmd
> +  (const char *name, command_class theclass, int *var,
> +   const literal_def *extra_literals, const char *set_doc,
> +   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
> +   show_value_ftype *show_func, cmd_list_element **set_list,
> +   cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_integer_cmd
> +  (const char *name, command_class theclass, const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   setting_func_types<int>::set set_func,
> +   setting_func_types<int>::get get_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_integer_cmd
>     (const char *name, command_class theclass, int *var, const char *set_doc,
>      const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
>      show_value_ftype *show_func, cmd_list_element **set_list,
> @@ -760,6 +808,34 @@ extern set_show_commands add_setshow_int
>      setting_func_types<int>::get get_func, show_value_ftype *show_func,
>      cmd_list_element **set_list, cmd_list_element **show_list);
>
> +extern set_show_commands add_setshow_pinteger_cmd
> +  (const char *name, command_class theclass, int *var,
> +   const literal_def *extra_literals, const char *set_doc,
> +   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
> +   show_value_ftype *show_func, cmd_list_element **set_list,
> +   cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_pinteger_cmd
> +  (const char *name, command_class theclass, const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   setting_func_types<int>::set set_func,
> +   setting_func_types<int>::get get_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_uinteger_cmd
> +  (const char *name, command_class theclass, unsigned int *var,
> +   const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   cmd_func_ftype *set_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_uinteger_cmd
> +  (const char *name, command_class theclass, const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   setting_func_types<unsigned int>::set set_func,
> +   setting_func_types<unsigned int>::get get_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
>   extern set_show_commands add_setshow_uinteger_cmd
>     (const char *name, command_class theclass, unsigned int *var,
>      const char *set_doc, const char *show_doc, const char *help_doc,
> Index: src/gdb/guile/scm-param.c
> ===================================================================
> --- src.orig/gdb/guile/scm-param.c
> +++ src/gdb/guile/scm-param.c
> @@ -117,18 +117,33 @@ struct param_smob
>   static setting
>   make_setting (param_smob *s)
>   {
> -  if (var_type_uses<bool> (s->type))
> -    return setting (s->type, &s->value.boolval);
> -  else if (var_type_uses<int> (s->type))
> -    return setting (s->type, &s->value.intval);
> -  else if (var_type_uses<auto_boolean> (s->type))
> -    return setting (s->type, &s->value.autoboolval);
> -  else if (var_type_uses<unsigned int> (s->type))
> -    return setting (s->type, &s->value.uintval);
> -  else if (var_type_uses<std::string> (s->type))
> -    return setting (s->type, s->value.stringval);
> -  else if (var_type_uses<const char *> (s->type))
> -    return setting (s->type, &s->value.cstringval);
> +  enum var_types type = s->type;
> +
> +  switch (type)
> +    {
> +    case var_zinteger:
> +      type = var_integer;
> +      break;
> +    case var_zuinteger:
> +      type = var_uinteger;
> +      break;
> +    case var_zuinteger_unlimited:
> +      type = var_pinteger;
> +      break;
> +    }
> +
> +  if (var_type_uses<bool> (type))
> +    return setting (type, &s->value.boolval);
> +  else if (var_type_uses<int> (type))
> +    return setting (type, &s->value.intval);
> +  else if (var_type_uses<auto_boolean> (type))
> +    return setting (type, &s->value.autoboolval);
> +  else if (var_type_uses<unsigned int> (type))
> +    return setting (type, &s->value.uintval);
> +  else if (var_type_uses<std::string> (type))
> +    return setting (type, s->value.stringval);
> +  else if (var_type_uses<const char *> (type))
> +    return setting (type, &s->value.cstringval);
>     else
>       gdb_assert_not_reached ("unhandled var type");
>   }
> @@ -588,10 +603,6 @@ pascm_param_type_name (enum var_types pa
>   static SCM
>   pascm_param_value (const setting &var, int arg_pos, const char *func_name)
>   {
> -  /* Note: We *could* support var_integer here in case someone is trying to get
> -     the value of a Python-created parameter (which is the only place that
> -     still supports var_integer).  To further discourage its use we do not.  */
> -
>     switch (var.type ())
>       {
>       case var_string:
> @@ -631,20 +642,35 @@ pascm_param_value (const setting &var, i
>   	  return auto_keyword;
>         }
>
> -    case var_zuinteger_unlimited:
> -      if (var.get<int> () == -1)
> -	return unlimited_keyword;
> -      gdb_assert (var.get<int> () >= 0);
> -      /* Fall through.  */
> -    case var_zinteger:
> -      return scm_from_int (var.get<int> ());
> -
>       case var_uinteger:
> -      if (var.get<unsigned int> ()== UINT_MAX)
> -	return unlimited_keyword;
> -      /* Fall through.  */
> -    case var_zuinteger:
> -      return scm_from_uint (var.get<unsigned int> ());
> +    case var_integer:
> +    case var_pinteger:
> +      {
> +	LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
> +
> +	bool literal = false;
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		if (strcmp (l->literal, "unlimited") == 0)
> +		  return unlimited_keyword;
> +		value = l->val;
> +		literal = true;
> +	      }
> +	if (var.type () == var_pinteger && !literal)
> +	  gdb_assert (value >= 0);
> +
> +	if (var.type () == var_uinteger)
> +	  return scm_from_uint (static_cast<const unsigned int> (value));
> +	else
> +	  return scm_from_int (static_cast<const int> (value));
> +      }
>
>       default:
>         break;
> @@ -666,14 +692,14 @@ pascm_set_param_value_x (param_smob *p_s
>   {
>     setting var = make_setting (p_smob);
>
> -  switch (var.type ())
> +  switch (p_smob->type)
>       {
>       case var_string:
>       case var_string_noescape:
>       case var_optional_filename:
>       case var_filename:
>         SCM_ASSERT_TYPE (scm_is_string (value)
> -		       || (var.type () != var_filename
> +		       || (p_smob->type != var_filename
>   			   && gdbscm_is_false (value)),
>   		       value, arg_pos, func_name,
>   		       _("string or #f for non-PARAM_FILENAME parameters"));
> @@ -739,8 +765,8 @@ pascm_set_param_value_x (param_smob *p_s
>       case var_uinteger:
>       case var_zuinteger:
>       case var_zuinteger_unlimited:
> -      if (var.type () == var_uinteger
> -	  || var.type () == var_zuinteger_unlimited)
> +      if (p_smob->type == var_uinteger
> +	  || p_smob->type == var_zuinteger_unlimited)
>   	{
>   	  SCM_ASSERT_TYPE (gdbscm_is_bool (value)
>   			   || scm_is_eq (value, unlimited_keyword),
> @@ -748,7 +774,7 @@ pascm_set_param_value_x (param_smob *p_s
>   			   _("integer or #:unlimited"));
>   	  if (scm_is_eq (value, unlimited_keyword))
>   	    {
> -	      if (var.type () == var_uinteger)
> +	      if (p_smob->type == var_uinteger)
>   		var.set<unsigned int> (UINT_MAX);
>   	      else
>   		var.set<int> (-1);
> @@ -761,12 +787,12 @@ pascm_set_param_value_x (param_smob *p_s
>   			   _("integer"));
>   	}
>
> -      if (var.type () == var_uinteger
> -	  || var.type () == var_zuinteger)
> +      if (p_smob->type == var_uinteger
> +	  || p_smob->type == var_zuinteger)
>   	{
>   	  unsigned int u = scm_to_uint (value);
>
> -	  if (var.type () == var_uinteger && u == 0)
> +	  if (p_smob->type == var_uinteger && u == 0)
>   	    u = UINT_MAX;
>   	  var.set<unsigned int> (u);
>   	}
> @@ -774,7 +800,7 @@ pascm_set_param_value_x (param_smob *p_s
>   	{
>   	  int i = scm_to_int (value);
>
> -	  if (var.type () == var_zuinteger_unlimited && i < -1)
> +	  if (p_smob->type == var_zuinteger_unlimited && i < -1)
>   	    {
>   	      gdbscm_out_of_range_error (func_name, arg_pos, value,
>   					 _("must be >= -1"));
> Index: src/gdb/maint-test-options.c
> ===================================================================
> --- src.orig/gdb/maint-test-options.c
> +++ src/gdb/maint-test-options.c
> @@ -207,6 +207,7 @@ static const gdb::option::option_def tes
>     gdb::option::uinteger_option_def<test_options_opts> {
>       "uinteger",
>       [] (test_options_opts *opts) { return &opts->uint_opt; },
> +    uinteger_unlimited_literals,
>       nullptr, /* show_cmd_cb */
>       N_("A uinteger option."),
>       nullptr, /* show_doc */
> @@ -214,9 +215,10 @@ static const gdb::option::option_def tes
>     },
>
>     /* A zuinteger_unlimited option.  */
> -  gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
> +  gdb::option::integer_option_def<test_options_opts> {
>       "zuinteger-unlimited",
>       [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
> +    zuinteger_unlimited_literals,
>       nullptr, /* show_cmd_cb */
>       N_("A zuinteger-unlimited option."),
>       nullptr, /* show_doc */
> Index: src/gdb/python/py-param.c
> ===================================================================
> --- src.orig/gdb/python/py-param.c
> +++ src/gdb/python/py-param.c
> @@ -96,18 +96,33 @@ struct parmpy_object
>   static setting
>   make_setting (parmpy_object *s)
>   {
> -  if (var_type_uses<bool> (s->type))
> -    return setting (s->type, &s->value.boolval);
> -  else if (var_type_uses<int> (s->type))
> -    return setting (s->type, &s->value.intval);
> -  else if (var_type_uses<auto_boolean> (s->type))
> -    return setting (s->type, &s->value.autoboolval);
> -  else if (var_type_uses<unsigned int> (s->type))
> -    return setting (s->type, &s->value.uintval);
> -  else if (var_type_uses<std::string> (s->type))
> -    return setting (s->type, s->value.stringval);
> -  else if (var_type_uses<const char *> (s->type))
> -    return setting (s->type, &s->value.cstringval);
> +  enum var_types type = s->type;
> +
> +  switch (type)
> +    {
> +    case var_zinteger:
> +      type = var_integer;
> +      break;
> +    case var_zuinteger:
> +      type = var_uinteger;
> +      break;
> +    case var_zuinteger_unlimited:
> +      type = var_pinteger;
> +      break;
> +    }
> +
> +  if (var_type_uses<bool> (type))
> +    return setting (type, &s->value.boolval);
> +  else if (var_type_uses<int> (type))
> +    return setting (type, &s->value.intval);
> +  else if (var_type_uses<auto_boolean> (type))
> +    return setting (type, &s->value.autoboolval);
> +  else if (var_type_uses<unsigned int> (type))
> +    return setting (type, &s->value.uintval);
> +  else if (var_type_uses<std::string> (type))
> +    return setting (type, s->value.stringval);
> +  else if (var_type_uses<const char *> (type))
> +    return setting (type, &s->value.cstringval);
>     else
>       gdb_assert_not_reached ("unhandled var type");
>   }
> Index: src/gdb/python/python.c
> ===================================================================
> --- src.orig/gdb/python/python.c
> +++ src/gdb/python/python.c
> @@ -502,35 +502,34 @@ gdbpy_parameter_value (const setting &va
>   	  Py_RETURN_NONE;
>         }
>
> -    case var_integer:
> -      if (var.get<int> () == INT_MAX)
> -	Py_RETURN_NONE;
> -      /* Fall through.  */
> -    case var_zinteger:
> -      return gdb_py_object_from_longest (var.get<int> ()).release ();
> -
> -    case var_zuinteger_unlimited:
> -      {
> -	int val = var.get<int> ();
> -
> -	if (val == -1)
> -	  Py_RETURN_NONE;
> -	return gdb_py_object_from_longest (val).release ();
> -      }
> -
>       case var_uinteger:
> +    case var_integer:
> +    case var_pinteger:
>         {
> -	unsigned int val = var.get<unsigned int> ();
> +	LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
>
> -	if (val == UINT_MAX)
> -	  Py_RETURN_NONE;
> -	return gdb_py_object_from_ulongest (val).release ();
> -      }
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		if (strcmp (l->literal, "unlimited") == 0)
> +		  Py_RETURN_NONE;
> +		value = l->val;
> +	      }
>
> -    case var_zuinteger:
> -      {
> -	unsigned int val = var.get<unsigned int> ();
> -	return gdb_py_object_from_ulongest (val).release ();
> +	if (var.type () == var_uinteger)
> +	  return
> +	    gdb_py_object_from_ulongest
> +	      (static_cast<const unsigned int> (value)).release ();
> +	else
> +	  return
> +	    gdb_py_object_from_longest
> +	      (static_cast<const int> (value)).release ();
>         }
>       }
>
> Index: src/gdb/valprint.c
> ===================================================================
> --- src.orig/gdb/valprint.c
> +++ src/gdb/valprint.c
> @@ -2974,8 +2974,8 @@ using boolean_option_def
>     = gdb::option::boolean_option_def<value_print_options>;
>   using uinteger_option_def
>     = gdb::option::uinteger_option_def<value_print_options>;
> -using zuinteger_unlimited_option_def
> -  = gdb::option::zuinteger_unlimited_option_def<value_print_options>;
> +using integer_option_def
> +  = gdb::option::integer_option_def<value_print_options>;
>
>   /* Definitions of options for the "print" and "compile print"
>      commands.  */
> @@ -3011,15 +3011,17 @@ static const gdb::option::option_def val
>     uinteger_option_def {
>       "elements",
>       [] (value_print_options *opt) { return &opt->print_max; },
> +    uinteger_unlimited_literals,
>       show_print_max, /* show_cmd_cb */
>       N_("Set limit on string chars or array elements to print."),
>       N_("Show limit on string chars or array elements to print."),
>       N_("\"unlimited\" causes there to be no limit."),
>     },
>
> -  zuinteger_unlimited_option_def {
> +  integer_option_def {
>       "max-depth",
>       [] (value_print_options *opt) { return &opt->max_depth; },
> +    zuinteger_unlimited_literals,
>       show_print_max_depth, /* show_cmd_cb */
>       N_("Set maximum print depth for nested structures, unions and arrays."),
>       N_("Show maximum print depth for nested structures, unions, and arrays."),
> @@ -3079,6 +3081,7 @@ pretty-printers for that value.")
>     uinteger_option_def {
>       "repeats",
>       [] (value_print_options *opt) { return &opt->repeat_count_threshold; },
> +    uinteger_unlimited_literals,
>       show_repeat_count_threshold, /* show_cmd_cb */
>       N_("Set threshold for repeated print elements."),
>       N_("Show threshold for repeated print elements."),

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-03-30 10:40     ` Maciej W. Rozycki
@ 2022-03-30 10:50       ` Simon Sobisch
  2022-03-30 11:52         ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Sobisch @ 2022-03-30 10:50 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches, Andrew Burgess, Simon Marchi, Tom Tromey


Am 30.03.2022 um 12:40 schrieb Maciej W. Rozycki:
> On Wed, 30 Mar 2022, Simon Sobisch wrote:
>
>> That seems like it should be mentioned in NEWS as it possibly affects
>> existing python extensions (if the commit that was fixed landed in an
>> official release).
>
>   Hmm, do we mention bug fixes in NEWS?
>
>    Maciej

Should - if it changes the result.

When you get a parameter before and it is an integer you can do integer
comparisons on it. After the changes it is None and you can't do integer
comparisons on it (raises an exception).

So if the bug was introduced to have -1 and it is likely that people
coded against that: please give them a clue with a note like

Python scripting: GDB x introduced a bug where `gdb.Parameter()` returns
'-1' for some Parameters when meaning "unlimited", which is now restored
to the previous behavior of returning 'None'.


This will allow people to watch out for this and adjust their scripts to
check for -1, then set to None (if they care for the buggy versions) and
compare to "None" in all places.

Thanks,
Simon

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands
  2022-03-30 10:42   ` Simon Sobisch
@ 2022-03-30 10:58     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 10:58 UTC (permalink / raw)
  To: Simon Sobisch; +Cc: gdb-patches, Andrew Burgess, Simon Marchi, Tom Tromey

On Wed, 30 Mar 2022, Simon Sobisch wrote:

> > Rather than just `unlimited' allow the integer set commands (or command
> > options) to define arbitrary keywords for the user to use, removing
> > hardcoded arrangements for the `unlimited' keyword.
> > 
> > Make obsolete the confusingly named `var_zinteger', `var_zuinteger' and
> > `var_zuinteger_unlimited' `set'/`show' command variable types redefining
> > them in terms of `var_uinteger', `var_integer' and `var_pinteger', which
> > have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.
> 
> Those "confusingly named" parts go into python, too; maybe someone could
> create a follow-up patch or adjust this one.
> I think keeping them aligned is very useful (if renamed the old python
> names should stay as aliases for the new ones, and ideally the doc
> should reference a "until GDB 12: named ..." entry as this helps a lot
> when creating python extensions).

 I can't think of user-visible Python syntax for such a redefinition, and 
my lack of knowledge of the language does not help either, so someone more 
experienced in this area would have to step in.  It would be great to have 
the ability to add arbitrary keywords from Python code too I suppose.

 And the old keywords have to stay anyway, just as I have retained, e.g. 
`add_setshow_zuinteger_unlimited_cmd' in C++ code so that callers do not 
have to repeat an explicit reference to `zuinteger_unlimited_literals'.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-03-30 10:50       ` Simon Sobisch
@ 2022-03-30 11:52         ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-03-30 11:52 UTC (permalink / raw)
  To: Simon Sobisch; +Cc: gdb-patches, Andrew Burgess, Simon Marchi, Tom Tromey

On Wed, 30 Mar 2022, Simon Sobisch wrote:

> When you get a parameter before and it is an integer you can do integer
> comparisons on it. After the changes it is None and you can't do integer
> comparisons on it (raises an exception).
> 
> So if the bug was introduced to have -1 and it is likely that people
> coded against that: please give them a clue with a note like
> 
> Python scripting: GDB x introduced a bug where `gdb.Parameter()` returns
> '-1' for some Parameters when meaning "unlimited", which is now restored
> to the previous behavior of returning 'None'.
> 
> 
> This will allow people to watch out for this and adjust their scripts to
> check for -1, then set to None (if they care for the buggy versions) and
> compare to "None" in all places.

 If maintainers agree, then I will add such a NEWS entry, however I'd 
rather avoid respinning the series just for such a small update (and 
another mere docs change), so I'll wait for feedback on the code changes 
proper first.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 7/8] GDB: Add a character string limiting option
  2022-03-30 10:24 ` [PATCH v5 7/8] GDB: Add a character string limiting option Maciej W. Rozycki
@ 2022-03-30 12:29   ` Eli Zaretskii
  0 siblings, 0 replies; 51+ messages in thread
From: Eli Zaretskii @ 2022-03-30 12:29 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches, simonsobisch, tom, aburgess

> Date: Wed, 30 Mar 2022 11:24:38 +0100 (BST)
> From: "Maciej W. Rozycki" <macro@embecosm.com>
> Cc: Simon Sobisch <simonsobisch@web.de>, Tom Tromey <tom@tromey.com>,
>  Andrew Burgess <aburgess@redhat.com>
> 
>  gdb/NEWS                           |   16 +++++++
>  gdb/ada-valprint.c                 |    6 +-
>  gdb/c-lang.c                       |    4 -
>  gdb/c-valprint.c                   |    5 +-
>  gdb/doc/gdb.texinfo                |   44 +++++++++++++++++--
>  gdb/doc/python.texi                |    5 ++
>  gdb/language.h                     |    2 
>  gdb/m2-lang.c                      |    3 -
>  gdb/m2-valprint.c                  |    4 +
>  gdb/p-lang.c                       |    3 -
>  gdb/p-valprint.c                   |    9 ++-
>  gdb/printcmd.c                     |    9 ++-
>  gdb/python/py-value.c              |    4 +
>  gdb/testsuite/gdb.base/default.exp |    7 +++
>  gdb/testsuite/gdb.base/options.exp |    1 
>  gdb/tracepoint.c                   |    4 -
>  gdb/valprint.c                     |   84 ++++++++++++++++++++++++++++---------
>  gdb/valprint.h                     |   20 +++++++-
>  18 files changed, 181 insertions(+), 49 deletions(-)

OK for the documentation parts.

Thanks.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (7 preceding siblings ...)
  2022-03-30 10:24 ` [PATCH v5 8/8] GDB/testsuite: Expand for character string limiting options Maciej W. Rozycki
@ 2022-04-13 11:20 ` Maciej W. Rozycki
  2022-04-13 12:10   ` Simon Sobisch
  2022-04-20 19:17 ` [PING^2][PATCH " Maciej W. Rozycki
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-04-13 11:20 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PING][PATCH v5 0/8] gdb: split array and string limiting options
  2022-04-13 11:20 ` [PING][PATCH v5 0/8] gdb: split array and " Maciej W. Rozycki
@ 2022-04-13 12:10   ` Simon Sobisch
  2022-04-13 12:18     ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Sobisch @ 2022-04-13 12:10 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey

As far as I'm concerned this is a very useful addition, well written,
with appropriate documentation. Only "more comments" - but those can be
handled _after_ this patchset is applied to GB12:

* last time I've checked a NEWS entry was missing
* patch v4 6/8: someone should check to add aliases for the exported
   python names, but again - nothing that should stop applying the patch

Thanks for your work in this!
Simon

Am 13.04.2022 um 13:20 schrieb Maciej W. Rozycki:
> On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:
>
>>   Following earlier discussion for compatibility with existing setups I
>> have implemented a mechanism to make the `set print characters' setting
>> follow that of `set print elements' by default.  Consequently what was a
>> single change has now grown into a patch series.
>
>   Ping for:
> <https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>
>
>    Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PING][PATCH v5 0/8] gdb: split array and string limiting options
  2022-04-13 12:10   ` Simon Sobisch
@ 2022-04-13 12:18     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-04-13 12:18 UTC (permalink / raw)
  To: Simon Sobisch; +Cc: gdb-patches, Andrew Burgess, Simon Marchi, Tom Tromey

On Wed, 13 Apr 2022, Simon Sobisch wrote:

> * last time I've checked a NEWS entry was missing

 There's a NEWS entry for the change in 7/8; the remaining changes are not 
user-visible.  I hope this clears your concern.  Thank you for your input.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^2][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (8 preceding siblings ...)
  2022-04-13 11:20 ` [PING][PATCH v5 0/8] gdb: split array and " Maciej W. Rozycki
@ 2022-04-20 19:17 ` Maciej W. Rozycki
  2022-04-26 19:57   ` Simon Sobisch
  2022-04-27 12:02 ` [PING^3][PATCH " Maciej W. Rozycki
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-04-20 19:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PING^2][PATCH v5 0/8] gdb: split array and string limiting options
  2022-04-20 19:17 ` [PING^2][PATCH " Maciej W. Rozycki
@ 2022-04-26 19:57   ` Simon Sobisch
  2022-04-27 12:00     ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Simon Sobisch @ 2022-04-26 19:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Maciej W. Rozycki

Re-Ping: is there a reason to _not_ add the patchset to gdb12 branch?
All remaining answers before the ping were positive or solved.

Thanks,
Simon

Am 20.04.2022 um 21:17 schrieb Maciej W. Rozycki:
> On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:
>
>>   Following earlier discussion for compatibility with existing setups I
>> have implemented a mechanism to make the `set print characters' setting
>> follow that of `set print elements' by default.  Consequently what was a
>> single change has now grown into a patch series.
>
>   Ping for:
> <https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>
>
>    Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PING^2][PATCH v5 0/8] gdb: split array and string limiting options
  2022-04-26 19:57   ` Simon Sobisch
@ 2022-04-27 12:00     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-04-27 12:00 UTC (permalink / raw)
  To: Simon Sobisch; +Cc: gdb-patches, Andrew Burgess, Simon Marchi, Tom Tromey

On Tue, 26 Apr 2022, Simon Sobisch wrote:

> Re-Ping: is there a reason to _not_ add the patchset to gdb12 branch?

 This has to be approved for trunk first before it can be considered for 
backporting.  Also I think only bug fixes really qualify for backporting 
upstream.  Software packagers downstream can of course cherry-pick any 
changes they deem appropriate from master.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^3][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (9 preceding siblings ...)
  2022-04-20 19:17 ` [PING^2][PATCH " Maciej W. Rozycki
@ 2022-04-27 12:02 ` Maciej W. Rozycki
  2022-05-04 10:05 ` [PING^4][PATCH " Maciej W. Rozycki
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-04-27 12:02 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^4][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (10 preceding siblings ...)
  2022-04-27 12:02 ` [PING^3][PATCH " Maciej W. Rozycki
@ 2022-05-04 10:05 ` Maciej W. Rozycki
  2022-05-12 21:20 ` [PING^5][PATCH " Maciej W. Rozycki
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-05-04 10:05 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:

<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

May I ask to get the thing at least rolling?  In particular 1/8 and 3-5/8 
are I believe pretty uncontroversial, so while not ones I'm interested in 
the most, getting them pushed would at least be some progress and less to 
handle later on.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^5][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (11 preceding siblings ...)
  2022-05-04 10:05 ` [PING^4][PATCH " Maciej W. Rozycki
@ 2022-05-12 21:20 ` Maciej W. Rozycki
  2022-05-20 10:49 ` [PING^6][PATCH " Maciej W. Rozycki
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-05-12 21:20 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^6][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (12 preceding siblings ...)
  2022-05-12 21:20 ` [PING^5][PATCH " Maciej W. Rozycki
@ 2022-05-20 10:49 ` Maciej W. Rozycki
  2022-05-25 15:52 ` [PING^7][PATCH " Maciej W. Rozycki
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-05-20 10:49 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^7][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (13 preceding siblings ...)
  2022-05-20 10:49 ` [PING^6][PATCH " Maciej W. Rozycki
@ 2022-05-25 15:52 ` Maciej W. Rozycki
  2022-05-25 19:20 ` [PATCH " Bruno Larsen
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-05-25 15:52 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-03-30 10:24 ` [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands Maciej W. Rozycki
@ 2022-05-25 18:36   ` Bruno Larsen
  2022-05-26 10:09     ` Maciej W. Rozycki
  2022-06-24 15:08   ` Andrew Burgess
  1 sibling, 1 reply; 51+ messages in thread
From: Bruno Larsen @ 2022-05-25 18:36 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey, Andrew Burgess


On 3/30/22 07:24, Maciej W. Rozycki wrote:
> Fix a completion consistency issue with `set' commands accepting integer
> values and the special `unlimited' keyword:
> 
> (gdb) complete print -elements
> print -elements NUMBER
> print -elements unlimited
> (gdb)
> 
> vs:
> 
> (gdb) complete set print elements
> set print elements unlimited
> (gdb)
> 
> (there is a space entered at the end of both commands, not shown here)
> which also means if you strike <Tab> with `set print elements ' input,
> it will, annoyingly, complete to `set print elements unlimited' right
> away rather than showing a choice between `NUMBER' and `unlimited'.
> 
> Add `NUMBER' then as an available completion for such `set' commands:
> 
> (gdb) complete set print elements
> set print elements NUMBER
> set print elements unlimited
> (gdb)
>    
> Adjust the testsuite accordingly.

Hi Maciej,

Thanks for looking at this!

> ---
> No change from v4.
> 
> New change in v4.
> ---
>   gdb/cli/cli-decode.c                |    2 ++
>   gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
>   2 files changed, 9 insertions(+), 1 deletion(-)
> 
> gdb-integer-complete-number.diff
> Index: src/gdb/cli/cli-decode.c
> ===================================================================
> --- src.orig/gdb/cli/cli-decode.c
> +++ src/gdb/cli/cli-decode.c
> @@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
>         NULL,
>       };
>   
> +  if (*text == '\0')
> +    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
>     complete_on_enum (tracker, keywords, text, word);
>   }

Seeing as the point of "complete_on_enum" is to add all keywords to the tracker, why not add "NUMBER" as a keyword? The only possible unfavorable side effect I can think of would be GDB completing N<TAB> to NUMBER, and personally I feel abstracting away how the option would be added is more important than not adding this completion option.

Another option would be having the function like this:

void
integer_unlimited_completer(...)
{
   static const char * const keywords [] =
     {
       "NUMBER",
       "unlimited",
       NULL
     }
   if (*text != '\0')
     complete_on_enum (tracker, keywords + 1, text, word);
   else
     complete_on_enum (tracker, keywords, text, word);
}

Or some more concise way of writing it.

>   
> Index: src/gdb/testsuite/gdb.base/settings.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.base/settings.exp
> +++ src/gdb/testsuite/gdb.base/settings.exp
> @@ -215,8 +215,14 @@ proc test-integer {variant} {
>   	test_gdb_complete_none \
>   	    "$set_cmd "
>       } else {
> +	test_gdb_complete_multiple "$set_cmd " "" "" {
> +	    "NUMBER"
> +	    "unlimited"
> +	}
> +	test_gdb_complete_none \
> +	    "$set_cmd 1"
>   	test_gdb_complete_unique \
> -	    "$set_cmd " \
> +	    "$set_cmd u" \
>   	    "$set_cmd unlimited"
>       }
>   
> 


Cheers!
Bruno Larsen


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (14 preceding siblings ...)
  2022-05-25 15:52 ` [PING^7][PATCH " Maciej W. Rozycki
@ 2022-05-25 19:20 ` Bruno Larsen
  2022-06-02 17:55 ` [PING^8][PATCH " Maciej W. Rozycki
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 51+ messages in thread
From: Bruno Larsen @ 2022-05-25 19:20 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey, Andrew Burgess

Hi Maciej,

I've taken a look at the whole series and only had comments for patch 5, all others seem ok to me. However, I can't approve patches, so here's hoping a maintainer gives you some feedback!

Cheers!
Bruno Larsen

On 3/30/22 07:23, Maciej W. Rozycki wrote:
> Hi,
> 
>   Sadly I have received no feedback for v4 of the series other than the
> docs (thank you, Eli!), so here is v5 with the documentation parts updated
> only for Andrew's original proposal to split the `set/show print elements'
> options into two, so that there are separate `set/show print characters'
> options to control how many characters of a string are printed.
> 
>   Following earlier discussion for compatibility with existing setups I
> have implemented a mechanism to make the `set print characters' setting
> follow that of `set print elements' by default.  Consequently what was a
> single change has now grown into a patch series.
> 
>   In this series I fix some preexisting issues in the area first, implement
> the general framework for extra literals used with integer settings second
> and then add the original change for `set print characters' from Andrew,
> adjusted accordingly, followed by a testsuite update as a separate change.
> This is so as to ensure the semantics of the existing `set print elements'
> knob hasn't changed in the default `set print characters' state (a small
> update for the test suite is nevertheless included with the `set print
> characters' command proper, because inevitably the relevant commands that
> list commands now print additional entries, plus there's been a minimal
> test case update included for the verification of setting defaults).
> 
>   Since I have noticed some v4 hunks to apply with significant line number
> changes (meaning larger code rearrangements) and also Python 2 support to
> have been removed (my original builds used it) I have re-regression-tested
> the changes (with the build switched to Python 3), again with a native
> `x86_64-linux-gnu' configuration.  I have also visually examined the
> result of the updated changes to the GDB manual in the info and PDF
> formats.
> 
>   See individual change descriptions for details.
> 
>   OK to apply?
> 
>    Maciej
> 


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-05-25 18:36   ` Bruno Larsen
@ 2022-05-26 10:09     ` Maciej W. Rozycki
  2022-05-26 11:46       ` Bruno Larsen
  0 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-05-26 10:09 UTC (permalink / raw)
  To: Bruno Larsen; +Cc: gdb-patches, Simon Sobisch, Tom Tromey, Andrew Burgess

Hi Bruno,

> > Index: src/gdb/cli/cli-decode.c
> > ===================================================================
> > --- src.orig/gdb/cli/cli-decode.c
> > +++ src/gdb/cli/cli-decode.c
> > @@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
> >         NULL,
> >       };
> >   +  if (*text == '\0')
> > +    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
> >     complete_on_enum (tracker, keywords, text, word);
> >   }
> 
> Seeing as the point of "complete_on_enum" is to add all keywords to the
> tracker, why not add "NUMBER" as a keyword? The only possible unfavorable side
> effect I can think of would be GDB completing N<TAB> to NUMBER, and personally
> I feel abstracting away how the option would be added is more important than
> not adding this completion option.

 This just follows the existing logic in `parse_option' and is really a 
special case.  I am inconvinced that there is a benefit from getting the 
completion broken visibly to the user for the sake of avoiding a manual 
call in the code.  Sorry.

> Another option would be having the function like this:
> 
> void
> integer_unlimited_completer(...)
> {
>   static const char * const keywords [] =
>     {
>       "NUMBER",
>       "unlimited",
>       NULL
>     }
>   if (*text != '\0')
>     complete_on_enum (tracker, keywords + 1, text, word);
>   else
>     complete_on_enum (tracker, keywords, text, word);
> }
> 
> Or some more concise way of writing it.

 And then with 6/8 (which removes `integer_unlimited_completer' entirely) 
that "NUMBER" entry would have to be added to all the keyword lists passed 
along rather than a single place in `integer_literals_completer', and 
still handled as a rather fragile special case where people writing any 
new keyword lists will have to remember to put a "NUMBER" entry first.  I 
really fail to see the advantage of such approach.  Sorry again.

 Thank you for your input however, it's always good to have a look from a 
different angle!

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-05-26 10:09     ` Maciej W. Rozycki
@ 2022-05-26 11:46       ` Bruno Larsen
  2022-05-26 14:24         ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Bruno Larsen @ 2022-05-26 11:46 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches, Simon Sobisch, Tom Tromey, Andrew Burgess

Hi Maciej

On 5/26/22 07:09, Maciej W. Rozycki wrote:
> Hi Bruno,
> 
>>> Index: src/gdb/cli/cli-decode.c
>>> ===================================================================
>>> --- src.orig/gdb/cli/cli-decode.c
>>> +++ src/gdb/cli/cli-decode.c
>>> @@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
>>>          NULL,
>>>        };
>>>    +  if (*text == '\0')
>>> +    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
>>>      complete_on_enum (tracker, keywords, text, word);
>>>    }
>>
>> Seeing as the point of "complete_on_enum" is to add all keywords to the
>> tracker, why not add "NUMBER" as a keyword? The only possible unfavorable side
>> effect I can think of would be GDB completing N<TAB> to NUMBER, and personally
>> I feel abstracting away how the option would be added is more important than
>> not adding this completion option.
> 
>   This just follows the existing logic in `parse_option' and is really a
> special case.  I am inconvinced that there is a benefit from getting the
> completion broken visibly to the user for the sake of avoiding a manual
> call in the code.  Sorry.

I don't really think `complete set print elements N<tab>` would naturally occur, so I don't really think it would break completion from a user standpoint. However, I think we can agree to disagree here, since you do away with this function later on, and I'm fine with how you decided to work on that patch.

FWIW, your series is fine by me (but I can't approve it for pushing, like I mentioned yesterday).

Cheers!
Bruno Larsen


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-05-26 11:46       ` Bruno Larsen
@ 2022-05-26 14:24         ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-05-26 14:24 UTC (permalink / raw)
  To: Bruno Larsen; +Cc: gdb-patches, Simon Sobisch, Tom Tromey, Andrew Burgess

Hi Bruno,

> >   This just follows the existing logic in `parse_option' and is really a
> > special case.  I am inconvinced that there is a benefit from getting the
> > completion broken visibly to the user for the sake of avoiding a manual
> > call in the code.  Sorry.
> 
> I don't really think `complete set print elements N<tab>` would naturally
> occur, so I don't really think it would break completion from a user
> standpoint. However, I think we can agree to disagree here, since you do away
> with this function later on, and I'm fine with how you decided to work on that
> patch.

 If someone, pehaps mistakenly, enters `set print elements N<tab>`, then 
the last word will complete to `NUMBER' (and likewise with `complete set 
print elements N'), which does not correspond to the syntax supported and 
is therefore supposed not to happen.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^8][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (15 preceding siblings ...)
  2022-05-25 19:20 ` [PATCH " Bruno Larsen
@ 2022-06-02 17:55 ` Maciej W. Rozycki
  2022-06-07 17:23   ` Simon Sobisch
  2022-06-15 22:47 ` [PING^9][PATCH " Maciej W. Rozycki
  2022-06-22 11:25 ` [PING^10][PATCH " Maciej W. Rozycki
  18 siblings, 1 reply; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-02 17:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PING^8][PATCH v5 0/8] gdb: split array and string limiting options
  2022-06-02 17:55 ` [PING^8][PATCH " Maciej W. Rozycki
@ 2022-06-07 17:23   ` Simon Sobisch
  0 siblings, 0 replies; 51+ messages in thread
From: Simon Sobisch @ 2022-06-07 17:23 UTC (permalink / raw)
  To: gdb-patches, Tom Tromey; +Cc: Andrew Burgess, Simon Marchi, Maciej W. Rozycki

RE-ping Tom Tromey which works on GDB Python code: please check this
patch and include if there are not severe issues with it (none were
reported to this list, some "ok for xyz parts" messages were left and
the patch is floating around since quite some time, too ... - a state
where we were before the last version branch, and hopefully don't miss
that again).

Thank you and thanks a lot for Maciej for taking all the hard work and
being patient!

Simon

Am 02.06.2022 um 19:55 schrieb Maciej W. Rozycki:
> On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:
>
>>   Following earlier discussion for compatibility with existing setups I
>> have implemented a mechanism to make the `set print characters' setting
>> follow that of `set print elements' by default.  Consequently what was a
>> single change has now grown into a patch series.
>
>   Ping for:
> <https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>
>
>    Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^9][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (16 preceding siblings ...)
  2022-06-02 17:55 ` [PING^8][PATCH " Maciej W. Rozycki
@ 2022-06-15 22:47 ` Maciej W. Rozycki
  2022-06-22 11:25 ` [PING^10][PATCH " Maciej W. Rozycki
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-15 22:47 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PING^10][PATCH v5 0/8] gdb: split array and string limiting options
  2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
                   ` (17 preceding siblings ...)
  2022-06-15 22:47 ` [PING^9][PATCH " Maciej W. Rozycki
@ 2022-06-22 11:25 ` Maciej W. Rozycki
  18 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-22 11:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess, Simon Marchi, Tom Tromey, Simon Sobisch

On Wed, 30 Mar 2022, Maciej W. Rozycki wrote:

>  Following earlier discussion for compatibility with existing setups I 
> have implemented a mechanism to make the `set print characters' setting 
> follow that of `set print elements' by default.  Consequently what was a 
> single change has now grown into a patch series.

 Ping for:
<https://sourceware.org/pipermail/gdb-patches/2022-March/187086.html>

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages
  2022-03-30 10:23 ` [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages Maciej W. Rozycki
@ 2022-06-24 14:32   ` Andrew Burgess
  2022-06-29 14:29     ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Andrew Burgess @ 2022-06-24 14:32 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> With errors given for bad commands such as `set annotate' or `set width' 
> we produce an extraneous full stop within parentheses:
>
> (gdb) set annotate
> Argument required (integer to set it to.).
> (gdb) set width
> Argument required (integer to set it to, or "unlimited".).
> (gdb)
>
> This is grammatically incorrect, so remove the full stop and adjust the 
> testsuite accordingly.

LGTM.

Thanks,
Andrew


> ---
> No change from v4.
>
> New change in v4.
> ---
>  gdb/cli/cli-setshow.c           |   10 +++++-----
>  gdb/testsuite/gdb.base/with.exp |    8 ++++----
>  2 files changed, 9 insertions(+), 9 deletions(-)
>
> gdb-parse-cli-var-integer-msg-stop.diff
> Index: src/gdb/cli/cli-setshow.c
> ===================================================================
> --- src.orig/gdb/cli/cli-setshow.c
> +++ src/gdb/cli/cli-setshow.c
> @@ -195,9 +195,9 @@ parse_cli_var_uinteger (var_types var_ty
>    if (*arg == nullptr || **arg == '\0')
>      {
>        if (var_type == var_uinteger)
> -	error_no_arg (_("integer to set it to, or \"unlimited\"."));
> +	error_no_arg (_("integer to set it to, or \"unlimited\""));
>        else
> -	error_no_arg (_("integer to set it to."));
> +	error_no_arg (_("integer to set it to"));
>      }
>  
>    if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
> @@ -228,7 +228,7 @@ parse_cli_var_zuinteger_unlimited (const
>    LONGEST val;
>  
>    if (*arg == nullptr || **arg == '\0')
> -    error_no_arg (_("integer to set it to, or \"unlimited\"."));
> +    error_no_arg (_("integer to set it to, or \"unlimited\""));
>  
>    if (is_unlimited_literal (arg, expression))
>      val = -1;
> @@ -418,9 +418,9 @@ do_set_command (const char *arg, int fro
>  	if (*arg == '\0')
>  	  {
>  	    if (c->var->type () == var_integer)
> -	      error_no_arg (_("integer to set it to, or \"unlimited\"."));
> +	      error_no_arg (_("integer to set it to, or \"unlimited\""));
>  	    else
> -	      error_no_arg (_("integer to set it to."));
> +	      error_no_arg (_("integer to set it to"));
>  	  }
>  
>  	if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
> Index: src/gdb/testsuite/gdb.base/with.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.base/with.exp
> +++ src/gdb/testsuite/gdb.base/with.exp
> @@ -99,14 +99,14 @@ with_test_prefix "maint" {
>      test_with_error "boolean" "2" "\"on\" or \"off\" expected\\."
>      test_with_error "uinteger" "-1" "integer -1 out of range"
>      test_with_error "uinteger" "" \
> -	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
> +	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
>      test_with_error "zuinteger" "-1" "integer -1 out of range"
>      test_with_error "zuinteger" "" \
> -	"Argument required \\(integer to set it to\\.\\)\\."
> +	"Argument required \\(integer to set it to\\)\\."
>      test_with_error "zuinteger-unlimited" "-2" \
>  	"only -1 is allowed to set as unlimited"
>      test_with_error "zuinteger-unlimited" "" \
> -	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
> +	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
>      test_with_error "filename" "" \
>  	"Argument required \\(filename to set it to\\.\\)\\."
>      test_with_error "enum" "" \
> @@ -243,7 +243,7 @@ with_test_prefix "errors" {
>  	"Cannot use this setting with the \"with\" command"
>  
>      gdb_test "with print elements -- p 1" \
> -	"Argument required \\(integer to set it to, or \"unlimited\"\\.\\)\\."
> +	"Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
>  
>      gdb_test "with -- p 1" \
>  	"Missing setting before '--' delimiter"


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-03-30 10:23 ` [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited' Maciej W. Rozycki
  2022-03-30 10:35   ` Simon Sobisch
@ 2022-06-24 14:40   ` Andrew Burgess
  2022-06-29 16:48     ` Maciej W. Rozycki
  1 sibling, 1 reply; 51+ messages in thread
From: Andrew Burgess @ 2022-06-24 14:40 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> Consistently with the `var_integer' and `var_uinteger' parameters return 
> the special value of None for a `var_zuinteger_unlimited' parameter set 
> to `unlimited' by using the Py_RETURN_NONE macro in this case, fixing 
> commit 0489430a0e1a ("Handle var_zuinteger and var_zuinteger_unlimited 
> from Python"); cf. PR python/20084.  Adjust the testsuite
> accordingly.

Unfortunately, nice as it would be to make this change (for
consistency), I think we're stuck with what we have.

The -1 behaviour is documented for PARAM_ZUINTEGER_UNLIMITED in the
manual so it is not unreasonable to assume that there could be code in
the wild that relies on the existing behaviuor.

Thanks,
Andrew




> ---
> No change from v4.
>
> New change in v4.
> ---
>  gdb/python/python.c                       |   10 +++++++++-
>  gdb/testsuite/gdb.python/py-parameter.exp |    4 ++--
>  2 files changed, 11 insertions(+), 3 deletions(-)
>
> gdb-python-var-zuinteger-unlimited-none.diff
> Index: src/gdb/python/python.c
> ===================================================================
> --- src.orig/gdb/python/python.c
> +++ src/gdb/python/python.c
> @@ -507,9 +507,17 @@ gdbpy_parameter_value (const setting &va
>  	Py_RETURN_NONE;
>        /* Fall through.  */
>      case var_zinteger:
> -    case var_zuinteger_unlimited:
>        return gdb_py_object_from_longest (var.get<int> ()).release ();
>  
> +    case var_zuinteger_unlimited:
> +      {
> +	int val = var.get<int> ();
> +
> +	if (val == -1)
> +	  Py_RETURN_NONE;
> +	return gdb_py_object_from_longest (val).release ();
> +      }
> +
>      case var_uinteger:
>        {
>  	unsigned int val = var.get<unsigned int> ();
> Index: src/gdb/testsuite/gdb.python/py-parameter.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.python/py-parameter.exp
> +++ src/gdb/testsuite/gdb.python/py-parameter.exp
> @@ -343,8 +343,8 @@ proc_with_prefix test_integer_parameter
>  	} elseif {$kind == "PARAM_ZUINTEGER_UNLIMITED"} {
>  	    gdb_test_no_output "python test_param_$kind.value = -1" \
>  		"check that PARAM_ZUINTEGER value can be set to -1"
> -	    gdb_test "python print(gdb.parameter('test-$kind'))" "-1" \
> -		"check that PARAM_ZUINTEGER value is -1 after setting"
> +	    gdb_test "python print(gdb.parameter('test-$kind'))" "None" \
> +		"check that PARAM_ZUINTEGER value is None after setting"
>  	} else {
>  	    error "invalid kind: $kind"
>  	}


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-03-30 10:24 ` [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands Maciej W. Rozycki
  2022-05-25 18:36   ` Bruno Larsen
@ 2022-06-24 15:08   ` Andrew Burgess
  2022-06-30 14:24     ` [PATCH v6 " Maciej W. Rozycki
  1 sibling, 1 reply; 51+ messages in thread
From: Andrew Burgess @ 2022-06-24 15:08 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> Fix a completion consistency issue with `set' commands accepting integer 
> values and the special `unlimited' keyword:
>
> (gdb) complete print -elements
> print -elements NUMBER
> print -elements unlimited
> (gdb)
>
> vs:
>
> (gdb) complete set print elements
> set print elements unlimited
> (gdb)
>
> (there is a space entered at the end of both commands, not shown here) 
> which also means if you strike <Tab> with `set print elements ' input, 
> it will, annoyingly, complete to `set print elements unlimited' right 
> away rather than showing a choice between `NUMBER' and `unlimited'.
>
> Add `NUMBER' then as an available completion for such `set' commands:
>
> (gdb) complete set print elements
> set print elements NUMBER
> set print elements unlimited
> (gdb)
>   
> Adjust the testsuite accordingly.

I like this change, but I think we should add some documentation in
`@node Completion` that describes this new behaviour. We should probably
add a NEWS entry too.

Thanks,
Andrew



> ---
> No change from v4.
>
> New change in v4.
> ---
>  gdb/cli/cli-decode.c                |    2 ++
>  gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
>  2 files changed, 9 insertions(+), 1 deletion(-)
>
> gdb-integer-complete-number.diff
> Index: src/gdb/cli/cli-decode.c
> ===================================================================
> --- src.orig/gdb/cli/cli-decode.c
> +++ src/gdb/cli/cli-decode.c
> @@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
>        NULL,
>      };
>  
> +  if (*text == '\0')
> +    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
>    complete_on_enum (tracker, keywords, text, word);
>  }
>  
> Index: src/gdb/testsuite/gdb.base/settings.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.base/settings.exp
> +++ src/gdb/testsuite/gdb.base/settings.exp
> @@ -215,8 +215,14 @@ proc test-integer {variant} {
>  	test_gdb_complete_none \
>  	    "$set_cmd "
>      } else {
> +	test_gdb_complete_multiple "$set_cmd " "" "" {
> +	    "NUMBER"
> +	    "unlimited"
> +	}
> +	test_gdb_complete_none \
> +	    "$set_cmd 1"
>  	test_gdb_complete_unique \
> -	    "$set_cmd " \
> +	    "$set_cmd u" \
>  	    "$set_cmd unlimited"
>      }
>  


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check
  2022-03-30 10:24 ` [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check Maciej W. Rozycki
@ 2022-06-24 15:09   ` Andrew Burgess
  2022-06-29 14:29     ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Andrew Burgess @ 2022-06-24 15:09 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> Match the whole error message expected to be given rather than omitting 
> the part about the "unlimited" keyword.  There's no point in omitting 
> the missing part first, and second with an upcoming change the part in 
> parentheses will no longer be a fixed string, so doing a full match will 
> ensure the algorithm correctly builds the message expected here.  Also 
> avoid any wildcard matches.

LGTM.

Thanks,
Andrew

> ---
> No change from v4.
>
> New change in v4.
> ---
>  gdb/testsuite/gdb.base/default.exp |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> gdb-test-set-print-elements-tightening.diff
> Index: src/gdb/testsuite/gdb.base/default.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.base/default.exp
> +++ src/gdb/testsuite/gdb.base/default.exp
> @@ -525,7 +525,8 @@ gdb_test_no_output "set print asm-demang
>  #test set print demangle
>  gdb_test_no_output "set print demangle" "set print demangle"
>  #test set print elements
> -gdb_test "set print elements" "Argument required .integer to set it to.*"
> +gdb_test "set print elements" \
> +	 "Argument required \\(integer to set it to, or \"unlimited\"\\)\\."
>  #test set print object
>  gdb_test_no_output "set print object" "set print object"
>  #test set print pretty


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command
  2022-03-30 10:24 ` [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command Maciej W. Rozycki
@ 2022-06-24 15:57   ` Andrew Burgess
  2022-07-07 11:04     ` Maciej W. Rozycki
  0 siblings, 1 reply; 51+ messages in thread
From: Andrew Burgess @ 2022-06-24 15:57 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> We currently have no coverage for the `print -elements ...' command (or 
> `p -elements ...' in the shortened form), so add a couple of test cases 
> mimicking ones using corresponding `set print elements ...' values.

LGTM.

Thanks,
Andrew


> ---
> No change from v4.
>
> New change in v4.
> ---
>  gdb/testsuite/gdb.base/printcmds.exp |    9 +++++++++
>  1 file changed, 9 insertions(+)
>
> gdb-test-printcmd-options.diff
> Index: src/gdb/testsuite/gdb.base/printcmds.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.base/printcmds.exp
> +++ src/gdb/testsuite/gdb.base/printcmds.exp
> @@ -538,6 +538,15 @@ proc test_print_strings {} {
>      gdb_test "p teststring" \
>  	" = (.unsigned char .. )?\"teststring contents\"" "p teststring with elements set to 20"
>  
> +    gdb_test "p -elements 1 -- teststring" \
> +	" = (.unsigned char .. )?\"t\"\\.\\.\\."
> +    gdb_test "p -elements 5 -- teststring" \
> +	" = (.unsigned char .. )?\"tests\"\\.\\.\\."
> +    gdb_test "p -elements 19 -- teststring" \
> +	" = (.unsigned char .. )?\"teststring contents\""
> +    gdb_test "p -elements 20 -- teststring" \
> +	" = (.unsigned char .. )?\"teststring contents\""
> +
>      gdb_test "print teststring2" \
>  	" = \\(charptr\\) \"more contents\""
>  


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands
  2022-03-30 10:24 ` [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands Maciej W. Rozycki
  2022-03-30 10:42   ` Simon Sobisch
@ 2022-06-28 14:04   ` Andrew Burgess
  2022-08-17 22:03     ` Maciej W. Rozycki
  1 sibling, 1 reply; 51+ messages in thread
From: Andrew Burgess @ 2022-06-28 14:04 UTC (permalink / raw)
  To: Maciej W. Rozycki, gdb-patches; +Cc: Simon Sobisch, Tom Tromey

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> Rather than just `unlimited' allow the integer set commands (or command 
> options) to define arbitrary keywords for the user to use, removing 
> hardcoded arrangements for the `unlimited' keyword.
>
> Make obsolete the confusingly named `var_zinteger', `var_zuinteger' and 
> `var_zuinteger_unlimited' `set'/`show' command variable types redefining 
> them in terms of `var_uinteger', `var_integer' and `var_pinteger', which 
> have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.
>
> Following existing practice `var_pinteger' allows extra negative values 
> to be used, however unlike `var_zuinteger_unlimited' any number of such 
> values can be defined rather than just `-1'.
>
> The "p" in `var_pinteger' stands for "positive", for the lack of a more 
> appropriate unambiguous letter, even though 0 obviously is not positive; 
> "n" would be confusing as to whether it stands for "non-negative" or 
> "negative".

While looking at this patch I was thinking to myself, I wonder why we
need var_pinteger, can't we achieve the same thing using var_uinteger
and different literals?

So I think I've convinced myself that you don't actually make use of
var_pinteger in this patch, and I'm pretty sure you don't use it in any
of the later patches either.

Maybe I'm wrong, so could you point out where it's used?

If it's not used then I think we should remove it.

If it's only used in a later commit then I think we should split its
addition out into a later commit.

If its used in this commit, then I'm sorry for missing it!

>
> Add a new structure, `literal_def', the entries of which define extra 
> keywords allowed for a command and numerical values they correspond to.  
> Those values are not verified against the basic range supported by the 
> underlying variable type, allowing extra values to be allowed outside 
> that range, which may or may not be individually made visible to the 
> user.  An optional value translation is possible with the structure to 
> follow the existing practice for some commands where user-entered 0 is 
> internally translated to UINT_MAX or INT_MAX.  Such translation can now 
> be arbitrary.  Literals defined by this structure are automatically used 
> for completion as necessary.
>
> So for example:
>
> const literal_def integer_unlimited_literals[] =
>   {
>     { "unlimited", 0, INT_MAX, true },
>     { nullptr }
>   };
>
> defines an extra `unlimited' keyword and a user-visible 0 value, both of 
> which get translated to INT_MAX for the setting to be used with.
>
> Similarly:
>
> const literal_def zuinteger_unlimited_literals[] =
>   {
>     { "unlimited", -1, -1, true },
>     { nullptr }
>   };
>
> defines the same keyword and a corresponding user-visible -1 value that is 
> used for the requested setting.  If the last member was set to `false' 
> here, then only the keyword would be allowed for the user to enter and 
> while -1 would still be used internally trying to enter it as a part of a 
> command would result in an "integer -1 out of range" error.
>
> The obsolete command variable types still remain for Guile and Python 
> use.  Eventually they need to be removed, however that would require a 
> further rework of our Guile and Python support code.  Given that these 
> variable types have been exported as keywords for those languages, those 
> definitions have to stay, however it would be better to redefine them in 
> terms of the modern variable types and overall export a better interface 
> that reflects the flexibility of our core code now.
>
> There is no user-visible change from this rework, so no documentation or
> testsuite updates.
> ---
> Hi,
>
>  NB I have observed that the value of INT_MIN is not correctly handled: 
> internally -2147483648 is interpreted as 2147483648 and consequently such 
> a value is rejected, e.g:
>
> (gdb) show heuristic-fence-post
> The distance searched for the start of a function is 0.
> (gdb) set heuristic-fence-post -2147483647
> (gdb) show heuristic-fence-post
> The distance searched for the start of a function is -2147483647.
> (gdb) set heuristic-fence-post -2147483648
> integer 2147483648 out of range
> (gdb)
>
> umm... (not that it makes sense to set negative values for the heuristic 
> fence post, but that's irrelevant here).  I haven't tried to track the 
> root cause for this.
>
>   Maciej
>
> No change from v4.
>
> New change in v4.
> ---
>  gdb/cli/cli-cmds.c       |   56 ++++----
>  gdb/cli/cli-decode.c     |  302 ++++++++++++++++++++++++++++++++++++++---------
>  gdb/cli/cli-option.c     |  116 +++++++++++-------
>  gdb/cli/cli-option.h     |   34 +++--
>  gdb/cli/cli-setshow.c    |  249 ++++++++++++++++++--------------------
>  gdb/cli/cli-setshow.h    |   20 +--
>  gdb/command.h            |  108 ++++++++++++++--
>  gdb/guile/scm-param.c    |  102 +++++++++------
>  gdb/maint-test-options.c |    4 
>  gdb/python/py-param.c    |   39 ++++--
>  gdb/python/python.c      |   49 +++----
>  gdb/valprint.c           |    9 -
>  12 files changed, 716 insertions(+), 372 deletions(-)
>
> gdb-setshow-cmd-extra-literals.diff
> Index: src/gdb/cli/cli-cmds.c
> ===================================================================
> --- src.orig/gdb/cli/cli-cmds.c
> +++ src/gdb/cli/cli-cmds.c
> @@ -2200,22 +2200,37 @@ value_from_setting (const setting &var,
>  {
>    switch (var.type ())
>      {
> +    case var_uinteger:
>      case var_integer:
> -      if (var.get<int> () == INT_MAX)
> -	return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				   0);
> -      else
> -	return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				   var.get<int> ());
> -    case var_zinteger:
> -      return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				 var.get<int> ());
> +    case var_pinteger:
> +      {
> +	LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
> +
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		value = l->val;
> +		break;
> +	      }
> +
> +	if (var.type () == var_uinteger)
> +	  return
> +	    value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
> +				 static_cast<const unsigned int> (value));
> +	else
> +	  return
> +	    value_from_longest (builtin_type (gdbarch)->builtin_int,
> +				static_cast<const int> (value));
> +      }
>      case var_boolean:
>        return value_from_longest (builtin_type (gdbarch)->builtin_int,
>  				 var.get<bool> () ? 1 : 0);
> -    case var_zuinteger_unlimited:
> -      return value_from_longest (builtin_type (gdbarch)->builtin_int,
> -				 var.get<int> ());
>      case var_auto_boolean:
>        {
>  	int val;
> @@ -2237,17 +2252,6 @@ value_from_setting (const setting &var,
>  	return value_from_longest (builtin_type (gdbarch)->builtin_int,
>  				   val);
>        }
> -    case var_uinteger:
> -      if (var.get<unsigned int> () == UINT_MAX)
> -	return value_from_ulongest
> -	  (builtin_type (gdbarch)->builtin_unsigned_int, 0);
> -      else
> -	return value_from_ulongest
> -	  (builtin_type (gdbarch)->builtin_unsigned_int,
> -	   var.get<unsigned int> ());
> -    case var_zuinteger:
> -      return value_from_ulongest (builtin_type (gdbarch)->builtin_unsigned_int,
> -				  var.get<unsigned int> ());
>      case var_string:
>      case var_string_noescape:
>      case var_optional_filename:
> @@ -2317,13 +2321,11 @@ str_value_from_setting (const setting &v
>  {
>    switch (var.type ())
>      {
> +    case var_uinteger:
>      case var_integer:
> -    case var_zinteger:
> +    case var_pinteger:
>      case var_boolean:
> -    case var_zuinteger_unlimited:
>      case var_auto_boolean:
> -    case var_uinteger:
> -    case var_zuinteger:
>        {
>  	std::string cmd_val = get_setshow_command_value_string (var);
>  
> Index: src/gdb/cli/cli-decode.c
> ===================================================================
> --- src.orig/gdb/cli/cli-decode.c
> +++ src/gdb/cli/cli-decode.c
> @@ -580,11 +580,51 @@ add_setshow_cmd_full_erased (const char
>    return {set, show};
>  }
>  
> +/* Completes on integer commands that support extra literals.  */
> +
> +static void
> +integer_literals_completer (struct cmd_list_element *c,
> +			    completion_tracker &tracker,
> +			    const char *text, const char *word)
> +{
> +  const literal_def *extra_literals = c->var->extra_literals ();
> +
> +  if (*text == '\0')
> +    {
> +      tracker.add_completion (make_unique_xstrdup ("NUMBER"));
> +      for (const literal_def *l = extra_literals;
> +	   l->literal != nullptr;
> +	   l++)
> +	tracker.add_completion (make_unique_xstrdup (l->literal));
> +    }
> +  else
> +    for (const literal_def *l = extra_literals;
> +	 l->literal != nullptr;
> +	 l++)
> +      if (startswith (l->literal, text))
> +	tracker.add_completion (make_unique_xstrdup (l->literal));
> +}
> +
> +/* Add element named NAME to both the command SET_LIST and SHOW_LIST.
> +   THECLASS is as in add_cmd.  VAR_TYPE is the kind of thing we are
> +   setting.  VAR is address of the variable being controlled by this
> +   command.  EXTRA_LITERALS if non-NULL define extra literals to be
> +   accepted in lieu of a number for integer variables.  If nullptr is
> +   given as VAR, then both SET_SETTING_FUNC and GET_SETTING_FUNC must
> +   be provided. SET_SETTING_FUNC and GET_SETTING_FUNC are callbacks
> +   used to access and modify the underlying property, whatever its
> +   storage is.  SET_FUNC and SHOW_FUNC are the callback functions
> +   (if non-NULL).  SET_DOC, SHOW_DOC and HELP_DOC are the
> +   documentation strings.
> +
> +   Return the newly created set and show commands.  */
> +
>  template<typename T>
>  static set_show_commands
>  add_setshow_cmd_full (const char *name,
>  		      enum command_class theclass,
>  		      var_types var_type, T *var,
> +		      const literal_def *extra_literals,
>  		      const char *set_doc, const char *show_doc,
>  		      const char *help_doc,
>  		      typename setting_func_types<T>::set set_setting_func,
> @@ -595,18 +635,44 @@ add_setshow_cmd_full (const char *name,
>  		      struct cmd_list_element **show_list)
>  {
>    auto erased_args
> -    = setting::erase_args (var_type, var,
> +    = setting::erase_args (var_type, var, extra_literals,
>  			   set_setting_func, get_setting_func);
> +  auto cmds = add_setshow_cmd_full_erased (name,
> +					   theclass,
> +					   var_type, erased_args,
> +					   set_doc, show_doc,
> +					   help_doc,
> +					   set_func,
> +					   show_func,
> +					   set_list,
> +					   show_list);
>  
> -  return add_setshow_cmd_full_erased (name,
> -				      theclass,
> -				      var_type, erased_args,
> -				      set_doc, show_doc,
> -				      help_doc,
> -				      set_func,
> -				      show_func,
> -				      set_list,
> -				      show_list);
> +  if (extra_literals != nullptr)
> +    set_cmd_completer (cmds.set, integer_literals_completer);
> +
> +  return cmds;
> +}
> +
> +/* Same as above but omitting EXTRA_LITERALS.  */
> +
> +template<typename T>
> +static set_show_commands
> +add_setshow_cmd_full (const char *name,
> +		      enum command_class theclass,
> +		      var_types var_type, T *var,
> +		      const char *set_doc, const char *show_doc,
> +		      const char *help_doc,
> +		      typename setting_func_types<T>::set set_setting_func,
> +		      typename setting_func_types<T>::get get_setting_func,
> +		      cmd_func_ftype *set_func,
> +		      show_value_ftype *show_func,
> +		      struct cmd_list_element **set_list,
> +		      struct cmd_list_element **show_list)
> +{
> +  return add_setshow_cmd_full (name, theclass, var_type, var, nullptr,
> +			       set_doc, show_doc, help_doc,
> +			       set_setting_func, get_setting_func,
> +			       set_func, show_func, set_list, show_list);
>  }
>  
>  /* Add element named NAME to command list LIST (the list for set or
> @@ -975,25 +1041,6 @@ add_setshow_optional_filename_cmd (const
>    return cmds;
>  }
>  
> -/* Completes on literal "unlimited".  Used by integer commands that
> -   support a special "unlimited" value.  */
> -
> -static void
> -integer_unlimited_completer (struct cmd_list_element *ignore,
> -			     completion_tracker &tracker,
> -			     const char *text, const char *word)
> -{
> -  static const char * const keywords[] =
> -    {
> -      "unlimited",
> -      NULL,
> -    };
> -
> -  if (*text == '\0')
> -    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
> -  complete_on_enum (tracker, keywords, text, word);
> -}
> -
>  /* Add element named NAME to both the set and show command LISTs (the
>     list for set/show or some sublist thereof).  CLASS is as in
>     add_cmd.  VAR is address of the variable which will contain the
> @@ -1002,6 +1049,55 @@ integer_unlimited_completer (struct cmd_
>  
>  set_show_commands
>  add_setshow_integer_cmd (const char *name, enum command_class theclass,
> +			 int *var, const literal_def *extra_literals,
> +			 const char *set_doc, const char *show_doc,
> +			 const char *help_doc,
> +			 cmd_func_ftype *set_func,
> +			 show_value_ftype *show_func,
> +			 struct cmd_list_element **set_list,
> +			 struct cmd_list_element **show_list)
> +{
> +  set_show_commands commands
> +    = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
> +				 extra_literals, set_doc, show_doc,
> +				 help_doc, nullptr, nullptr, set_func,
> +				 show_func, set_list, show_list);
> +  return commands;
> +}
> +
> +/* Same as above but using a getter and a setter function instead of a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_integer_cmd (const char *name, command_class theclass,
> +			 const literal_def *extra_literals,
> +			 const char *set_doc, const char *show_doc,
> +			 const char *help_doc,
> +			 setting_func_types<int>::set set_func,
> +			 setting_func_types<int>::get get_func,
> +			 show_value_ftype *show_func,
> +			 cmd_list_element **set_list,
> +			 cmd_list_element **show_list)
> +{
> +  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
> +					 extra_literals, set_doc, show_doc,
> +					 help_doc, set_func, get_func, nullptr,
> +					 show_func, set_list, show_list);
> +  return cmds;
> +}
> +
> +/* Accept `unlimited' or 0, translated internally to INT_MAX.  */
> +const literal_def integer_unlimited_literals[] =
> +  {
> +    { "unlimited", 0, INT_MAX, true },
> +    { nullptr }
> +  };
> +
> +/* Same as above but using `integer_unlimited_literals', with a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_integer_cmd (const char *name, enum command_class theclass,
>  			 int *var,
>  			 const char *set_doc, const char *show_doc,
>  			 const char *help_doc,
> @@ -1012,12 +1108,10 @@ add_setshow_integer_cmd (const char *nam
>  {
>    set_show_commands commands
>      = add_setshow_cmd_full<int> (name, theclass, var_integer, var,
> +				 integer_unlimited_literals,
>  				 set_doc, show_doc, help_doc,
>  				 nullptr, nullptr, set_func,
>  				 show_func, set_list, show_list);
> -
> -  set_cmd_completer (commands.set, integer_unlimited_completer);
> -
>    return commands;
>  }
>  
> @@ -1035,12 +1129,54 @@ add_setshow_integer_cmd (const char *nam
>  			 cmd_list_element **show_list)
>  {
>    auto cmds = add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
> +					 integer_unlimited_literals,
>  					 set_doc, show_doc, help_doc, set_func,
>  					 get_func, nullptr, show_func, set_list,
>  					 show_list);
> +  return cmds;
> +}
>  
> -  set_cmd_completer (cmds.set, integer_unlimited_completer);
> +/* Add element named NAME to both the set and show command LISTs (the
> +   list for set/show or some sublist thereof).  CLASS is as in
> +   add_cmd.  VAR is address of the variable which will contain the
> +   value.  SET_DOC and SHOW_DOC are the documentation strings.  */
> +
> +set_show_commands
> +add_setshow_pinteger_cmd (const char *name, enum command_class theclass,
> +			  int *var, const literal_def *extra_literals,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  cmd_func_ftype *set_func,
> +			  show_value_ftype *show_func,
> +			  struct cmd_list_element **set_list,
> +			  struct cmd_list_element **show_list)
> +{
> +  set_show_commands commands
> +    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
> +				 extra_literals, set_doc, show_doc,
> +				 help_doc, nullptr, nullptr, set_func,
> +				 show_func, set_list, show_list);
> +  return commands;
> +}
>  
> +/* Same as above but using a getter and a setter function instead of a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_pinteger_cmd (const char *name, command_class theclass,
> +			  const literal_def *extra_literals,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  setting_func_types<int>::set set_func,
> +			  setting_func_types<int>::get get_func,
> +			  show_value_ftype *show_func,
> +			  cmd_list_element **set_list,
> +			  cmd_list_element **show_list)
> +{
> +  auto cmds = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
> +					 extra_literals, set_doc, show_doc,
> +					 help_doc, set_func, get_func, nullptr,
> +					 show_func, set_list, show_list);
>    return cmds;
>  }
>  
> @@ -1051,7 +1187,7 @@ add_setshow_integer_cmd (const char *nam
>  
>  set_show_commands
>  add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
> -			  unsigned int *var,
> +			  unsigned int *var, const literal_def *extra_literals,
>  			  const char *set_doc, const char *show_doc,
>  			  const char *help_doc,
>  			  cmd_func_ftype *set_func,
> @@ -1061,12 +1197,9 @@ add_setshow_uinteger_cmd (const char *na
>  {
>    set_show_commands commands
>      = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
> -					  set_doc, show_doc, help_doc,
> -					  nullptr, nullptr, set_func,
> +					  extra_literals, set_doc, show_doc,
> +					  help_doc, nullptr, nullptr, set_func,
>  					  show_func, set_list, show_list);
> -
> -  set_cmd_completer (commands.set, integer_unlimited_completer);
> -
>    return commands;
>  }
>  
> @@ -1075,6 +1208,7 @@ add_setshow_uinteger_cmd (const char *na
>  
>  set_show_commands
>  add_setshow_uinteger_cmd (const char *name, command_class theclass,
> +			  const literal_def *extra_literals,
>  			  const char *set_doc, const char *show_doc,
>  			  const char *help_doc,
>  			  setting_func_types<unsigned int>::set set_func,
> @@ -1084,13 +1218,63 @@ add_setshow_uinteger_cmd (const char *na
>  			  cmd_list_element **show_list)
>  {
>    auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
> -						  nullptr, set_doc, show_doc,
> -						  help_doc, set_func, get_func,
> -						  nullptr, show_func, set_list,
> +						  nullptr, extra_literals,
> +						  set_doc, show_doc, help_doc,
> +						  set_func, get_func, nullptr,
> +						  show_func, set_list,
>  						  show_list);
> +  return cmds;
> +}
>  
> -  set_cmd_completer (cmds.set, integer_unlimited_completer);
> +/* Accept `unlimited' or 0, translated internally to UINT_MAX.  */
> +const literal_def uinteger_unlimited_literals[] =
> +  {
> +    { "unlimited", 0, UINT_MAX, true },
> +    { nullptr }
> +  };
> +
> +/* Same as above but using `uinteger_unlimited_literals', with a pointer
> +   to a global storage buffer.  */
> +
> +set_show_commands
> +add_setshow_uinteger_cmd (const char *name, enum command_class theclass,
> +			  unsigned int *var,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  cmd_func_ftype *set_func,
> +			  show_value_ftype *show_func,
> +			  struct cmd_list_element **set_list,
> +			  struct cmd_list_element **show_list)
> +{
> +  set_show_commands commands
> +    = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger, var,
> +					  uinteger_unlimited_literals,
> +					  set_doc, show_doc, help_doc, nullptr,
> +					  nullptr, set_func, show_func,
> +					  set_list, show_list);
> +  return commands;
> +}
> +
> +/* Same as above but using a getter and a setter function instead of a pointer
> +   to a global storage buffer.  */
>  
> +set_show_commands
> +add_setshow_uinteger_cmd (const char *name, command_class theclass,
> +			  const char *set_doc, const char *show_doc,
> +			  const char *help_doc,
> +			  setting_func_types<unsigned int>::set set_func,
> +			  setting_func_types<unsigned int>::get get_func,
> +			  show_value_ftype *show_func,
> +			  cmd_list_element **set_list,
> +			  cmd_list_element **show_list)
> +{
> +  auto cmds = add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
> +						  nullptr,
> +						  uinteger_unlimited_literals,
> +						  set_doc, show_doc, help_doc,
> +						  set_func, get_func, nullptr,
> +						  show_func, set_list,
> +						  show_list);
>    return cmds;
>  }
>  
> @@ -1109,7 +1293,7 @@ add_setshow_zinteger_cmd (const char *na
>  			  struct cmd_list_element **set_list,
>  			  struct cmd_list_element **show_list)
>  {
> -  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, var,
> +  return add_setshow_cmd_full<int> (name, theclass, var_integer, var,
>  				    set_doc, show_doc, help_doc,
>  				    nullptr, nullptr, set_func,
>  				    show_func, set_list, show_list);
> @@ -1128,12 +1312,22 @@ add_setshow_zinteger_cmd (const char *na
>  			  cmd_list_element **set_list,
>  			  cmd_list_element **show_list)
>  {
> -  return add_setshow_cmd_full<int> (name, theclass, var_zinteger, nullptr,
> +  return add_setshow_cmd_full<int> (name, theclass, var_integer, nullptr,
>  				    set_doc, show_doc, help_doc, set_func,
>  				    get_func, nullptr, show_func, set_list,
>  				    show_list);
>  }
>  
> +/* Accept `unlimited' or -1, using -1 internally.  */
> +const literal_def zuinteger_unlimited_literals[] =
> +  {
> +    { "unlimited", -1, -1, true },
> +    { nullptr }
> +  };
> +
> +/* Same as above but using `zuinteger_unlimited_literals', with a pointer
> +   to a global storage buffer.  */
> +
>  set_show_commands
>  add_setshow_zuinteger_unlimited_cmd (const char *name,
>  				     enum command_class theclass,
> @@ -1147,13 +1341,11 @@ add_setshow_zuinteger_unlimited_cmd (con
>  				     struct cmd_list_element **show_list)
>  {
>    set_show_commands commands
> -    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited, var,
> +    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, var,
> +				 zuinteger_unlimited_literals,
>  				 set_doc, show_doc, help_doc, nullptr,
>  				 nullptr, set_func, show_func, set_list,
>  				 show_list);
> -
> -  set_cmd_completer (commands.set, integer_unlimited_completer);
> -
>    return commands;
>  }
>  
> @@ -1171,13 +1363,11 @@ add_setshow_zuinteger_unlimited_cmd (con
>  				     cmd_list_element **show_list)
>  {
>    auto cmds
> -    = add_setshow_cmd_full<int> (name, theclass, var_zuinteger_unlimited,
> -				 nullptr, set_doc, show_doc, help_doc, set_func,
> +    = add_setshow_cmd_full<int> (name, theclass, var_pinteger, nullptr,
> +				 zuinteger_unlimited_literals,
> +				 set_doc, show_doc, help_doc, set_func,
>  				 get_func, nullptr, show_func, set_list,
>  				 show_list);
> -
> -  set_cmd_completer (cmds.set, integer_unlimited_completer);
> -
>    return cmds;
>  }
>  
> @@ -1196,7 +1386,7 @@ add_setshow_zuinteger_cmd (const char *n
>  			   struct cmd_list_element **set_list,
>  			   struct cmd_list_element **show_list)
>  {
> -  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
> +  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
>  					     var, set_doc, show_doc, help_doc,
>  					     nullptr, nullptr, set_func,
>  					     show_func, set_list, show_list);
> @@ -1215,7 +1405,7 @@ add_setshow_zuinteger_cmd (const char *n
>  			   cmd_list_element **set_list,
>  			   cmd_list_element **show_list)
>  {
> -  return add_setshow_cmd_full<unsigned int> (name, theclass, var_zuinteger,
> +  return add_setshow_cmd_full<unsigned int> (name, theclass, var_uinteger,
>  					     nullptr, set_doc, show_doc,
>  					     help_doc, set_func, get_func,
>  					     nullptr, show_func, set_list,
> Index: src/gdb/cli/cli-option.c
> ===================================================================
> --- src.orig/gdb/cli/cli-option.c
> +++ src/gdb/cli/cli-option.c
> @@ -38,7 +38,7 @@ union option_value
>    /* For var_uinteger options.  */
>    unsigned int uinteger;
>  
> -  /* For var_zuinteger_unlimited options.  */
> +  /* For var_integer and var_pinteger options.  */
>    int integer;
>  
>    /* For var_enum options.  */
> @@ -356,42 +356,55 @@ parse_option (gdb::array_view<const opti
>  	return option_def_and_value {*match, match_ctx, val};
>        }
>      case var_uinteger:
> -    case var_zuinteger_unlimited:
> +    case var_integer:
> +    case var_pinteger:
>        {
>  	if (completion != nullptr)
>  	  {
> -	    if (**args == '\0')
> -	      {
> -		/* Convenience to let the user know what the option
> -		   can accept.  Note there's no common prefix between
> -		   the strings on purpose, so that readline doesn't do
> -		   a partial match.  */
> -		completion->tracker.add_completion
> -		  (make_unique_xstrdup ("NUMBER"));
> -		completion->tracker.add_completion
> -		  (make_unique_xstrdup ("unlimited"));
> -		return {};
> -	      }
> -	    else if (startswith ("unlimited", *args))
> +	    if (match->extra_literals != nullptr)
>  	      {
> -		completion->tracker.add_completion
> -		  (make_unique_xstrdup ("unlimited"));
> -		return {};
> +		/* Convenience to let the user know what the option can
> +		   accept.  Make sure there's no common prefix between
> +		   "NUMBER" and all the strings when adding new ones,
> +		   so that readline doesn't do a partial match.  */
> +		if (**args == '\0')
> +		  {
> +		    completion->tracker.add_completion
> +		      (make_unique_xstrdup ("NUMBER"));
> +		    for (const literal_def *l = match->extra_literals;
> +			 l->literal != nullptr;
> +			 l++)
> +		      completion->tracker.add_completion
> +			(make_unique_xstrdup (l->literal));
> +		    return {};
> +		  }
> +		else
> +		  {
> +		    bool completions = false;
> +		    for (const literal_def *l = match->extra_literals;
> +			 l->literal != nullptr;
> +			 l++)
> +		      if (startswith (l->literal, *args))
> +			{
> +			  completion->tracker.add_completion
> +			    (make_unique_xstrdup (l->literal));
> +			  completions = true;
> +			}
> +		    if (completions)
> +		      return {};
> +		  }
>  	      }
>  	  }
>  
> -	if (match->type == var_zuinteger_unlimited)
> -	  {
> -	    option_value val;
> -	    val.integer = parse_cli_var_zuinteger_unlimited (args, false);
> -	    return option_def_and_value {*match, match_ctx, val};
> -	  }
> +	LONGEST v = parse_cli_var_integer (match->type,
> +					   match->extra_literals,
> +					   args, false);
> +	option_value val;
> +	if (match->type == var_uinteger)
> +	  val.uinteger = v;
>  	else
> -	  {
> -	    option_value val;
> -	    val.uinteger = parse_cli_var_uinteger (match->type, args, false);
> -	    return option_def_and_value {*match, match_ctx, val};
> -	  }
> +	  val.integer = v;
> +	return option_def_and_value {*match, match_ctx, val};
>        }
>      case var_enum:
>        {
> @@ -593,7 +606,7 @@ save_option_value_in_ctx (gdb::optional<
>        *ov->option.var_address.uinteger (ov->option, ov->ctx)
>  	= ov->value->uinteger;
>        break;
> -    case var_zuinteger_unlimited:
> +    case var_integer:
>        *ov->option.var_address.integer (ov->option, ov->ctx)
>  	= ov->value->integer;
>        break;
> @@ -664,8 +677,20 @@ get_val_type_str (const option_def &opt,
>      case var_boolean:
>        return "[on|off]";
>      case var_uinteger:
> -    case var_zuinteger_unlimited:
> -      return "NUMBER|unlimited";
> +    case var_integer:
> +    case var_pinteger:
> +      {
> +	buffer = "NUMBER";
> +	if (opt.extra_literals != nullptr)
> +	  for (const literal_def *l = opt.extra_literals;
> +	       l->literal != nullptr;
> +	       l++)
> +	    {
> +	      buffer += '|';
> +	      buffer += l->literal;
> +	    }
> +	return buffer.c_str ();
> +      }
>      case var_enum:
>        {
>  	buffer = "";
> @@ -789,20 +814,31 @@ add_setshow_cmds_for_options (command_cl
>  	{
>  	  add_setshow_uinteger_cmd (option.name, cmd_class,
>  				    option.var_address.uinteger (option, data),
> +				    option.extra_literals,
>  				    option.set_doc, option.show_doc,
>  				    option.help_doc,
>  				    nullptr, option.show_cmd_cb,
>  				    set_list, show_list);
>  	}
> -      else if (option.type == var_zuinteger_unlimited)
> +      else if (option.type == var_integer)
>  	{
> -	  add_setshow_zuinteger_unlimited_cmd
> -	    (option.name, cmd_class,
> -	     option.var_address.integer (option, data),
> -	     option.set_doc, option.show_doc,
> -	     option.help_doc,
> -	     nullptr, option.show_cmd_cb,
> -	     set_list, show_list);
> +	  add_setshow_integer_cmd (option.name, cmd_class,
> +				   option.var_address.integer (option, data),
> +				   option.extra_literals,
> +				   option.set_doc, option.show_doc,
> +				   option.help_doc,
> +				   nullptr, option.show_cmd_cb,
> +				   set_list, show_list);
> +	}
> +      else if (option.type == var_pinteger)
> +	{
> +	  add_setshow_pinteger_cmd (option.name, cmd_class,
> +				    option.var_address.integer (option, data),
> +				    option.extra_literals,
> +				    option.set_doc, option.show_doc,
> +				    option.help_doc,
> +				    nullptr, option.show_cmd_cb,
> +				    set_list, show_list);
>  	}
>        else if (option.type == var_enum)
>  	{
> Index: src/gdb/cli/cli-option.h
> ===================================================================
> --- src.orig/gdb/cli/cli-option.h
> +++ src/gdb/cli/cli-option.h
> @@ -49,12 +49,13 @@ struct option_def
>       used to create the option's "set/show" commands.  */
>    constexpr option_def (const char *name_,
>  			var_types var_type_,
> +			const literal_def *extra_literals_,
>  			erased_get_var_address_ftype *erased_get_var_address_,
>  			show_value_ftype *show_cmd_cb_,
>  			const char *set_doc_,
>  			const char *show_doc_,
>  			const char *help_doc_)
> -    : name (name_), type (var_type_),
> +    : name (name_), type (var_type_), extra_literals (extra_literals_),
>        erased_get_var_address (erased_get_var_address_),
>        var_address {},
>        show_cmd_cb (show_cmd_cb_),
> @@ -68,6 +69,9 @@ struct option_def
>    /* The option's type.  */
>    var_types type;
>  
> +  /* Extra literals, such as `unlimited', accepted in lieu of a number.  */
> +  const literal_def *extra_literals;
> +
>    /* A function that gets the controlling variable's address, type
>       erased.  */
>    erased_get_var_address_ftype *erased_get_var_address;
> @@ -160,7 +164,7 @@ struct boolean_option_def : option_def
>  		      const char *set_doc_,
>  		      const char *show_doc_ = nullptr,
>  		      const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_boolean,
> +    : option_def (long_option_, var_boolean, nullptr,
>  		  (erased_get_var_address_ftype *) get_var_address_cb_,
>  		  show_cmd_cb_,
>  		  set_doc_, show_doc_, help_doc_)
> @@ -207,11 +211,12 @@ struct uinteger_option_def : option_def
>  {
>    uinteger_option_def (const char *long_option_,
>  		       unsigned int *(*get_var_address_cb_) (Context *),
> +		       const literal_def *extra_literals_,
>  		       show_value_ftype *show_cmd_cb_,
>  		       const char *set_doc_,
>  		       const char *show_doc_ = nullptr,
>  		       const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_uinteger,
> +    : option_def (long_option_, var_uinteger, extra_literals_,
>  		  (erased_get_var_address_ftype *) get_var_address_cb_,
>  		  show_cmd_cb_,
>  		  set_doc_, show_doc_, help_doc_)

I think we should add a second constructor for uinteger_option_def like
this:

  uinteger_option_def (const char *long_option_,
                      unsigned int *(*get_var_address_cb_) (Context *),
                      show_value_ftype *show_cmd_cb_,
                      const char *set_doc_,
                      const char *show_doc_ = nullptr,
                      const char *help_doc_ = nullptr)
    : uinteger_option_def (long_option_, get_var_address_cb_,
                          uinteger_unlimited_literals, show_cmd_cb_,
                          set_doc_, show_doc_, help_doc_)
  { /* Nothing.  */ }

This would keep the existing '0 == unlimited' as the default behaviour,
but still give the option of overriding the literals if needed.


> @@ -220,18 +225,19 @@ struct uinteger_option_def : option_def
>    }
>  };
>  
> -/* A var_zuinteger_unlimited command line option.  */
> +/* A var_integer command line option.  */
>  
>  template<typename Context>
> -struct zuinteger_unlimited_option_def : option_def

If instead of deleting zuinteger_unlimited_option_def we redefined the
class like this:

  /* A var_zuinteger_unlimited command line option.  */
  
  template<typename Context>
  struct zuinteger_unlimited_option_def : integer_option_def<Context>
  {
    zuinteger_unlimited_option_def (const char *long_option_,
                                   int *(*get_var_address_cb_) (Context *),
                                   show_value_ftype *show_cmd_cb_,
                                   const char *set_doc_,
                                   const char *show_doc_ = nullptr,
                                   const char *help_doc_ = nullptr)
      : integer_option_def<Context> (long_option_, get_var_address_cb_,
                                    zuinteger_unlimited_literals, show_cmd_cb_,
                                    set_doc_, show_doc_, help_doc_)
    { /* Nothing.  */ }
  };

We could then still make use of zuinteger_unlimited_option_def if we
wanted, which would be an integer with zuinteger_unlimited_literals.

With this change, and the previous change I suggest, all the changes in
valprint.c could be reverted.




> +struct integer_option_def : option_def
>  {
> -  zuinteger_unlimited_option_def (const char *long_option_,
> -				  int *(*get_var_address_cb_) (Context *),
> -				  show_value_ftype *show_cmd_cb_,
> -				  const char *set_doc_,
> -				  const char *show_doc_ = nullptr,
> -				  const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_zuinteger_unlimited,
> +  integer_option_def (const char *long_option_,
> +		      int *(*get_var_address_cb_) (Context *),
> +		      const literal_def *extra_literals_,
> +		      show_value_ftype *show_cmd_cb_,
> +		      const char *set_doc_,
> +		      const char *show_doc_ = nullptr,
> +		      const char *help_doc_ = nullptr)
> +    : option_def (long_option_, var_integer, extra_literals_,
>  		  (erased_get_var_address_ftype *) get_var_address_cb_,
>  		  show_cmd_cb_,
>  		  set_doc_, show_doc_, help_doc_)
> @@ -252,7 +258,7 @@ struct enum_option_def : option_def
>  		   const char *set_doc_,
>  		   const char *show_doc_ = nullptr,
>  		   const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_enum,
> +    : option_def (long_option_, var_enum, nullptr,
>  		  (erased_get_var_address_ftype *) get_var_address_cb_,
>  		  show_cmd_cb_,
>  		  set_doc_, show_doc_, help_doc_)
> @@ -273,7 +279,7 @@ struct string_option_def : option_def
>  		     const char *set_doc_,
>  		     const char *show_doc_ = nullptr,
>  		     const char *help_doc_ = nullptr)
> -    : option_def (long_option_, var_string,
> +    : option_def (long_option_, var_string, nullptr,
>  		  (erased_get_var_address_ftype *) get_var_address_cb_,
>  		  show_cmd_cb_,
>  		  set_doc_, show_doc_, help_doc_)
> Index: src/gdb/cli/cli-setshow.c
> ===================================================================
> --- src.orig/gdb/cli/cli-setshow.c
> +++ src/gdb/cli/cli-setshow.c
> @@ -149,10 +149,11 @@ deprecated_show_value_hack (struct ui_fi
>      }
>  }
>  
> -/* Returns true if ARG is "unlimited".  */
> +/* Returns true and the value in VAL if ARG is an accepted literal.  */
>  
>  static bool
> -is_unlimited_literal (const char **arg, bool expression)
> +get_literal_val (LONGEST &val, const literal_def *extra_literals,
> +		 const char **arg, bool expression)
>  {
>    *arg = skip_spaces (*arg);
>  
> @@ -162,85 +163,108 @@ is_unlimited_literal (const char **arg,
>  
>    size_t len = p - *arg;
>  
> -  if (len > 0 && strncmp ("unlimited", *arg, len) == 0)
> -    {
> -      *arg += len;
> -
> -      /* If parsing an expression (i.e., parsing for a "set" command),
> -	 anything after "unlimited" is junk.  For options, anything
> -	 after "unlimited" might be a command argument or another
> -	 option.  */
> -      if (expression)
> +  if (len > 0 && extra_literals != nullptr)
> +    for (const literal_def *l = extra_literals;
> +	 l->literal != nullptr;
> +	 l++)
> +      if (strncmp (l->literal, *arg, len) == 0)
>  	{
> -	  const char *after = skip_spaces (*arg);
> -	  if (*after != '\0')
> -	    error (_("Junk after \"%.*s\": %s"),
> -		   (int) len, unl_start, after);
> -	}
> +	  *arg += len;
>  
> -      return true;
> -    }
> +	  /* If parsing an expression (i.e., parsing for a "set" command),
> +	     anything after the literal is junk.  For options, anything
> +	     after the literal might be a command argument or another
> +	     option.  */
> +	  if (expression)
> +	    {
> +	      const char *after = skip_spaces (*arg);
> +	      if (*after != '\0')
> +		error (_("Junk after \"%.*s\": %s"),
> +		       (int) len, unl_start, after);
> +	    }
> +
> +	  val = l->use;
> +	  return true;
> +	}
>  
>    return false;
>  }
>  
>  /* See cli-setshow.h.  */
>  
> -unsigned int
> -parse_cli_var_uinteger (var_types var_type, const char **arg,
> -			bool expression)
> +LONGEST
> +parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
> +		       const char **arg, bool expression)
>  {
>    LONGEST val;
>  
>    if (*arg == nullptr || **arg == '\0')
>      {
> -      if (var_type == var_uinteger)
> -	error_no_arg (_("integer to set it to, or \"unlimited\""));
> -      else
> +      if (extra_literals == nullptr)
>  	error_no_arg (_("integer to set it to"));
> -    }
> -
> -  if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
> -    val = 0;
> -  else if (expression)
> -    val = parse_and_eval_long (*arg);
> -  else
> -    val = get_ulongest (arg);
> -
> -  if (var_type == var_uinteger && val == 0)
> -    val = UINT_MAX;
> -  else if (val < 0
> -	   /* For var_uinteger, don't let the user set the value
> -	      to UINT_MAX directly, as that exposes an
> -	      implementation detail to the user interface.  */
> -	   || (var_type == var_uinteger && val >= UINT_MAX)
> -	   || (var_type == var_zuinteger && val > UINT_MAX))
> -    error (_("integer %s out of range"), plongest (val));
> -
> -  return val;
> -}
> -
> -/* See cli-setshow.h.  */
> +      else
> +	{
> +	  std::string buffer = "";
> +	  size_t count = 0;
>  
> -int
> -parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
> -{
> -  LONGEST val;
> +	  for (const literal_def *l = extra_literals;
> +	       l->literal != nullptr;
> +	       l++, count++)
> +	    {
> +	      if (count != 0)
> +		buffer += ", ";
> +	      buffer = buffer + '"' + l->literal + '"';
> +	    }
> +	  if (count > 1)
> +	    error_no_arg
> +	      (string_printf (_("integer to set it to, or one of: %s"),
> +			      buffer.c_str ()).c_str ());
> +	  else
> +	    error_no_arg
> +	      (string_printf (_("integer to set it to, or %s"),
> +			      buffer.c_str ()).c_str ());
> +	}
> +    }
>  
> -  if (*arg == nullptr || **arg == '\0')
> -    error_no_arg (_("integer to set it to, or \"unlimited\""));
> +  if (!get_literal_val (val, extra_literals, arg, expression))
> +    {
> +      if (expression)
> +	val = parse_and_eval_long (*arg);
> +      else
> +	val = get_ulongest (arg);
>  
> -  if (is_unlimited_literal (arg, expression))
> -    val = -1;
> -  else if (expression)
> -    val = parse_and_eval_long (*arg);
> -  else
> -    val = get_ulongest (arg);
> +      enum tribool allowed = TRIBOOL_UNKNOWN;
> +      if (extra_literals != nullptr)
> +	{
> +	  for (const literal_def *l = extra_literals;
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (val == l->val)
> +	      {
> +		allowed = l->allow ? TRIBOOL_TRUE : TRIBOOL_FALSE;
> +		val = l->use;
> +		break;
> +	      }
> +	    else if (val == l->use)
> +	      {
> +		allowed = TRIBOOL_FALSE;
> +		break;
> +	      }
> +	}

I haven't run the testsuite on this, so maybe there's issues, but I'd
like to propose that this loop be rewritten as:

      if (extra_literals != nullptr)
	{
	  for (const literal_def *l = extra_literals;
	       l->literal != nullptr;
	       l++)
	    if (val == l->val && l->allow)
	      {
		allowed = TRIBOOL_TRUE;
		val = l->use;
		break;
	      }
	    else if (val == l->use)
	      allowed = TRIBOOL_FALSE;
	}

The 'if (val == l->val && l->allow)' would be improved if l->val was
changed to an optional.  The change to the 'val == l->use' block allows
I think another improvement, this:

  static const literal_def print_characters_literals[] =
    {
      { "elements", 0, 0, false },
      { "unlimited", 0, UINT_MAX, true },
      { nullptr }
    };

The change here is that:

  set print characters 0

now behaves the same as:

  set print elements 0

In both cases, this sets the value to "unlimited".  I like the
consistency.

>  
> -  if (val > INT_MAX)
> -    error (_("integer %s out of range"), plongest (val));
> -  else if (val < -1)
> -    error (_("only -1 is allowed to set as unlimited"));
> +      if (allowed == TRIBOOL_UNKNOWN)
> +	{
> +	  if (var_type == var_pinteger && val < 0)
> +	    error (_("only -1 is allowed to set as unlimited"));
> +	  else if (val > UINT_MAX || val < INT_MIN
> +		   || (var_type == var_uinteger && val < 0)
> +		   || (var_type == var_integer && val > INT_MAX)
> +		   || (var_type == var_pinteger && val > INT_MAX))
> +	    allowed = TRIBOOL_FALSE;
> +	}
> +      if (allowed == TRIBOOL_FALSE)
> +	error (_("integer %s out of range"), plongest (val));
> +    }
>  
>    return val;
>  }
> @@ -405,41 +429,18 @@ do_set_command (const char *arg, int fro
>        option_changed = c->var->set<enum auto_boolean> (parse_auto_binary_operation (arg));
>        break;
>      case var_uinteger:
> -    case var_zuinteger:
>        option_changed
> -	= c->var->set<unsigned int> (parse_cli_var_uinteger (c->var->type (),
> -							     &arg, true));
> +	= c->var->set<unsigned int> (parse_cli_var_integer (c->var->type (),
> +							    c->var->
> +							    extra_literals (),
> +							    &arg, true));
>        break;
>      case var_integer:
> -    case var_zinteger:
> -      {
> -	LONGEST val;
> -
> -	if (*arg == '\0')
> -	  {
> -	    if (c->var->type () == var_integer)
> -	      error_no_arg (_("integer to set it to, or \"unlimited\""));
> -	    else
> -	      error_no_arg (_("integer to set it to"));
> -	  }
> -
> -	if (c->var->type () == var_integer && is_unlimited_literal (&arg, true))
> -	  val = 0;
> -	else
> -	  val = parse_and_eval_long (arg);
> -
> -	if (val == 0 && c->var->type () == var_integer)
> -	  val = INT_MAX;
> -	else if (val < INT_MIN
> -		 /* For var_integer, don't let the user set the value
> -		    to INT_MAX directly, as that exposes an
> -		    implementation detail to the user interface.  */
> -		 || (c->var->type () == var_integer && val >= INT_MAX)
> -		 || (c->var->type () == var_zinteger && val > INT_MAX))
> -	  error (_("integer %s out of range"), plongest (val));
> -
> -	option_changed = c->var->set<int> (val);
> -      }
> +    case var_pinteger:
> +      option_changed
> +	= c->var->set<int> (parse_cli_var_integer (c->var->type (),
> +						   c->var->extra_literals (),
> +						   &arg, true));
>        break;
>      case var_enum:
>        {
> @@ -454,10 +455,6 @@ do_set_command (const char *arg, int fro
>  	option_changed = c->var->set<const char *> (match);
>        }
>        break;
> -    case var_zuinteger_unlimited:
> -      option_changed = c->var->set<int>
> -	(parse_cli_var_zuinteger_unlimited (&arg, true));
> -      break;
>      default:
>        error (_("gdb internal error: bad var_type in do_setshow_command"));
>      }
> @@ -551,7 +548,6 @@ do_set_command (const char *arg, int fro
>  	  }
>  	  break;
>  	case var_uinteger:
> -	case var_zuinteger:
>  	  {
>  	    char s[64];
>  
> @@ -560,8 +556,7 @@ do_set_command (const char *arg, int fro
>  	  }
>  	  break;
>  	case var_integer:
> -	case var_zinteger:
> -	case var_zuinteger_unlimited:
> +	case var_pinteger:
>  	  {
>  	    char s[64];
>  
> @@ -623,36 +618,32 @@ get_setshow_command_value_string (const
>  	}
>        break;
>      case var_uinteger:
> -    case var_zuinteger:
> -      {
> -	const unsigned int value = var.get<unsigned int> ();
> -
> -	if (var.type () == var_uinteger
> -	    && value == UINT_MAX)
> -	  stb.puts ("unlimited");
> -	else
> -	  stb.printf ("%u", value);
> -      }
> -      break;
>      case var_integer:
> -    case var_zinteger:
> +    case var_pinteger:
>        {
> -	const int value = var.get<int> ();
> +	bool printed = false;
> +	const LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
>  
> -	if (var.type () == var_integer
> -	    && value == INT_MAX)
> -	  stb.puts ("unlimited");
> -	else
> -	  stb.printf ("%d", value);
> -      }
> -      break;
> -    case var_zuinteger_unlimited:
> -      {
> -	const int value = var.get<int> ();
> -	if (value == -1)
> -	  stb.puts ("unlimited");
> -	else
> -	  stb.printf ("%d", value);
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		stb.puts (l->literal);
> +		printed = true;
> +		break;
> +	      }
> +	if (!printed)
> +	  {
> +	    if (var.type () == var_uinteger)
> +	      stb.printf ("%u", static_cast<const unsigned int> (value));
> +	    else
> +	      stb.printf ("%d", static_cast<const int> (value));
> +	  }
>        }
>        break;
>      default:
> Index: src/gdb/cli/cli-setshow.h
> ===================================================================
> --- src.orig/gdb/cli/cli-setshow.h
> +++ src/gdb/cli/cli-setshow.h
> @@ -29,21 +29,19 @@ extern int parse_cli_boolean_value (cons
>     past a successfully parsed value.  */
>  extern int parse_cli_boolean_value (const char **arg);
>  
> -/* Parse ARG, an option to a var_uinteger or var_zuinteger variable.
> -   Either returns the parsed value on success or throws an error.  If
> -   EXPRESSION is true, *ARG is parsed as an expression; otherwise, it
> -   is parsed with get_ulongest.  It's not possible to parse the
> +/* Parse ARG, an option to a var_uinteger, var_integer or var_pinteger
> +   variable.  Return the parsed value on success or throw an error.  If
> +   EXTRA_LITERALS is non-null, then interpret those literals accordingly.
> +   If EXPRESSION is true, *ARG is parsed as an expression; otherwise,
> +   it is parsed with get_ulongest.  It's not possible to parse the
>     integer as an expression when there may be valid input after the
>     integer, such as when parsing command options.  E.g., "print
>     -elements NUMBER -obj --".  In such case, parsing as an expression
>     would parse "-obj --" as part of the expression as well.  */
> -extern unsigned int parse_cli_var_uinteger (var_types var_type,
> -					    const char **arg,
> -					    bool expression);
> -
> -/* Like parse_cli_var_uinteger, for var_zuinteger_unlimited.  */
> -extern int parse_cli_var_zuinteger_unlimited (const char **arg,
> -					      bool expression);
> +extern LONGEST parse_cli_var_integer (var_types var_type,
> +				      const literal_def *extra_literals,
> +				      const char **arg,
> +				      bool expression);
>  
>  /* Parse ARG, an option to a var_enum variable.  ENUM is a
>     null-terminated array of possible values. Either returns the parsed
> Index: src/gdb/command.h
> ===================================================================
> --- src.orig/gdb/command.h
> +++ src/gdb/command.h
> @@ -84,16 +84,18 @@ typedef enum var_types
>         value.  */
>      var_auto_boolean,
>  
> -    /* Unsigned Integer.  *VAR is an unsigned int.  The user can type
> -       0 to mean "unlimited", which is stored in *VAR as UINT_MAX.  */
> +    /* Unsigned Integer.  *VAR is an unsigned int.  In the Guile and Python
> +       APIs 0 means unlimited, which is stored in *VAR as UINT_MAX.  */
>      var_uinteger,
>  
> -    /* Like var_uinteger but signed.  *VAR is an int.  The user can
> -       type 0 to mean "unlimited", which is stored in *VAR as
> -       INT_MAX.  The only remaining use of it is the Python API.
> -       Don't use it elsewhere.  */
> +    /* Like var_uinteger but signed.  *VAR is an int.  In the Guile and
> +       Python APIs 0 means unlimited, which is stored in *VAR as INT_MAX.  */
>      var_integer,
>  
> +    /* Like var_integer but negative numbers are not allowed,
> +       except for special values.  *VAR is an int.  */
> +    var_pinteger,
> +
>      /* String which the user enters with escapes (e.g. the user types
>         \n and it is a real newline in the stored string).
>         *VAR is a std::string, "" if the string is empty.  */
> @@ -106,15 +108,16 @@ typedef enum var_types
>      var_optional_filename,
>      /* String which stores a filename.  (*VAR) is a std::string.  */
>      var_filename,
> -    /* ZeroableInteger.  *VAR is an int.  Like var_integer except
> -       that zero really means zero.  */
> +    /* Like var_integer.  *VAR is an int.  The only remaining uses
> +       of it are the Guile and Python APIs.  Don't use it elsewhere.  */
>      var_zinteger,
> -    /* ZeroableUnsignedInteger.  *VAR is an unsigned int.  Zero really
> -       means zero.  */
> +    /* Like var_uinteger.  *VAR is an unsigned int.  The only remaining
> +       uses of it are the Guile and Python APIs.  Don't use it elsewhere.  */
>      var_zuinteger,
> -    /* ZeroableUnsignedInteger with unlimited value.  *VAR is an int,
> -       but its range is [0, INT_MAX].  -1 stands for unlimited and
> -       other negative numbers are not allowed.  */
> +    /* Like var_pinteger.  *VAR is an int, but its range is [-1, INT_MAX].
> +       -1 stands for unlimited and other negative numbers are not allowed.
> +       The only remaining uses of it are the Guile and Python APIs.  Don't
> +       use it elsewhere.  */
>      var_zuinteger_unlimited,
>      /* Enumerated type.  Can only have one of the specified values.
>         *VAR is a char pointer to the name of the element that we
> @@ -123,6 +126,22 @@ typedef enum var_types
>    }
>  var_types;
>  
> +/* A structure describing an extra literal accepted and shown in place
> +   of a number.  */
> +typedef struct literal_defs

You don't need the typedef trick as this is C++.

> +  {
> +    /* The literal to define, e.g. "unlimited".  */
> +    const char *literal;
> +    /* A number optionally accepted that stands for the literal.  */
> +    LONGEST val;
> +    /* The number to substitute internally for LITERAL or VAL;
> +       the use of this number is not allowed (unless the same as VAL).  */
> +    LONGEST use;
> +    /* True if the use of VAL is allowed; otherwise only the literal is.  */
> +    bool allow;

Could we replace VAL and ALLOW with something like:

  gdb::optional<LONGEST> ....

> +  }
> +literal_def;
> +
>  /* Return true if a setting of type VAR_TYPE is backed with type T.
>  
>     This function is left without definition intentionally.  This template is
> @@ -153,15 +172,14 @@ inline bool var_type_uses<enum auto_bool
>  template<>
>  inline bool var_type_uses<unsigned int> (var_types t)
>  {
> -  return (t == var_uinteger || t == var_zinteger || t == var_zuinteger);
> +  return t == var_uinteger;
>  }

Should we really remove all these uses of var_zinteger, etc?  The enum
values are still around, right?  So surely if you passed in that enum
field the true/false response shouldn't change...

Thanks,
Andrew

>  
>  /* Return true if a setting of type T is backed by an int variable.  */
>  template<>
>  inline bool var_type_uses<int> (var_types t)
>  {
> -  return (t == var_integer || t == var_zinteger
> -	  || t == var_zuinteger_unlimited);
> +  return t == var_integer || t == var_pinteger;
>  }
>  
>  /* Return true if a setting of type T is backed by a std::string variable.  */
> @@ -233,6 +251,7 @@ struct setting
>    struct erased_args
>    {
>      void *var;
> +    const void *extra_literals;
>      erased_func setter;
>      erased_func getter;
>    };
> @@ -240,6 +259,7 @@ struct setting
>    template<typename T>
>    static erased_args erase_args (var_types var_type,
>  				 T *var,
> +				 const literal_def *extra_literals,
>  				 typename setting_func_types<T>::set set_setting_func,
>  				 typename setting_func_types<T>::get get_setting_func)
>    {
> @@ -254,6 +274,7 @@ struct setting
>  
>      return {
>  	var,
> +	extra_literals,
>  	reinterpret_cast<erased_func> (set_setting_func),
>  	reinterpret_cast<erased_func> (get_setting_func)
>      };
> @@ -265,6 +286,7 @@ struct setting
>    setting (var_types var_type, const erased_args &args)
>      : m_var_type (var_type),
>        m_var (args.var),
> +      m_extra_literals (args.extra_literals),
>        m_getter (args.getter),
>        m_setter (args.setter)
>    {
> @@ -295,6 +317,10 @@ struct setting
>    var_types type () const
>    { return m_var_type; }
>  
> +  /* Access any extra literals accepted.  */
> +  const literal_def *extra_literals () const
> +  { return static_cast<const literal_def *> (m_extra_literals); }
> +
>    /* Return the current value.
>  
>       The template parameter T is the type of the variable used to store the
> @@ -357,6 +383,9 @@ struct setting
>       non-nullptr.  */
>    void *m_var = nullptr;
>  
> +  /* Any extra literals accepted.  */
> +  const void *m_extra_literals = nullptr;
> +
>    /* Pointer to a user provided getter.  */
>    erased_func m_getter = nullptr;
>  
> @@ -652,6 +681,11 @@ typedef void (show_value_ftype) (struct
>     instead print the value out directly.  */
>  extern show_value_ftype deprecated_show_value_hack;
>  
> +/* Various sets of extra literals accepted.  */
> +extern const literal_def integer_unlimited_literals[];
> +extern const literal_def uinteger_unlimited_literals[];
> +extern const literal_def zuinteger_unlimited_literals[];
> +
>  extern set_show_commands add_setshow_enum_cmd
>    (const char *name, command_class theclass, const char *const *enumlist,
>     const char **var, const char *set_doc, const char *show_doc,
> @@ -748,6 +782,20 @@ extern set_show_commands add_setshow_opt
>     cmd_list_element **show_list);
>  
>  extern set_show_commands add_setshow_integer_cmd
> +  (const char *name, command_class theclass, int *var,
> +   const literal_def *extra_literals, const char *set_doc,
> +   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
> +   show_value_ftype *show_func, cmd_list_element **set_list,
> +   cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_integer_cmd
> +  (const char *name, command_class theclass, const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   setting_func_types<int>::set set_func,
> +   setting_func_types<int>::get get_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_integer_cmd
>    (const char *name, command_class theclass, int *var, const char *set_doc,
>     const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
>     show_value_ftype *show_func, cmd_list_element **set_list,
> @@ -760,6 +808,34 @@ extern set_show_commands add_setshow_int
>     setting_func_types<int>::get get_func, show_value_ftype *show_func,
>     cmd_list_element **set_list, cmd_list_element **show_list);
>  
> +extern set_show_commands add_setshow_pinteger_cmd
> +  (const char *name, command_class theclass, int *var,
> +   const literal_def *extra_literals, const char *set_doc,
> +   const char *show_doc, const char *help_doc, cmd_func_ftype *set_func,
> +   show_value_ftype *show_func, cmd_list_element **set_list,
> +   cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_pinteger_cmd
> +  (const char *name, command_class theclass, const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   setting_func_types<int>::set set_func,
> +   setting_func_types<int>::get get_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_uinteger_cmd
> +  (const char *name, command_class theclass, unsigned int *var,
> +   const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   cmd_func_ftype *set_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
> +extern set_show_commands add_setshow_uinteger_cmd
> +  (const char *name, command_class theclass, const literal_def *extra_literals,
> +   const char *set_doc, const char *show_doc, const char *help_doc,
> +   setting_func_types<unsigned int>::set set_func,
> +   setting_func_types<unsigned int>::get get_func, show_value_ftype *show_func,
> +   cmd_list_element **set_list, cmd_list_element **show_list);
> +
>  extern set_show_commands add_setshow_uinteger_cmd
>    (const char *name, command_class theclass, unsigned int *var,
>     const char *set_doc, const char *show_doc, const char *help_doc,
> Index: src/gdb/guile/scm-param.c
> ===================================================================
> --- src.orig/gdb/guile/scm-param.c
> +++ src/gdb/guile/scm-param.c
> @@ -117,18 +117,33 @@ struct param_smob
>  static setting
>  make_setting (param_smob *s)
>  {
> -  if (var_type_uses<bool> (s->type))
> -    return setting (s->type, &s->value.boolval);
> -  else if (var_type_uses<int> (s->type))
> -    return setting (s->type, &s->value.intval);
> -  else if (var_type_uses<auto_boolean> (s->type))
> -    return setting (s->type, &s->value.autoboolval);
> -  else if (var_type_uses<unsigned int> (s->type))
> -    return setting (s->type, &s->value.uintval);
> -  else if (var_type_uses<std::string> (s->type))
> -    return setting (s->type, s->value.stringval);
> -  else if (var_type_uses<const char *> (s->type))
> -    return setting (s->type, &s->value.cstringval);
> +  enum var_types type = s->type;
> +
> +  switch (type)
> +    {
> +    case var_zinteger:
> +      type = var_integer;
> +      break;
> +    case var_zuinteger:
> +      type = var_uinteger;
> +      break;
> +    case var_zuinteger_unlimited:
> +      type = var_pinteger;
> +      break;
> +    }
> +
> +  if (var_type_uses<bool> (type))
> +    return setting (type, &s->value.boolval);
> +  else if (var_type_uses<int> (type))
> +    return setting (type, &s->value.intval);
> +  else if (var_type_uses<auto_boolean> (type))
> +    return setting (type, &s->value.autoboolval);
> +  else if (var_type_uses<unsigned int> (type))
> +    return setting (type, &s->value.uintval);
> +  else if (var_type_uses<std::string> (type))
> +    return setting (type, s->value.stringval);
> +  else if (var_type_uses<const char *> (type))
> +    return setting (type, &s->value.cstringval);
>    else
>      gdb_assert_not_reached ("unhandled var type");
>  }
> @@ -588,10 +603,6 @@ pascm_param_type_name (enum var_types pa
>  static SCM
>  pascm_param_value (const setting &var, int arg_pos, const char *func_name)
>  {
> -  /* Note: We *could* support var_integer here in case someone is trying to get
> -     the value of a Python-created parameter (which is the only place that
> -     still supports var_integer).  To further discourage its use we do not.  */
> -
>    switch (var.type ())
>      {
>      case var_string:
> @@ -631,20 +642,35 @@ pascm_param_value (const setting &var, i
>  	  return auto_keyword;
>        }
>  
> -    case var_zuinteger_unlimited:
> -      if (var.get<int> () == -1)
> -	return unlimited_keyword;
> -      gdb_assert (var.get<int> () >= 0);
> -      /* Fall through.  */
> -    case var_zinteger:
> -      return scm_from_int (var.get<int> ());
> -
>      case var_uinteger:
> -      if (var.get<unsigned int> ()== UINT_MAX)
> -	return unlimited_keyword;
> -      /* Fall through.  */
> -    case var_zuinteger:
> -      return scm_from_uint (var.get<unsigned int> ());
> +    case var_integer:
> +    case var_pinteger:
> +      {
> +	LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
> +
> +	bool literal = false;
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		if (strcmp (l->literal, "unlimited") == 0)
> +		  return unlimited_keyword;
> +		value = l->val;
> +		literal = true;
> +	      }
> +	if (var.type () == var_pinteger && !literal)
> +	  gdb_assert (value >= 0);
> +
> +	if (var.type () == var_uinteger)
> +	  return scm_from_uint (static_cast<const unsigned int> (value));
> +	else
> +	  return scm_from_int (static_cast<const int> (value));
> +      }
>  
>      default:
>        break;
> @@ -666,14 +692,14 @@ pascm_set_param_value_x (param_smob *p_s
>  {
>    setting var = make_setting (p_smob);
>  
> -  switch (var.type ())
> +  switch (p_smob->type)
>      {
>      case var_string:
>      case var_string_noescape:
>      case var_optional_filename:
>      case var_filename:
>        SCM_ASSERT_TYPE (scm_is_string (value)
> -		       || (var.type () != var_filename
> +		       || (p_smob->type != var_filename
>  			   && gdbscm_is_false (value)),
>  		       value, arg_pos, func_name,
>  		       _("string or #f for non-PARAM_FILENAME parameters"));
> @@ -739,8 +765,8 @@ pascm_set_param_value_x (param_smob *p_s
>      case var_uinteger:
>      case var_zuinteger:
>      case var_zuinteger_unlimited:
> -      if (var.type () == var_uinteger
> -	  || var.type () == var_zuinteger_unlimited)
> +      if (p_smob->type == var_uinteger
> +	  || p_smob->type == var_zuinteger_unlimited)
>  	{
>  	  SCM_ASSERT_TYPE (gdbscm_is_bool (value)
>  			   || scm_is_eq (value, unlimited_keyword),
> @@ -748,7 +774,7 @@ pascm_set_param_value_x (param_smob *p_s
>  			   _("integer or #:unlimited"));
>  	  if (scm_is_eq (value, unlimited_keyword))
>  	    {
> -	      if (var.type () == var_uinteger)
> +	      if (p_smob->type == var_uinteger)
>  		var.set<unsigned int> (UINT_MAX);
>  	      else
>  		var.set<int> (-1);
> @@ -761,12 +787,12 @@ pascm_set_param_value_x (param_smob *p_s
>  			   _("integer"));
>  	}
>  
> -      if (var.type () == var_uinteger
> -	  || var.type () == var_zuinteger)
> +      if (p_smob->type == var_uinteger
> +	  || p_smob->type == var_zuinteger)
>  	{
>  	  unsigned int u = scm_to_uint (value);
>  
> -	  if (var.type () == var_uinteger && u == 0)
> +	  if (p_smob->type == var_uinteger && u == 0)
>  	    u = UINT_MAX;
>  	  var.set<unsigned int> (u);
>  	}
> @@ -774,7 +800,7 @@ pascm_set_param_value_x (param_smob *p_s
>  	{
>  	  int i = scm_to_int (value);
>  
> -	  if (var.type () == var_zuinteger_unlimited && i < -1)
> +	  if (p_smob->type == var_zuinteger_unlimited && i < -1)
>  	    {
>  	      gdbscm_out_of_range_error (func_name, arg_pos, value,
>  					 _("must be >= -1"));
> Index: src/gdb/maint-test-options.c
> ===================================================================
> --- src.orig/gdb/maint-test-options.c
> +++ src/gdb/maint-test-options.c
> @@ -207,6 +207,7 @@ static const gdb::option::option_def tes
>    gdb::option::uinteger_option_def<test_options_opts> {
>      "uinteger",
>      [] (test_options_opts *opts) { return &opts->uint_opt; },
> +    uinteger_unlimited_literals,
>      nullptr, /* show_cmd_cb */
>      N_("A uinteger option."),
>      nullptr, /* show_doc */
> @@ -214,9 +215,10 @@ static const gdb::option::option_def tes
>    },
>  
>    /* A zuinteger_unlimited option.  */
> -  gdb::option::zuinteger_unlimited_option_def<test_options_opts> {
> +  gdb::option::integer_option_def<test_options_opts> {
>      "zuinteger-unlimited",
>      [] (test_options_opts *opts) { return &opts->zuint_unl_opt; },
> +    zuinteger_unlimited_literals,
>      nullptr, /* show_cmd_cb */
>      N_("A zuinteger-unlimited option."),
>      nullptr, /* show_doc */
> Index: src/gdb/python/py-param.c
> ===================================================================
> --- src.orig/gdb/python/py-param.c
> +++ src/gdb/python/py-param.c
> @@ -96,18 +96,33 @@ struct parmpy_object
>  static setting
>  make_setting (parmpy_object *s)
>  {
> -  if (var_type_uses<bool> (s->type))
> -    return setting (s->type, &s->value.boolval);
> -  else if (var_type_uses<int> (s->type))
> -    return setting (s->type, &s->value.intval);
> -  else if (var_type_uses<auto_boolean> (s->type))
> -    return setting (s->type, &s->value.autoboolval);
> -  else if (var_type_uses<unsigned int> (s->type))
> -    return setting (s->type, &s->value.uintval);
> -  else if (var_type_uses<std::string> (s->type))
> -    return setting (s->type, s->value.stringval);
> -  else if (var_type_uses<const char *> (s->type))
> -    return setting (s->type, &s->value.cstringval);
> +  enum var_types type = s->type;
> +
> +  switch (type)
> +    {
> +    case var_zinteger:
> +      type = var_integer;
> +      break;
> +    case var_zuinteger:
> +      type = var_uinteger;
> +      break;
> +    case var_zuinteger_unlimited:
> +      type = var_pinteger;
> +      break;
> +    }
> +
> +  if (var_type_uses<bool> (type))
> +    return setting (type, &s->value.boolval);
> +  else if (var_type_uses<int> (type))
> +    return setting (type, &s->value.intval);
> +  else if (var_type_uses<auto_boolean> (type))
> +    return setting (type, &s->value.autoboolval);
> +  else if (var_type_uses<unsigned int> (type))
> +    return setting (type, &s->value.uintval);
> +  else if (var_type_uses<std::string> (type))
> +    return setting (type, s->value.stringval);
> +  else if (var_type_uses<const char *> (type))
> +    return setting (type, &s->value.cstringval);
>    else
>      gdb_assert_not_reached ("unhandled var type");
>  }
> Index: src/gdb/python/python.c
> ===================================================================
> --- src.orig/gdb/python/python.c
> +++ src/gdb/python/python.c
> @@ -502,35 +502,34 @@ gdbpy_parameter_value (const setting &va
>  	  Py_RETURN_NONE;
>        }
>  
> -    case var_integer:
> -      if (var.get<int> () == INT_MAX)
> -	Py_RETURN_NONE;
> -      /* Fall through.  */
> -    case var_zinteger:
> -      return gdb_py_object_from_longest (var.get<int> ()).release ();
> -
> -    case var_zuinteger_unlimited:
> -      {
> -	int val = var.get<int> ();
> -
> -	if (val == -1)
> -	  Py_RETURN_NONE;
> -	return gdb_py_object_from_longest (val).release ();
> -      }
> -
>      case var_uinteger:
> +    case var_integer:
> +    case var_pinteger:
>        {
> -	unsigned int val = var.get<unsigned int> ();
> +	LONGEST value
> +	  = (var.type () == var_uinteger
> +	     ? static_cast<LONGEST> (var.get<unsigned int> ())
> +	     : static_cast<LONGEST> (var.get<int> ()));
>  
> -	if (val == UINT_MAX)
> -	  Py_RETURN_NONE;
> -	return gdb_py_object_from_ulongest (val).release ();
> -      }
> +	if (var.extra_literals () != nullptr)
> +	  for (const literal_def *l = var.extra_literals ();
> +	       l->literal != nullptr;
> +	       l++)
> +	    if (value == l->use)
> +	      {
> +		if (strcmp (l->literal, "unlimited") == 0)
> +		  Py_RETURN_NONE;
> +		value = l->val;
> +	      }
>  
> -    case var_zuinteger:
> -      {
> -	unsigned int val = var.get<unsigned int> ();
> -	return gdb_py_object_from_ulongest (val).release ();
> +	if (var.type () == var_uinteger)
> +	  return
> +	    gdb_py_object_from_ulongest
> +	      (static_cast<const unsigned int> (value)).release ();
> +	else
> +	  return
> +	    gdb_py_object_from_longest
> +	      (static_cast<const int> (value)).release ();
>        }
>      }
>  
> Index: src/gdb/valprint.c
> ===================================================================
> --- src.orig/gdb/valprint.c
> +++ src/gdb/valprint.c
> @@ -2974,8 +2974,8 @@ using boolean_option_def
>    = gdb::option::boolean_option_def<value_print_options>;
>  using uinteger_option_def
>    = gdb::option::uinteger_option_def<value_print_options>;
> -using zuinteger_unlimited_option_def
> -  = gdb::option::zuinteger_unlimited_option_def<value_print_options>;
> +using integer_option_def
> +  = gdb::option::integer_option_def<value_print_options>;
>  
>  /* Definitions of options for the "print" and "compile print"
>     commands.  */
> @@ -3011,15 +3011,17 @@ static const gdb::option::option_def val
>    uinteger_option_def {
>      "elements",
>      [] (value_print_options *opt) { return &opt->print_max; },
> +    uinteger_unlimited_literals,
>      show_print_max, /* show_cmd_cb */
>      N_("Set limit on string chars or array elements to print."),
>      N_("Show limit on string chars or array elements to print."),
>      N_("\"unlimited\" causes there to be no limit."),
>    },
>  
> -  zuinteger_unlimited_option_def {
> +  integer_option_def {
>      "max-depth",
>      [] (value_print_options *opt) { return &opt->max_depth; },
> +    zuinteger_unlimited_literals,
>      show_print_max_depth, /* show_cmd_cb */
>      N_("Set maximum print depth for nested structures, unions and arrays."),
>      N_("Show maximum print depth for nested structures, unions, and arrays."),
> @@ -3079,6 +3081,7 @@ pretty-printers for that value.")
>    uinteger_option_def {
>      "repeats",
>      [] (value_print_options *opt) { return &opt->repeat_count_threshold; },
> +    uinteger_unlimited_literals,
>      show_repeat_count_threshold, /* show_cmd_cb */
>      N_("Set threshold for repeated print elements."),
>      N_("Show threshold for repeated print elements."),


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages
  2022-06-24 14:32   ` Andrew Burgess
@ 2022-06-29 14:29     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-29 14:29 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Simon Sobisch, Tom Tromey

On Fri, 24 Jun 2022, Andrew Burgess wrote:

> > This is grammatically incorrect, so remove the full stop and adjust the 
> > testsuite accordingly.
> 
> LGTM.

 I have applied this change now, thank you for your review.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check
  2022-06-24 15:09   ` Andrew Burgess
@ 2022-06-29 14:29     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-29 14:29 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Simon Sobisch, Tom Tromey

On Fri, 24 Jun 2022, Andrew Burgess wrote:

> > Match the whole error message expected to be given rather than omitting 
> > the part about the "unlimited" keyword.  There's no point in omitting 
> > the missing part first, and second with an upcoming change the part in 
> > parentheses will no longer be a fixed string, so doing a full match will 
> > ensure the algorithm correctly builds the message expected here.  Also 
> > avoid any wildcard matches.
> 
> LGTM.

 I have committed this change too, thank you!

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited'
  2022-06-24 14:40   ` Andrew Burgess
@ 2022-06-29 16:48     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-29 16:48 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Simon Sobisch, Tom Tromey

On Fri, 24 Jun 2022, Andrew Burgess wrote:

> > Consistently with the `var_integer' and `var_uinteger' parameters return 
> > the special value of None for a `var_zuinteger_unlimited' parameter set 
> > to `unlimited' by using the Py_RETURN_NONE macro in this case, fixing 
> > commit 0489430a0e1a ("Handle var_zuinteger and var_zuinteger_unlimited 
> > from Python"); cf. PR python/20084.  Adjust the testsuite
> > accordingly.
> 
> Unfortunately, nice as it would be to make this change (for
> consistency), I think we're stuck with what we have.

 Yes, this does seem a bit risky, however we already have a documented 
precedent for a similar API correction:

 -- Function: gdb.breakpoints ()
     Return a sequence holding all of GDB's breakpoints.  *Note
     Breakpoints In Python::, for more information.  In GDB version 7.11
     and earlier, this function returned 'None' if there were no
     breakpoints.  This peculiarity was subsequently fixed, and now
     'gdb.breakpoints' returns an empty sequence in this case.

and here the peculiarity/inconsistency in my opinion is even more 
prominent.

> The -1 behaviour is documented for PARAM_ZUINTEGER_UNLIMITED in the
> manual so it is not unreasonable to assume that there could be code in
> the wild that relies on the existing behaviuor.

 Well, but that is not different from the two other cases, which have no 
mention of 'None':

'gdb.PARAM_UINTEGER'
     The value is an unsigned integer.  The value of 0 should be
     interpreted to mean "unlimited".

'gdb.PARAM_INTEGER'
     The value is a signed integer.  The value of 0 should be
     interpreted to mean "unlimited".

even they do return 'None' for "unlimited", and then as you say:

'gdb.PARAM_ZUINTEGER_UNLIMITED'
     The value is a signed integer.  This is like 'PARAM_ZUINTEGER',
     except the special value -1 should be interpreted to mean
     "unlimited".  Other negative values are not allowed.

 So what I think would be best to do here is actually (having missed the 
manual part before):

1. Accept (if we don't already; I haven't checked) and document 'None' as 
   input to parameters of these types, meaning "unlimited".

2. Deprecate and undocument but keep accepting special numeric values as 
   input to such parameters.

3. Produce and document 'None' as output for special "unlimited" numeric 
   values consistently from all such parameters.

Yes, there could be some fallout from such a change, however it should be 
easy to correct in Python code.  What would be a typical use case in 
Python code for retrieving these parameters?  And how is 'None' handled by 
Python when just passed to a `print' like standard routine to present it 
to the user?

 Given that PARAM_ZUINTEGER_UNLIMITED has been retrofitted chances are its 
handling in user code has been as well to existing code for PARAM_UINTEGER 
and PARAM_INTEGER, and it may already handle 'None' for all the three by 
default, before going on to special-casing the special values actually 
documented.

 Please let me know what you think, and thank you for your review.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v6 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-06-24 15:08   ` Andrew Burgess
@ 2022-06-30 14:24     ` Maciej W. Rozycki
  2022-06-30 15:53       ` Eli Zaretskii
  2022-06-30 16:01       ` Andrew Burgess
  0 siblings, 2 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-30 14:24 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Simon Sobisch, Tom Tromey

Fix a completion consistency issue with `set' commands accepting integer 
values and the special `unlimited' keyword:

(gdb) complete print -elements
print -elements NUMBER
print -elements unlimited
(gdb)

vs:

(gdb) complete set print elements
set print elements unlimited
(gdb)

(there is a space entered at the end of both commands, not shown here) 
which also means if you strike <Tab> with `set print elements ' input, 
it will, annoyingly, complete to `set print elements unlimited' right 
away rather than showing a choice between `NUMBER' and `unlimited'.

Add `NUMBER' then as an available completion for such `set' commands:

(gdb) complete set print elements
set print elements NUMBER
set print elements unlimited
(gdb)
  
Adjust the testsuite accordingly.  Also document the feature in the 
Completion section of the manual in addition to the Command Options 
section already there.
---
On Fri, 24 Jun 2022, Andrew Burgess wrote:

> > Add `NUMBER' then as an available completion for such `set' commands:
> >
> > (gdb) complete set print elements
> > set print elements NUMBER
> > set print elements unlimited
> > (gdb)
> >   
> > Adjust the testsuite accordingly.
> 
> I like this change, but I think we should add some documentation in
> `@node Completion` that describes this new behaviour. We should probably
> add a NEWS entry too.

 Thank you for your review.

 This is already documented in the Command Options section, but that's not 
necessarily the place one will look for it, so maybe it's worth repeating 
here as well indeed.  I have changed the wording slightly compared to the 
original.

 How about this version then?

  Maciej

Changes from v5:

- document the `NUMBER' completion in the Completion section of the manual
  for commands accepting keywords as well as numbers,

- document the addition of `NUMBER' completion for `set' commands in NEWS.

No change from v4.

New change in v4.
---
 gdb/NEWS                            |   12 ++++++++++++
 gdb/cli/cli-decode.c                |    2 ++
 gdb/doc/gdb.texinfo                 |   15 +++++++++++++++
 gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
 4 files changed, 36 insertions(+), 1 deletion(-)

gdb-integer-complete-number.diff
Index: src/gdb/NEWS
===================================================================
--- src.orig/gdb/NEWS
+++ src/gdb/NEWS
@@ -27,6 +27,18 @@
   emit to indicate where a breakpoint should be placed to break in a function
   past its prologue.
 
+* Completion now also offers "NUMBER" for "set" commands that accept
+  a numeric argument and the "unlimited" keyword.  For example:
+
+   (gdb) set width <TAB>
+   NUMBER     unlimited
+
+  and consequently:
+
+   (gdb) complete set width
+   set width NUMBER
+   set width unlimited
+
 * New commands
 
 maintenance set ignore-prologue-end-flag on|off
Index: src/gdb/cli/cli-decode.c
===================================================================
--- src.orig/gdb/cli/cli-decode.c
+++ src/gdb/cli/cli-decode.c
@@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
       NULL,
     };
 
+  if (*text == '\0')
+    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
   complete_on_enum (tracker, keywords, text, word);
 }
 
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo
+++ src/gdb/doc/gdb.texinfo
@@ -1960,6 +1960,21 @@ After displaying the available possibili
 partial input (@samp{b make_} in the example) so you can finish the
 command.
 
+If the command you are trying to complete expects either a keyword or a
+number to follow, then @samp{NUMBER} will be shown among the available
+completions, for example:
+
+@smallexample
+(@value{GDBP}) print -elements @key{TAB}@key{TAB}
+NUMBER     unlimited
+(@value{GDBP}) print -elements@tie{}
+@end smallexample
+
+@noindent
+Here, the option expects a number (e.g., @code{100}), not literal
+@code{NUMBER}.  Such metasyntactical arguments are always presented in
+uppercase.
+
 If you just want to see the list of alternatives in the first place, you
 can press @kbd{M-?} rather than pressing @key{TAB} twice.  @kbd{M-?}
 means @kbd{@key{META} ?}.  You can type this either by holding down a
Index: src/gdb/testsuite/gdb.base/settings.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/settings.exp
+++ src/gdb/testsuite/gdb.base/settings.exp
@@ -215,8 +215,14 @@ proc test-integer {variant} {
 	test_gdb_complete_none \
 	    "$set_cmd "
     } else {
+	test_gdb_complete_multiple "$set_cmd " "" "" {
+	    "NUMBER"
+	    "unlimited"
+	}
+	test_gdb_complete_none \
+	    "$set_cmd 1"
 	test_gdb_complete_unique \
-	    "$set_cmd " \
+	    "$set_cmd u" \
 	    "$set_cmd unlimited"
     }
 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v6 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-06-30 14:24     ` [PATCH v6 " Maciej W. Rozycki
@ 2022-06-30 15:53       ` Eli Zaretskii
  2022-06-30 18:59         ` Maciej W. Rozycki
  2022-06-30 16:01       ` Andrew Burgess
  1 sibling, 1 reply; 51+ messages in thread
From: Eli Zaretskii @ 2022-06-30 15:53 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: aburgess, simonsobisch, tom, gdb-patches

> Date: Thu, 30 Jun 2022 15:24:01 +0100 (BST)
> From: "Maciej W. Rozycki" <macro@embecosm.com>
> Cc: Simon Sobisch <simonsobisch@web.de>, Tom Tromey <tom@tromey.com>,
>  gdb-patches@sourceware.org
> 
>  gdb/NEWS                            |   12 ++++++++++++
>  gdb/cli/cli-decode.c                |    2 ++
>  gdb/doc/gdb.texinfo                 |   15 +++++++++++++++
>  gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
>  4 files changed, 36 insertions(+), 1 deletion(-)

OK for the documentation parts, thanks.

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v6 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-06-30 14:24     ` [PATCH v6 " Maciej W. Rozycki
  2022-06-30 15:53       ` Eli Zaretskii
@ 2022-06-30 16:01       ` Andrew Burgess
  1 sibling, 0 replies; 51+ messages in thread
From: Andrew Burgess @ 2022-06-30 16:01 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Simon Sobisch, Tom Tromey, gdb-patches

"Maciej W. Rozycki" <macro@embecosm.com> writes:

> Fix a completion consistency issue with `set' commands accepting integer 
> values and the special `unlimited' keyword:
>
> (gdb) complete print -elements
> print -elements NUMBER
> print -elements unlimited
> (gdb)
>
> vs:
>
> (gdb) complete set print elements
> set print elements unlimited
> (gdb)
>
> (there is a space entered at the end of both commands, not shown here) 
> which also means if you strike <Tab> with `set print elements ' input, 
> it will, annoyingly, complete to `set print elements unlimited' right 
> away rather than showing a choice between `NUMBER' and `unlimited'.
>
> Add `NUMBER' then as an available completion for such `set' commands:
>
> (gdb) complete set print elements
> set print elements NUMBER
> set print elements unlimited
> (gdb)
>   
> Adjust the testsuite accordingly.  Also document the feature in the 
> Completion section of the manual in addition to the Command Options 
> section already there.

Thanks for the update, this LGTM.

Andrew


> ---
> On Fri, 24 Jun 2022, Andrew Burgess wrote:
>
>> > Add `NUMBER' then as an available completion for such `set' commands:
>> >
>> > (gdb) complete set print elements
>> > set print elements NUMBER
>> > set print elements unlimited
>> > (gdb)
>> >   
>> > Adjust the testsuite accordingly.
>> 
>> I like this change, but I think we should add some documentation in
>> `@node Completion` that describes this new behaviour. We should probably
>> add a NEWS entry too.
>
>  Thank you for your review.
>
>  This is already documented in the Command Options section, but that's not 
> necessarily the place one will look for it, so maybe it's worth repeating 
> here as well indeed.  I have changed the wording slightly compared to the 
> original.
>
>  How about this version then?
>
>   Maciej
>
> Changes from v5:
>
> - document the `NUMBER' completion in the Completion section of the manual
>   for commands accepting keywords as well as numbers,
>
> - document the addition of `NUMBER' completion for `set' commands in NEWS.
>
> No change from v4.
>
> New change in v4.
> ---
>  gdb/NEWS                            |   12 ++++++++++++
>  gdb/cli/cli-decode.c                |    2 ++
>  gdb/doc/gdb.texinfo                 |   15 +++++++++++++++
>  gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
>  4 files changed, 36 insertions(+), 1 deletion(-)
>
> gdb-integer-complete-number.diff
> Index: src/gdb/NEWS
> ===================================================================
> --- src.orig/gdb/NEWS
> +++ src/gdb/NEWS
> @@ -27,6 +27,18 @@
>    emit to indicate where a breakpoint should be placed to break in a function
>    past its prologue.
>  
> +* Completion now also offers "NUMBER" for "set" commands that accept
> +  a numeric argument and the "unlimited" keyword.  For example:
> +
> +   (gdb) set width <TAB>
> +   NUMBER     unlimited
> +
> +  and consequently:
> +
> +   (gdb) complete set width
> +   set width NUMBER
> +   set width unlimited
> +
>  * New commands
>  
>  maintenance set ignore-prologue-end-flag on|off
> Index: src/gdb/cli/cli-decode.c
> ===================================================================
> --- src.orig/gdb/cli/cli-decode.c
> +++ src/gdb/cli/cli-decode.c
> @@ -989,6 +989,8 @@ integer_unlimited_completer (struct cmd_
>        NULL,
>      };
>  
> +  if (*text == '\0')
> +    tracker.add_completion (make_unique_xstrdup ("NUMBER"));
>    complete_on_enum (tracker, keywords, text, word);
>  }
>  
> Index: src/gdb/doc/gdb.texinfo
> ===================================================================
> --- src.orig/gdb/doc/gdb.texinfo
> +++ src/gdb/doc/gdb.texinfo
> @@ -1960,6 +1960,21 @@ After displaying the available possibili
>  partial input (@samp{b make_} in the example) so you can finish the
>  command.
>  
> +If the command you are trying to complete expects either a keyword or a
> +number to follow, then @samp{NUMBER} will be shown among the available
> +completions, for example:
> +
> +@smallexample
> +(@value{GDBP}) print -elements @key{TAB}@key{TAB}
> +NUMBER     unlimited
> +(@value{GDBP}) print -elements@tie{}
> +@end smallexample
> +
> +@noindent
> +Here, the option expects a number (e.g., @code{100}), not literal
> +@code{NUMBER}.  Such metasyntactical arguments are always presented in
> +uppercase.
> +
>  If you just want to see the list of alternatives in the first place, you
>  can press @kbd{M-?} rather than pressing @key{TAB} twice.  @kbd{M-?}
>  means @kbd{@key{META} ?}.  You can type this either by holding down a
> Index: src/gdb/testsuite/gdb.base/settings.exp
> ===================================================================
> --- src.orig/gdb/testsuite/gdb.base/settings.exp
> +++ src/gdb/testsuite/gdb.base/settings.exp
> @@ -215,8 +215,14 @@ proc test-integer {variant} {
>  	test_gdb_complete_none \
>  	    "$set_cmd "
>      } else {
> +	test_gdb_complete_multiple "$set_cmd " "" "" {
> +	    "NUMBER"
> +	    "unlimited"
> +	}
> +	test_gdb_complete_none \
> +	    "$set_cmd 1"
>  	test_gdb_complete_unique \
> -	    "$set_cmd " \
> +	    "$set_cmd u" \
>  	    "$set_cmd unlimited"
>      }
>  


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v6 3/8] GDB: Add `NUMBER' completion to `set' integer commands
  2022-06-30 15:53       ` Eli Zaretskii
@ 2022-06-30 18:59         ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-06-30 18:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: aburgess, simonsobisch, tom, gdb-patches

On Thu, 30 Jun 2022, Eli Zaretskii wrote:

> > Date: Thu, 30 Jun 2022 15:24:01 +0100 (BST)
> > From: "Maciej W. Rozycki" <macro@embecosm.com>
> > Cc: Simon Sobisch <simonsobisch@web.de>, Tom Tromey <tom@tromey.com>,
> >  gdb-patches@sourceware.org
> > 
> >  gdb/NEWS                            |   12 ++++++++++++
> >  gdb/cli/cli-decode.c                |    2 ++
> >  gdb/doc/gdb.texinfo                 |   15 +++++++++++++++
> >  gdb/testsuite/gdb.base/settings.exp |    8 +++++++-
> >  4 files changed, 36 insertions(+), 1 deletion(-)
> 
> OK for the documentation parts, thanks.

 Thank you for your review, I have pushed this change now.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command
  2022-06-24 15:57   ` Andrew Burgess
@ 2022-07-07 11:04     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-07-07 11:04 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Simon Sobisch, Tom Tromey

On Fri, 24 Jun 2022, Andrew Burgess wrote:

> > We currently have no coverage for the `print -elements ...' command (or 
> > `p -elements ...' in the shortened form), so add a couple of test cases 
> > mimicking ones using corresponding `set print elements ...' values.
> 
> LGTM.

 I have pushed this change now, thank you for your review.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands
  2022-06-28 14:04   ` Andrew Burgess
@ 2022-08-17 22:03     ` Maciej W. Rozycki
  0 siblings, 0 replies; 51+ messages in thread
From: Maciej W. Rozycki @ 2022-08-17 22:03 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, Simon Sobisch, Tom Tromey

On Tue, 28 Jun 2022, Andrew Burgess wrote:

> > Rather than just `unlimited' allow the integer set commands (or command 
> > options) to define arbitrary keywords for the user to use, removing 
> > hardcoded arrangements for the `unlimited' keyword.
> >
> > Make obsolete the confusingly named `var_zinteger', `var_zuinteger' and 
> > `var_zuinteger_unlimited' `set'/`show' command variable types redefining 
> > them in terms of `var_uinteger', `var_integer' and `var_pinteger', which 
> > have the range of [0;UINT_MAX], [INT_MIN;INT_MAX], and [0;INT_MAX] each.
> >
> > Following existing practice `var_pinteger' allows extra negative values 
> > to be used, however unlike `var_zuinteger_unlimited' any number of such 
> > values can be defined rather than just `-1'.
> >
> > The "p" in `var_pinteger' stands for "positive", for the lack of a more 
> > appropriate unambiguous letter, even though 0 obviously is not positive; 
> > "n" would be confusing as to whether it stands for "non-negative" or 
> > "negative".
> 
> While looking at this patch I was thinking to myself, I wonder why we
> need var_pinteger, can't we achieve the same thing using var_uinteger
> and different literals?

 We probably could.  We'd have to forbid values within (INT_MAX;UINT_MAX] 
however somehow, and it's not clear to me such an arrangement is worth the 
complication.

 Mind that `var_pinteger' is a generalisation of `var_zuinteger_unlimited' 
and whoever came with `var_zuinteger_unlimited' must have had a reason not 
to define it in terms of an unsigned integer in the first place (and use 
UINT_MAX for `unlimited'), most likely to avoid values beyond INT_MAX.

> So I think I've convinced myself that you don't actually make use of
> var_pinteger in this patch, and I'm pretty sure you don't use it in any
> of the later patches either.
> 
> Maybe I'm wrong, so could you point out where it's used?

 See `add_setshow_zuinteger_unlimited_cmd' (and `add_setshow_pinteger_cmd' 
and `add_setshow_cmds_for_options' obviously as well; the idea here is to 
gradually move away from `add_setshow_zuinteger_unlimited_cmd' as parts of 
code are converted to using `add_setshow_cmds_for_options' referring to 
`zuinteger_unlimited_literals' as extra literals rather than individual 
calls to `add_setshow_*_cmd' functions).

> If it's not used then I think we should remove it.
> 
> If it's only used in a later commit then I think we should split its
> addition out into a later commit.
> 
> If its used in this commit, then I'm sorry for missing it!

 Your concerns however have prompted me to actually make one step further 
and remove `var_zinteger', `var_zuinteger' and `var_zuinteger_unlimited' 
enumeration constants altogether, even from the Guile/Scheme and Python 
interface modules, which should hopefully reduce any confusion that may 
remain.  This has actually made arrangements for extra literals more 
straightforward in the interface modules and while I have not implemented 
Scheme or Python syntax for defining new settings with arbitrary extra 
literals, it should now be pretty straightforward for anyone fluent in 
these languages.  And it made another pair of places where `var_pinteger' 
is referred from.

> > Index: src/gdb/cli/cli-option.h
> > ===================================================================
> > --- src.orig/gdb/cli/cli-option.h
> > +++ src/gdb/cli/cli-option.h
[...]
> > @@ -207,11 +211,12 @@ struct uinteger_option_def : option_def
> >  {
> >    uinteger_option_def (const char *long_option_,
> >  		       unsigned int *(*get_var_address_cb_) (Context *),
> > +		       const literal_def *extra_literals_,
> >  		       show_value_ftype *show_cmd_cb_,
> >  		       const char *set_doc_,
> >  		       const char *show_doc_ = nullptr,
> >  		       const char *help_doc_ = nullptr)
> > -    : option_def (long_option_, var_uinteger,
> > +    : option_def (long_option_, var_uinteger, extra_literals_,
> >  		  (erased_get_var_address_ftype *) get_var_address_cb_,
> >  		  show_cmd_cb_,
> >  		  set_doc_, show_doc_, help_doc_)
> 
> I think we should add a second constructor for uinteger_option_def like
> this:
> 
>   uinteger_option_def (const char *long_option_,
>                       unsigned int *(*get_var_address_cb_) (Context *),
>                       show_value_ftype *show_cmd_cb_,
>                       const char *set_doc_,
>                       const char *show_doc_ = nullptr,
>                       const char *help_doc_ = nullptr)
>     : uinteger_option_def (long_option_, get_var_address_cb_,
>                           uinteger_unlimited_literals, show_cmd_cb_,
>                           set_doc_, show_doc_, help_doc_)
>   { /* Nothing.  */ }
> 
> This would keep the existing '0 == unlimited' as the default behaviour,
> but still give the option of overriding the literals if needed.

 I think this would be going against the spirit of my change though where 
`uinteger' is just a plain unsigned integer with no extra semantic 
features implied, which is what any software engineer not familiar with 
GDB's convoluted history would assume.  Myself I have had to double-check 
the description of `var_types' enumeration constants every time while 
working on this change so as not to get the meanings confused.

 With your proposed update one would have to pass `nullptr' explicitly as 
`extra_literals' to get a plain unsigned integer setting and I find it 
backwards.  I find it more natural for a missing initialiser to mean 
`nullptr' and I have added suitable extra constructors now.

 NB eventually we'll need an `integer_option_def' class here as well, but 
I'm leaving it out until there's a user for it; I could perhaps convert 
say gdb/source.c for demonstrational purposes, but I'm not that inclined.

> > @@ -220,18 +225,19 @@ struct uinteger_option_def : option_def
> >    }
> >  };
> >  
> > -/* A var_zuinteger_unlimited command line option.  */
> > +/* A var_integer command line option.  */
> >  
> >  template<typename Context>
> > -struct zuinteger_unlimited_option_def : option_def
> 
> If instead of deleting zuinteger_unlimited_option_def we redefined the
> class like this:
> 
>   /* A var_zuinteger_unlimited command line option.  */
>   
>   template<typename Context>
>   struct zuinteger_unlimited_option_def : integer_option_def<Context>
>   {
>     zuinteger_unlimited_option_def (const char *long_option_,
>                                    int *(*get_var_address_cb_) (Context *),
>                                    show_value_ftype *show_cmd_cb_,
>                                    const char *set_doc_,
>                                    const char *show_doc_ = nullptr,
>                                    const char *help_doc_ = nullptr)
>       : integer_option_def<Context> (long_option_, get_var_address_cb_,
>                                     zuinteger_unlimited_literals, show_cmd_cb_,
>                                     set_doc_, show_doc_, help_doc_)
>     { /* Nothing.  */ }
>   };
> 
> We could then still make use of zuinteger_unlimited_option_def if we
> wanted, which would be an integer with zuinteger_unlimited_literals.

 Like above, I'd prefer to get rid of the convoluted name (and this needs 
to be called `pinteger_option_def'; so much for my confusion avoidance).

 Also the more I think about it the more I am convinced all the three 
variables holding the "unlimited" extra literal simply ought to match the 
name of the corresponding `var_types' enumeration constant, so 
`pinteger_unlimited_literals' here and elsewhere.

 Ultimately we'll need `integer_option_def' too, but there's no user 
currently (settings of the `var_integer' type are only created via the 
legacy `add_setshow_integer_cmd' function, which I think should eventually 
go away).

> > Index: src/gdb/cli/cli-setshow.c
> > ===================================================================
> > --- src.orig/gdb/cli/cli-setshow.c
> > +++ src/gdb/cli/cli-setshow.c
[...]
> >  /* See cli-setshow.h.  */
> >  
> > -unsigned int
> > -parse_cli_var_uinteger (var_types var_type, const char **arg,
> > -			bool expression)
> > +LONGEST
> > +parse_cli_var_integer (var_types var_type, const literal_def *extra_literals,
> > +		       const char **arg, bool expression)
> >  {
> >    LONGEST val;
> >  
> >    if (*arg == nullptr || **arg == '\0')
> >      {
> > -      if (var_type == var_uinteger)
> > -	error_no_arg (_("integer to set it to, or \"unlimited\""));
> > -      else
> > +      if (extra_literals == nullptr)
> >  	error_no_arg (_("integer to set it to"));
> > -    }
> > -
> > -  if (var_type == var_uinteger && is_unlimited_literal (arg, expression))
> > -    val = 0;
> > -  else if (expression)
> > -    val = parse_and_eval_long (*arg);
> > -  else
> > -    val = get_ulongest (arg);
> > -
> > -  if (var_type == var_uinteger && val == 0)
> > -    val = UINT_MAX;
> > -  else if (val < 0
> > -	   /* For var_uinteger, don't let the user set the value
> > -	      to UINT_MAX directly, as that exposes an
> > -	      implementation detail to the user interface.  */
> > -	   || (var_type == var_uinteger && val >= UINT_MAX)
> > -	   || (var_type == var_zuinteger && val > UINT_MAX))
> > -    error (_("integer %s out of range"), plongest (val));
> > -
> > -  return val;
> > -}
> > -
> > -/* See cli-setshow.h.  */
> > +      else
> > +	{
> > +	  std::string buffer = "";
> > +	  size_t count = 0;
> >  
> > -int
> > -parse_cli_var_zuinteger_unlimited (const char **arg, bool expression)
> > -{
> > -  LONGEST val;
> > +	  for (const literal_def *l = extra_literals;
> > +	       l->literal != nullptr;
> > +	       l++, count++)
> > +	    {
> > +	      if (count != 0)
> > +		buffer += ", ";
> > +	      buffer = buffer + '"' + l->literal + '"';
> > +	    }
> > +	  if (count > 1)
> > +	    error_no_arg
> > +	      (string_printf (_("integer to set it to, or one of: %s"),
> > +			      buffer.c_str ()).c_str ());
> > +	  else
> > +	    error_no_arg
> > +	      (string_printf (_("integer to set it to, or %s"),
> > +			      buffer.c_str ()).c_str ());
> > +	}
> > +    }
> >  
> > -  if (*arg == nullptr || **arg == '\0')
> > -    error_no_arg (_("integer to set it to, or \"unlimited\""));
> > +  if (!get_literal_val (val, extra_literals, arg, expression))
> > +    {
> > +      if (expression)
> > +	val = parse_and_eval_long (*arg);
> > +      else
> > +	val = get_ulongest (arg);
> >  
> > -  if (is_unlimited_literal (arg, expression))
> > -    val = -1;
> > -  else if (expression)
> > -    val = parse_and_eval_long (*arg);
> > -  else
> > -    val = get_ulongest (arg);
> > +      enum tribool allowed = TRIBOOL_UNKNOWN;
> > +      if (extra_literals != nullptr)
> > +	{
> > +	  for (const literal_def *l = extra_literals;
> > +	       l->literal != nullptr;
> > +	       l++)
> > +	    if (val == l->val)
> > +	      {
> > +		allowed = l->allow ? TRIBOOL_TRUE : TRIBOOL_FALSE;
> > +		val = l->use;
> > +		break;
> > +	      }
> > +	    else if (val == l->use)
> > +	      {
> > +		allowed = TRIBOOL_FALSE;
> > +		break;
> > +	      }
> > +	}
> 
> I haven't run the testsuite on this, so maybe there's issues, but I'd
> like to propose that this loop be rewritten as:
> 
>       if (extra_literals != nullptr)
> 	{
> 	  for (const literal_def *l = extra_literals;
> 	       l->literal != nullptr;
> 	       l++)
> 	    if (val == l->val && l->allow)
> 	      {
> 		allowed = TRIBOOL_TRUE;
> 		val = l->use;
> 		break;
> 	      }
> 	    else if (val == l->use)
> 	      allowed = TRIBOOL_FALSE;
> 	}

 This has a problem where `l->val' is not allowed with one entry and it 
doesn't match any other.  In that case execution will fall through to 
TRIBOOL_UNKNOWN below and the value will be incorrectly accepted as long 
as within the range of the requested `var_type'.

> The 'if (val == l->val && l->allow)' would be improved if l->val was
> changed to an optional.

 I like this idea (mind that I'm a C old-timer really and I haven't still 
soaked with all the C++ features we have at hand) and I have updated code 
accordingly.

>  The change to the 'val == l->use' block allows
> I think another improvement, this:
> 
>   static const literal_def print_characters_literals[] =
>     {
>       { "elements", 0, 0, false },
>       { "unlimited", 0, UINT_MAX, true },
>       { nullptr }
>     };
> 
> The change here is that:
> 
>   set print characters 0
> 
> now behaves the same as:
> 
>   set print elements 0
> 
> In both cases, this sets the value to "unlimited".  I like the
> consistency.

 You needn't change the loop to achieve this effect, you can just swap the 
entries in the array or use UINT_MAX as `val' for "elements".  And with 
optional `l->val' you would actually still have to swap the entries as 
`l->use' would match against 0 first and reject it.

 The idea with my change was not to expose the internal value for new 
additions.  I guess I'm not that attached to it, so if you think such 
consistency matters (mind that we have different numeric values for 
"unlimited" across various settings anyway), then I can allow 0 here.

> > Index: src/gdb/command.h
> > ===================================================================
> > --- src.orig/gdb/command.h
> > +++ src/gdb/command.h
[...]
> > @@ -123,6 +126,22 @@ typedef enum var_types
> >    }
> >  var_types;
> >  
> > +/* A structure describing an extra literal accepted and shown in place
> > +   of a number.  */
> > +typedef struct literal_defs
> 
> You don't need the typedef trick as this is C++.

 We still have them in several places though.  I have now removed it from 
my change.

> > +  {
> > +    /* The literal to define, e.g. "unlimited".  */
> > +    const char *literal;
> > +    /* A number optionally accepted that stands for the literal.  */
> > +    LONGEST val;
> > +    /* The number to substitute internally for LITERAL or VAL;
> > +       the use of this number is not allowed (unless the same as VAL).  */
> > +    LONGEST use;
> > +    /* True if the use of VAL is allowed; otherwise only the literal is.  */
> > +    bool allow;
> 
> Could we replace VAL and ALLOW with something like:
> 
>   gdb::optional<LONGEST> ....

 Done now.

> 
> > +  }
> > +literal_def;
> > +
> >  /* Return true if a setting of type VAR_TYPE is backed with type T.
> >  
> >     This function is left without definition intentionally.  This template is
> > @@ -153,15 +172,14 @@ inline bool var_type_uses<enum auto_bool
> >  template<>
> >  inline bool var_type_uses<unsigned int> (var_types t)
> >  {
> > -  return (t == var_uinteger || t == var_zinteger || t == var_zuinteger);
> > +  return t == var_uinteger;
> >  }
> 
> Should we really remove all these uses of var_zinteger, etc?  The enum
> values are still around, right?  So surely if you passed in that enum
> field the true/false response shouldn't change...

 Not relevant anymore since I have removed `var_zinteger', etc. altogether 
as the attempt to leave them for Guile/Python was clearly hardly less if 
not more confusing than the original arrangement.

 Thank you for your review, I'll be posting v6 shortly.  While making this 
update I have discovered a few further issues, so we're back at 8 patches.

  Maciej

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2022-08-17 22:03 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-30 10:23 [PATCH v5 0/8] gdb: split array and string limiting options Maciej W. Rozycki
2022-03-30 10:23 ` [PATCH v5 1/8] GDB: Remove extraneous full stops from `set' command error messages Maciej W. Rozycki
2022-06-24 14:32   ` Andrew Burgess
2022-06-29 14:29     ` Maciej W. Rozycki
2022-03-30 10:23 ` [PATCH v5 2/8] GDB/Python: Use None for `var_zuinteger_unlimited' value set to `unlimited' Maciej W. Rozycki
2022-03-30 10:35   ` Simon Sobisch
2022-03-30 10:40     ` Maciej W. Rozycki
2022-03-30 10:50       ` Simon Sobisch
2022-03-30 11:52         ` Maciej W. Rozycki
2022-06-24 14:40   ` Andrew Burgess
2022-06-29 16:48     ` Maciej W. Rozycki
2022-03-30 10:24 ` [PATCH v5 3/8] GDB: Add `NUMBER' completion to `set' integer commands Maciej W. Rozycki
2022-05-25 18:36   ` Bruno Larsen
2022-05-26 10:09     ` Maciej W. Rozycki
2022-05-26 11:46       ` Bruno Larsen
2022-05-26 14:24         ` Maciej W. Rozycki
2022-06-24 15:08   ` Andrew Burgess
2022-06-30 14:24     ` [PATCH v6 " Maciej W. Rozycki
2022-06-30 15:53       ` Eli Zaretskii
2022-06-30 18:59         ` Maciej W. Rozycki
2022-06-30 16:01       ` Andrew Burgess
2022-03-30 10:24 ` [PATCH v5 4/8] GDB/testsuite: Tighten `set print elements' error check Maciej W. Rozycki
2022-06-24 15:09   ` Andrew Burgess
2022-06-29 14:29     ` Maciej W. Rozycki
2022-03-30 10:24 ` [PATCH v5 5/8] GDB/testsuite: Add coverage for `print -elements' command Maciej W. Rozycki
2022-06-24 15:57   ` Andrew Burgess
2022-07-07 11:04     ` Maciej W. Rozycki
2022-03-30 10:24 ` [PATCH v5 6/8] GDB: Allow arbitrary keywords in integer set commands Maciej W. Rozycki
2022-03-30 10:42   ` Simon Sobisch
2022-03-30 10:58     ` Maciej W. Rozycki
2022-06-28 14:04   ` Andrew Burgess
2022-08-17 22:03     ` Maciej W. Rozycki
2022-03-30 10:24 ` [PATCH v5 7/8] GDB: Add a character string limiting option Maciej W. Rozycki
2022-03-30 12:29   ` Eli Zaretskii
2022-03-30 10:24 ` [PATCH v5 8/8] GDB/testsuite: Expand for character string limiting options Maciej W. Rozycki
2022-04-13 11:20 ` [PING][PATCH v5 0/8] gdb: split array and " Maciej W. Rozycki
2022-04-13 12:10   ` Simon Sobisch
2022-04-13 12:18     ` Maciej W. Rozycki
2022-04-20 19:17 ` [PING^2][PATCH " Maciej W. Rozycki
2022-04-26 19:57   ` Simon Sobisch
2022-04-27 12:00     ` Maciej W. Rozycki
2022-04-27 12:02 ` [PING^3][PATCH " Maciej W. Rozycki
2022-05-04 10:05 ` [PING^4][PATCH " Maciej W. Rozycki
2022-05-12 21:20 ` [PING^5][PATCH " Maciej W. Rozycki
2022-05-20 10:49 ` [PING^6][PATCH " Maciej W. Rozycki
2022-05-25 15:52 ` [PING^7][PATCH " Maciej W. Rozycki
2022-05-25 19:20 ` [PATCH " Bruno Larsen
2022-06-02 17:55 ` [PING^8][PATCH " Maciej W. Rozycki
2022-06-07 17:23   ` Simon Sobisch
2022-06-15 22:47 ` [PING^9][PATCH " Maciej W. Rozycki
2022-06-22 11:25 ` [PING^10][PATCH " Maciej W. Rozycki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).