* ada-lang.c (ada_make_symbol_completion_list): Add 'code'
argument, assertion. * c-exp.y (typebase): Add completion productions. * completer.c (expression_completer): Handle tag completion. * expression.h (parse_expression_for_completion): Add argument. * f-lang.c (f_make_symbol_completion_list): Add 'code' argument. * language.h (struct language_defn) <la_make_symbol_completion_list>: Add 'code' argument. * parse.c (expout_tag_completion_type, expout_completion_name): New globals. (mark_struct_expression): Add assertion. (mark_completion_tag): New function. (parse_exp_in_context): Initialize new globals. (parse_expression_for_completion): Add 'code' argument. Handle tag completion. * parser-defs.h (mark_completion_tag): Declare. * symtab.c (default_make_symbol_completion_list_break_on): Add 'code' argument. Update. (default_make_symbol_completion_list): Add 'code' argument. (make_symbol_completion_list): Update. (make_symbol_completion_type): New function. * symtab.h (default_make_symbol_completion_list_break_on) (default_make_symbol_completion_list): Update. (make_symbol_completion_type): Declare. testsuite * gdb.base/break1.c (enum some_enum, union some_union): New. (some_enum_global, some_union_global, some_value): New globals. * gdb.base/completion.exp: Add tag completion tests.
This commit is contained in:
parent
155da5173d
commit
2f68a89553
@ -1,3 +1,31 @@
|
||||
2012-12-07 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* ada-lang.c (ada_make_symbol_completion_list): Add 'code'
|
||||
argument, assertion.
|
||||
* c-exp.y (typebase): Add completion productions.
|
||||
* completer.c (expression_completer): Handle tag completion.
|
||||
* expression.h (parse_expression_for_completion): Add argument.
|
||||
* f-lang.c (f_make_symbol_completion_list): Add 'code'
|
||||
argument.
|
||||
* language.h (struct language_defn)
|
||||
<la_make_symbol_completion_list>: Add 'code' argument.
|
||||
* parse.c (expout_tag_completion_type, expout_completion_name):
|
||||
New globals.
|
||||
(mark_struct_expression): Add assertion.
|
||||
(mark_completion_tag): New function.
|
||||
(parse_exp_in_context): Initialize new globals.
|
||||
(parse_expression_for_completion): Add 'code' argument. Handle
|
||||
tag completion.
|
||||
* parser-defs.h (mark_completion_tag): Declare.
|
||||
* symtab.c (default_make_symbol_completion_list_break_on): Add
|
||||
'code' argument. Update.
|
||||
(default_make_symbol_completion_list): Add 'code' argument.
|
||||
(make_symbol_completion_list): Update.
|
||||
(make_symbol_completion_type): New function.
|
||||
* symtab.h (default_make_symbol_completion_list_break_on)
|
||||
(default_make_symbol_completion_list): Update.
|
||||
(make_symbol_completion_type): Declare.
|
||||
|
||||
2012-12-07 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* expression.h (parse_expression_for_completion): Rename
|
||||
|
@ -5802,7 +5802,7 @@ ada_expand_partial_symbol_name (const char *name, void *user_data)
|
||||
the entire command on which completion is made. */
|
||||
|
||||
static VEC (char_ptr) *
|
||||
ada_make_symbol_completion_list (char *text0, char *word)
|
||||
ada_make_symbol_completion_list (char *text0, char *word, enum type_code code)
|
||||
{
|
||||
char *text;
|
||||
int text_len;
|
||||
@ -5817,6 +5817,8 @@ ada_make_symbol_completion_list (char *text0, char *word)
|
||||
int i;
|
||||
struct block_iterator iter;
|
||||
|
||||
gdb_assert (code == TYPE_CODE_UNDEF);
|
||||
|
||||
if (text0[0] == '<')
|
||||
{
|
||||
text = xstrdup (text0);
|
||||
|
44
gdb/c-exp.y
44
gdb/c-exp.y
@ -1268,15 +1268,59 @@ typebase /* Implements (approximately): (type-qualifier)* type-specifier */
|
||||
| STRUCT name
|
||||
{ $$ = lookup_struct (copy_name ($2),
|
||||
expression_context_block); }
|
||||
| STRUCT COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_STRUCT, "", 0);
|
||||
$$ = NULL;
|
||||
}
|
||||
| STRUCT name COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_STRUCT, $2.ptr,
|
||||
$2.length);
|
||||
$$ = NULL;
|
||||
}
|
||||
| CLASS name
|
||||
{ $$ = lookup_struct (copy_name ($2),
|
||||
expression_context_block); }
|
||||
| CLASS COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_CLASS, "", 0);
|
||||
$$ = NULL;
|
||||
}
|
||||
| CLASS name COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_CLASS, $2.ptr,
|
||||
$2.length);
|
||||
$$ = NULL;
|
||||
}
|
||||
| UNION name
|
||||
{ $$ = lookup_union (copy_name ($2),
|
||||
expression_context_block); }
|
||||
| UNION COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_UNION, "", 0);
|
||||
$$ = NULL;
|
||||
}
|
||||
| UNION name COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_UNION, $2.ptr,
|
||||
$2.length);
|
||||
$$ = NULL;
|
||||
}
|
||||
| ENUM name
|
||||
{ $$ = lookup_enum (copy_name ($2),
|
||||
expression_context_block); }
|
||||
| ENUM COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_ENUM, "", 0);
|
||||
$$ = NULL;
|
||||
}
|
||||
| ENUM name COMPLETE
|
||||
{
|
||||
mark_completion_tag (TYPE_CODE_ENUM, $2.ptr,
|
||||
$2.length);
|
||||
$$ = NULL;
|
||||
}
|
||||
| UNSIGNED typename
|
||||
{ $$ = lookup_unsigned_typename (parse_language,
|
||||
parse_gdbarch,
|
||||
|
@ -390,13 +390,14 @@ expression_completer (struct cmd_list_element *ignore,
|
||||
struct type *type = NULL;
|
||||
char *fieldname, *p;
|
||||
volatile struct gdb_exception except;
|
||||
enum type_code code = TYPE_CODE_UNDEF;
|
||||
|
||||
/* Perform a tentative parse of the expression, to see whether a
|
||||
field completion is required. */
|
||||
fieldname = NULL;
|
||||
TRY_CATCH (except, RETURN_MASK_ERROR)
|
||||
{
|
||||
type = parse_expression_for_completion (text, &fieldname);
|
||||
type = parse_expression_for_completion (text, &fieldname, &code);
|
||||
}
|
||||
if (except.reason < 0)
|
||||
return NULL;
|
||||
@ -422,6 +423,15 @@ expression_completer (struct cmd_list_element *ignore,
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (fieldname && code != TYPE_CODE_UNDEF)
|
||||
{
|
||||
VEC (char_ptr) *result;
|
||||
struct cleanup *cleanup = make_cleanup (xfree, fieldname);
|
||||
|
||||
result = make_symbol_completion_type (fieldname, fieldname, code);
|
||||
do_cleanups (cleanup);
|
||||
return result;
|
||||
}
|
||||
xfree (fieldname);
|
||||
|
||||
/* Commands which complete on locations want to see the entire
|
||||
|
@ -98,7 +98,8 @@ struct expression
|
||||
|
||||
extern struct expression *parse_expression (char *);
|
||||
|
||||
extern struct type *parse_expression_for_completion (char *, char **);
|
||||
extern struct type *parse_expression_for_completion (char *, char **,
|
||||
enum type_code *);
|
||||
|
||||
extern struct expression *parse_exp_1 (char **, CORE_ADDR pc,
|
||||
const struct block *, int);
|
||||
|
@ -230,9 +230,9 @@ f_word_break_characters (void)
|
||||
class. */
|
||||
|
||||
static VEC (char_ptr) *
|
||||
f_make_symbol_completion_list (char *text, char *word)
|
||||
f_make_symbol_completion_list (char *text, char *word, enum type_code code)
|
||||
{
|
||||
return default_make_symbol_completion_list_break_on (text, word, ":");
|
||||
return default_make_symbol_completion_list_break_on (text, word, ":", code);
|
||||
}
|
||||
|
||||
const struct language_defn f_language_defn =
|
||||
|
@ -284,8 +284,11 @@ struct language_defn
|
||||
|
||||
/* Should return a vector of all symbols which are possible
|
||||
completions for TEXT. WORD is the entire command on which the
|
||||
completion is being made. */
|
||||
VEC (char_ptr) *(*la_make_symbol_completion_list) (char *text, char *word);
|
||||
completion is being made. If CODE is TYPE_CODE_UNDEF, then all
|
||||
symbols should be examined; otherwise, only STRUCT_DOMAIN
|
||||
symbols whose type has a code of CODE should be matched. */
|
||||
VEC (char_ptr) *(*la_make_symbol_completion_list) (char *text, char *word,
|
||||
enum type_code code);
|
||||
|
||||
/* The per-architecture (OS/ABI) language information. */
|
||||
void (*la_language_arch_info) (struct gdbarch *,
|
||||
|
45
gdb/parse.c
45
gdb/parse.c
@ -88,6 +88,13 @@ int parse_completion;
|
||||
'->'. This is set when parsing and is only used when completing a
|
||||
field name. It is -1 if no dereference operation was found. */
|
||||
static int expout_last_struct = -1;
|
||||
|
||||
/* If we are completing a tagged type name, this will be nonzero. */
|
||||
static enum type_code expout_tag_completion_type = TYPE_CODE_UNDEF;
|
||||
|
||||
/* The token for tagged type name completion. */
|
||||
static char *expout_completion_name;
|
||||
|
||||
|
||||
static unsigned int expressiondebug = 0;
|
||||
static void
|
||||
@ -578,9 +585,32 @@ write_exp_msymbol (struct minimal_symbol *msymbol)
|
||||
void
|
||||
mark_struct_expression (void)
|
||||
{
|
||||
gdb_assert (parse_completion
|
||||
&& expout_tag_completion_type == TYPE_CODE_UNDEF);
|
||||
expout_last_struct = expout_ptr;
|
||||
}
|
||||
|
||||
/* Indicate that the current parser invocation is completing a tag.
|
||||
TAG is the type code of the tag, and PTR and LENGTH represent the
|
||||
start of the tag name. */
|
||||
|
||||
void
|
||||
mark_completion_tag (enum type_code tag, const char *ptr, int length)
|
||||
{
|
||||
gdb_assert (parse_completion
|
||||
&& expout_tag_completion_type == TYPE_CODE_UNDEF
|
||||
&& expout_completion_name == NULL
|
||||
&& expout_last_struct == -1);
|
||||
gdb_assert (tag == TYPE_CODE_UNION
|
||||
|| tag == TYPE_CODE_STRUCT
|
||||
|| tag == TYPE_CODE_CLASS
|
||||
|| tag == TYPE_CODE_ENUM);
|
||||
expout_tag_completion_type = tag;
|
||||
expout_completion_name = xmalloc (length + 1);
|
||||
memcpy (expout_completion_name, ptr, length);
|
||||
expout_completion_name[length] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Recognize tokens that start with '$'. These include:
|
||||
|
||||
@ -1124,6 +1154,9 @@ parse_exp_in_context (char **stringptr, CORE_ADDR pc, const struct block *block,
|
||||
paren_depth = 0;
|
||||
type_stack.depth = 0;
|
||||
expout_last_struct = -1;
|
||||
expout_tag_completion_type = TYPE_CODE_UNDEF;
|
||||
xfree (expout_completion_name);
|
||||
expout_completion_name = NULL;
|
||||
|
||||
comma_terminates = comma;
|
||||
|
||||
@ -1244,7 +1277,8 @@ parse_expression (char *string)
|
||||
*NAME must be freed by the caller. */
|
||||
|
||||
struct type *
|
||||
parse_expression_for_completion (char *string, char **name)
|
||||
parse_expression_for_completion (char *string, char **name,
|
||||
enum type_code *code)
|
||||
{
|
||||
struct expression *exp = NULL;
|
||||
struct value *val;
|
||||
@ -1259,6 +1293,15 @@ parse_expression_for_completion (char *string, char **name)
|
||||
parse_completion = 0;
|
||||
if (except.reason < 0 || ! exp)
|
||||
return NULL;
|
||||
|
||||
if (expout_tag_completion_type != TYPE_CODE_UNDEF)
|
||||
{
|
||||
*code = expout_tag_completion_type;
|
||||
*name = expout_completion_name;
|
||||
expout_completion_name = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (expout_last_struct == -1)
|
||||
{
|
||||
xfree (exp);
|
||||
|
@ -372,4 +372,8 @@ extern void parser_fprintf (FILE *, const char *, ...) ATTRIBUTE_PRINTF (2, 3);
|
||||
|
||||
extern int exp_uses_objfile (struct expression *exp, struct objfile *objfile);
|
||||
|
||||
extern void mark_completion_tag (enum type_code, const char *ptr,
|
||||
int length);
|
||||
|
||||
#endif /* PARSER_DEFS_H */
|
||||
|
||||
|
86
gdb/symtab.c
86
gdb/symtab.c
@ -4202,7 +4202,8 @@ expand_partial_symbol_name (const char *name, void *user_data)
|
||||
|
||||
VEC (char_ptr) *
|
||||
default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
const char *break_on)
|
||||
const char *break_on,
|
||||
enum type_code code)
|
||||
{
|
||||
/* Problem: All of the symbols have to be copied because readline
|
||||
frees them. I'm not going to worry about this; hopefully there
|
||||
@ -4309,13 +4310,18 @@ default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
anything that isn't a text symbol (everything else will be
|
||||
handled by the psymtab code above). */
|
||||
|
||||
ALL_MSYMBOLS (objfile, msymbol)
|
||||
{
|
||||
QUIT;
|
||||
COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text, word);
|
||||
if (code == TYPE_CODE_UNDEF)
|
||||
{
|
||||
ALL_MSYMBOLS (objfile, msymbol)
|
||||
{
|
||||
QUIT;
|
||||
COMPLETION_LIST_ADD_SYMBOL (msymbol, sym_text, sym_text_len, text,
|
||||
word);
|
||||
|
||||
completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text, word);
|
||||
}
|
||||
completion_list_objc_symbol (msymbol, sym_text, sym_text_len, text,
|
||||
word);
|
||||
}
|
||||
}
|
||||
|
||||
/* Search upwards from currently selected frame (so that we can
|
||||
complete on local vars). Also catch fields of types defined in
|
||||
@ -4332,10 +4338,17 @@ default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
|
||||
ALL_BLOCK_SYMBOLS (b, iter, sym)
|
||||
{
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
|
||||
word);
|
||||
completion_list_add_fields (sym, sym_text, sym_text_len, text,
|
||||
word);
|
||||
if (code == TYPE_CODE_UNDEF)
|
||||
{
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
|
||||
word);
|
||||
completion_list_add_fields (sym, sym_text, sym_text_len, text,
|
||||
word);
|
||||
}
|
||||
else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
|
||||
&& TYPE_CODE (SYMBOL_TYPE (sym)) == code)
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text,
|
||||
word);
|
||||
}
|
||||
|
||||
/* Stop when we encounter an enclosing function. Do not stop for
|
||||
@ -4348,13 +4361,16 @@ default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
|
||||
/* Add fields from the file's types; symbols will be added below. */
|
||||
|
||||
if (surrounding_static_block != NULL)
|
||||
ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
|
||||
completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
|
||||
if (code == TYPE_CODE_UNDEF)
|
||||
{
|
||||
if (surrounding_static_block != NULL)
|
||||
ALL_BLOCK_SYMBOLS (surrounding_static_block, iter, sym)
|
||||
completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
|
||||
|
||||
if (surrounding_global_block != NULL)
|
||||
ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
|
||||
completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
|
||||
if (surrounding_global_block != NULL)
|
||||
ALL_BLOCK_SYMBOLS (surrounding_global_block, iter, sym)
|
||||
completion_list_add_fields (sym, sym_text, sym_text_len, text, word);
|
||||
}
|
||||
|
||||
/* Go through the symtabs and check the externs and statics for
|
||||
symbols which match. */
|
||||
@ -4365,7 +4381,10 @@ default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
|
||||
ALL_BLOCK_SYMBOLS (b, iter, sym)
|
||||
{
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
|
||||
if (code == TYPE_CODE_UNDEF
|
||||
|| (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
|
||||
&& TYPE_CODE (SYMBOL_TYPE (sym)) == code))
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4375,11 +4394,17 @@ default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
|
||||
ALL_BLOCK_SYMBOLS (b, iter, sym)
|
||||
{
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
|
||||
if (code == TYPE_CODE_UNDEF
|
||||
|| (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
|
||||
&& TYPE_CODE (SYMBOL_TYPE (sym)) == code))
|
||||
COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_language->la_macro_expansion == macro_expansion_c)
|
||||
/* Skip macros if we are completing a struct tag -- arguable but
|
||||
usually what is expected. */
|
||||
if (current_language->la_macro_expansion == macro_expansion_c
|
||||
&& code == TYPE_CODE_UNDEF)
|
||||
{
|
||||
struct macro_scope *scope;
|
||||
|
||||
@ -4407,9 +4432,10 @@ default_make_symbol_completion_list_break_on (char *text, char *word,
|
||||
}
|
||||
|
||||
VEC (char_ptr) *
|
||||
default_make_symbol_completion_list (char *text, char *word)
|
||||
default_make_symbol_completion_list (char *text, char *word,
|
||||
enum type_code code)
|
||||
{
|
||||
return default_make_symbol_completion_list_break_on (text, word, "");
|
||||
return default_make_symbol_completion_list_break_on (text, word, "", code);
|
||||
}
|
||||
|
||||
/* Return a vector of all symbols (regardless of class) which begin by
|
||||
@ -4419,7 +4445,21 @@ default_make_symbol_completion_list (char *text, char *word)
|
||||
VEC (char_ptr) *
|
||||
make_symbol_completion_list (char *text, char *word)
|
||||
{
|
||||
return current_language->la_make_symbol_completion_list (text, word);
|
||||
return current_language->la_make_symbol_completion_list (text, word,
|
||||
TYPE_CODE_UNDEF);
|
||||
}
|
||||
|
||||
/* Like make_symbol_completion_list, but only return STRUCT_DOMAIN
|
||||
symbols whose type code is CODE. */
|
||||
|
||||
VEC (char_ptr) *
|
||||
make_symbol_completion_type (char *text, char *word, enum type_code code)
|
||||
{
|
||||
gdb_assert (code == TYPE_CODE_UNION
|
||||
|| code == TYPE_CODE_STRUCT
|
||||
|| code == TYPE_CODE_CLASS
|
||||
|| code == TYPE_CODE_ENUM);
|
||||
return current_language->la_make_symbol_completion_list (text, word, code);
|
||||
}
|
||||
|
||||
/* Like make_symbol_completion_list, but suitable for use as a
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "vec.h"
|
||||
#include "gdb_vecs.h"
|
||||
#include "gdbtypes.h"
|
||||
|
||||
/* Opaque declarations. */
|
||||
struct ui_file;
|
||||
@ -1182,9 +1183,13 @@ extern void forget_cached_source_info (void);
|
||||
extern void select_source_symtab (struct symtab *);
|
||||
|
||||
extern VEC (char_ptr) *default_make_symbol_completion_list_break_on
|
||||
(char *text, char *word, const char *break_on);
|
||||
extern VEC (char_ptr) *default_make_symbol_completion_list (char *, char *);
|
||||
(char *text, char *word, const char *break_on,
|
||||
enum type_code code);
|
||||
extern VEC (char_ptr) *default_make_symbol_completion_list (char *, char *,
|
||||
enum type_code);
|
||||
extern VEC (char_ptr) *make_symbol_completion_list (char *, char *);
|
||||
extern VEC (char_ptr) *make_symbol_completion_type (char *, char *,
|
||||
enum type_code);
|
||||
extern VEC (char_ptr) *make_symbol_completion_list_fn (struct cmd_list_element *,
|
||||
char *, char *);
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
2012-12-07 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.base/break1.c (enum some_enum, union some_union): New.
|
||||
(some_enum_global, some_union_global, some_value): New globals.
|
||||
* gdb.base/completion.exp: Add tag completion tests.
|
||||
|
||||
2012-12-07 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.base/completion.exp: Add tests for ptype and whatis
|
||||
|
@ -29,6 +29,23 @@ struct some_struct
|
||||
|
||||
struct some_struct values[50];
|
||||
|
||||
/* Some definitions for tag completion. */
|
||||
enum some_enum { VALUE };
|
||||
|
||||
enum some_enum some_enum_global;
|
||||
|
||||
union some_union
|
||||
{
|
||||
int f1;
|
||||
double f2;
|
||||
};
|
||||
|
||||
union some_union some_union_global;
|
||||
|
||||
/* A variable with a name "similar" to the above struct, to test that
|
||||
tag completion works ok. */
|
||||
int some_variable;
|
||||
|
||||
/* The following functions do nothing useful. They are included
|
||||
simply as places to try setting breakpoints at. They are
|
||||
explicitly "one-line functions" to verify that this case works
|
||||
|
@ -700,6 +700,14 @@ gdb_test "complete sav" "save" "test non-deprecated completion"
|
||||
gdb_test "complete save-t" "save-tracepoints" "test deprecated completion"
|
||||
|
||||
|
||||
#
|
||||
# Tag name completion.
|
||||
#
|
||||
|
||||
gdb_test "complete ptype struct some_" "ptype struct some_struct"
|
||||
gdb_test "complete ptype enum some_" "ptype enum some_enum"
|
||||
gdb_test "complete ptype union some_" "ptype union some_union"
|
||||
|
||||
# Restore globals modified in this test...
|
||||
set timeout $oldtimeout1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user