Blame command.y

Packit Service f629e6
/*
Packit Service f629e6
 * command.y - yacc/bison parser for debugger commands.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 2004, 2010, 2011, 2014, 2016, 2017
Packit Service f629e6
 * the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335,
Packit Service f629e6
 * USA 
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
%{
Packit Service f629e6
#include "awk.h"
Packit Service f629e6
#include "cmd.h"
Packit Service f629e6
Packit Service f629e6
#if 0
Packit Service f629e6
#define YYDEBUG 12
Packit Service f629e6
int yydebug = 2;
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
static int yylex(void);
Packit Service f629e6
static void yyerror(const char *mesg, ...);
Packit Service f629e6
Packit Service f629e6
static int find_command(const char *token, size_t toklen);
Packit Service f629e6
Packit Service f629e6
static bool want_nodeval = false;
Packit Service f629e6
Packit Service f629e6
static int cmd_idx = -1;		/* index of current command in cmd table */
Packit Service f629e6
static int repeat_idx = -1;		/* index of last repeatable command in command table */
Packit Service f629e6
static CMDARG *arg_list = NULL;		/* list of arguments */
Packit Service f629e6
static long errcount = 0;
Packit Service f629e6
static char *lexptr_begin = NULL;
Packit Service f629e6
static bool in_commands = false;
Packit Service f629e6
static int num_dim;
Packit Service f629e6
Packit Service f629e6
static bool in_eval = false;
Packit Service f629e6
static const char start_EVAL[] = "function @eval(){";
Packit Service f629e6
static const char end_EVAL[] = "}";
Packit Service f629e6
static CMDARG *append_statement(CMDARG *stmt_list, char *stmt);
Packit Service f629e6
static NODE *concat_args(CMDARG *a, int count);
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_LIBREADLINE
Packit Service f629e6
static char *next_word(char *p, int len, char **endp);
Packit Service f629e6
static void history_expand_line(char **line);
Packit Service f629e6
static char *command_generator(const char *text, int state);
Packit Service f629e6
static char *srcfile_generator(const char *text, int state);
Packit Service f629e6
static char *argument_generator(const char *text, int state);
Packit Service f629e6
static char *variable_generator(const char *text, int state);
Packit Service f629e6
extern char *option_generator(const char *text, int state);
Packit Service f629e6
static int this_cmd = D_illegal;
Packit Service f629e6
#else
Packit Service f629e6
#define history_expand_line(p)	/* nothing */
Packit Service f629e6
static int rl_inhibit_completion;	/* dummy variable */
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
struct argtoken {
Packit Service f629e6
	const char *name;
Packit Service f629e6
	enum argtype cmd;
Packit Service f629e6
	enum nametypeval value;
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * These two should be static, but there are some compilers that
Packit Service f629e6
 * don't like the static keyword with an empty size. Therefore give
Packit Service f629e6
 * them names that are less likely to conflict with the rest of gawk.
Packit Service f629e6
 */
Packit Service f629e6
#define argtab zz_debug_argtab
Packit Service f629e6
#define cmdtab zz_debug_cmdtab
Packit Service f629e6
Packit Service f629e6
extern struct argtoken argtab[];
Packit Service f629e6
extern struct cmdtoken cmdtab[];
Packit Service f629e6
Packit Service f629e6
static CMDARG *mk_cmdarg(enum argtype type);
Packit Service f629e6
static void append_cmdarg(CMDARG *arg);
Packit Service f629e6
static int find_argument(CMDARG *arg);
Packit Service f629e6
#define YYSTYPE CMDARG *
Packit Service f629e6
%}
Packit Service f629e6
Packit Service f629e6
%token D_BACKTRACE D_BREAK D_CLEAR D_CONTINUE D_DELETE D_DISABLE D_DOWN
Packit Service f629e6
%token D_ENABLE D_FINISH D_FRAME D_HELP D_IGNORE D_INFO D_LIST
Packit Service f629e6
%token D_NEXT D_NEXTI D_PRINT D_PRINTF D_QUIT D_RETURN D_RUN D_SET
Packit Service f629e6
%token D_STEP D_STEPI D_TBREAK D_UP D_UNTIL
Packit Service f629e6
%token D_DISPLAY D_UNDISPLAY D_WATCH D_UNWATCH
Packit Service f629e6
%token D_DUMP D_TRACE
Packit Service f629e6
%token D_INT D_STRING D_NODE D_VARIABLE
Packit Service f629e6
%token D_OPTION D_COMMANDS D_END D_SILENT D_SOURCE
Packit Service f629e6
%token D_SAVE D_EVAL D_CONDITION
Packit Service f629e6
%token D_STATEMENT
Packit Service f629e6
Packit Service f629e6
%%
Packit Service f629e6
Packit Service f629e6
input
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	| input line
Packit Service f629e6
	  {
Packit Service f629e6
		cmd_idx = -1;
Packit Service f629e6
		want_nodeval = false;
Packit Service f629e6
		if (lexptr_begin != NULL) {
Packit Service f629e6
			if (input_from_tty && lexptr_begin[0] != '\0')
Packit Service f629e6
				add_history(lexptr_begin);
Packit Service f629e6
			efree(lexptr_begin);
Packit Service f629e6
			lexptr_begin = NULL;
Packit Service f629e6
		}
Packit Service f629e6
		if (arg_list != NULL) {
Packit Service f629e6
			free_cmdarg(arg_list);
Packit Service f629e6
			arg_list = NULL;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
line
Packit Service f629e6
	: nls
Packit Service f629e6
	| command nls
Packit Service f629e6
	  {
Packit Service f629e6
		if (errcount == 0 && cmd_idx >= 0) {
Packit Service f629e6
			Func_cmd cmdfunc;
Packit Service f629e6
			bool terminate = false;
Packit Service f629e6
			CMDARG *args;
Packit Service f629e6
			int ctype = 0;
Packit Service f629e6
Packit Service f629e6
			ctype = cmdtab[cmd_idx].type;
Packit Service f629e6
Packit Service f629e6
			/* a blank line repeats previous command
Packit Service f629e6
			 * (list, next, nexti, step, stepi and continue without arguments).
Packit Service f629e6
			 * save the index in the command table; used in yylex
Packit Service f629e6
			 */
Packit Service f629e6
			if ((ctype == D_list
Packit Service f629e6
					|| ctype == D_next
Packit Service f629e6
					|| ctype == D_step
Packit Service f629e6
					|| ctype == D_nexti
Packit Service f629e6
					|| ctype == D_stepi
Packit Service f629e6
					|| ctype == D_continue)
Packit Service f629e6
				&& arg_list == NULL
Packit Service f629e6
				&& ! in_commands
Packit Service f629e6
				&& input_from_tty
Packit Service f629e6
			)
Packit Service f629e6
				repeat_idx = cmd_idx;
Packit Service f629e6
			else
Packit Service f629e6
				repeat_idx = -1;
Packit Service f629e6
Packit Service f629e6
			/* call the command handler; reset the globals arg_list, cmd_idx,
Packit Service f629e6
			 * since this handler could invoke yyparse again.
Packit Service f629e6
			 * call do_commands for the list of commands in `commands';
Packit Service f629e6
			 * arg_list isn't freed on return.
Packit Service f629e6
			 */
Packit Service f629e6
Packit Service f629e6
			cmdfunc = cmdtab[cmd_idx].cf_ptr;
Packit Service f629e6
			if (in_commands)
Packit Service f629e6
				cmdfunc = do_commands;
Packit Service f629e6
			cmd_idx = -1;
Packit Service f629e6
			want_nodeval = false;
Packit Service f629e6
Packit Service f629e6
			args = arg_list;
Packit Service f629e6
			arg_list = NULL;
Packit Service f629e6
Packit Service f629e6
			terminate = (*cmdfunc)(args, ctype);
Packit Service f629e6
			if (! in_commands || ctype == D_commands)
Packit Service f629e6
				free_cmdarg(args);
Packit Service f629e6
			if (terminate)
Packit Service f629e6
				YYACCEPT;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	| error nls
Packit Service f629e6
	  {
Packit Service f629e6
		yyerrok;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
control_cmd
Packit Service f629e6
	: D_CONTINUE
Packit Service f629e6
	| D_NEXT
Packit Service f629e6
	| D_NEXTI
Packit Service f629e6
	| D_STEP
Packit Service f629e6
	| D_STEPI
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
d_cmd
Packit Service f629e6
	: D_UNDISPLAY
Packit Service f629e6
	| D_UNWATCH
Packit Service f629e6
	| D_DISABLE
Packit Service f629e6
	| D_DELETE
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
frame_cmd
Packit Service f629e6
	: D_UP
Packit Service f629e6
	| D_DOWN
Packit Service f629e6
	| D_BACKTRACE
Packit Service f629e6
	| D_FRAME
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
break_cmd
Packit Service f629e6
	: D_BREAK
Packit Service f629e6
	| D_TBREAK
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
/* mid-rule action buried in non-terminal to avoid conflict */
Packit Service f629e6
set_want_nodeval
Packit Service f629e6
	: { want_nodeval = true; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
eval_prologue
Packit Service f629e6
	: D_EVAL set_want_nodeval opt_param_list nls
Packit Service f629e6
	  {
Packit Service f629e6
		if (errcount == 0) {
Packit Service f629e6
			/* don't free arg_list;	passed on to statement_list
Packit Service f629e6
			 * non-terminal (empty rule action). See below.
Packit Service f629e6
			 */
Packit Service f629e6
			if (input_from_tty) {
Packit Service f629e6
				dbg_prompt = eval_prompt;
Packit Service f629e6
				fprintf(out_fp,
Packit Service f629e6
		_("Type (g)awk statement(s). End with the command \"end\"\n"));
Packit Service f629e6
				rl_inhibit_completion = 1;
Packit Service f629e6
			}
Packit Service f629e6
			cmd_idx = -1;
Packit Service f629e6
			in_eval = true;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
statement_list
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  {
Packit Service f629e6
		$$ = append_statement(arg_list, (char *) start_EVAL);
Packit Service f629e6
		if (read_a_line == read_commands_string)	/* unserializing 'eval' in 'commands' */
Packit Service f629e6
			$$->a_string[0] = '\0';
Packit Service f629e6
		free_cmdarg(arg_list);
Packit Service f629e6
		arg_list = NULL;
Packit Service f629e6
	  }
Packit Service f629e6
	| statement_list D_STATEMENT { $$ = append_statement($1, lexptr_begin); } nls
Packit Service f629e6
	  {
Packit Service f629e6
		$$ = $3;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
eval_cmd
Packit Service f629e6
	: eval_prologue statement_list D_END
Packit Service f629e6
	  {
Packit Service f629e6
		arg_list = append_statement($2, (char *) end_EVAL);
Packit Service f629e6
		if (read_a_line == read_commands_string) {	/* unserializing 'eval' in 'commands' */
Packit Service f629e6
			char *str = arg_list->a_string;
Packit Service f629e6
			size_t len = strlen(str);
Packit Service f629e6
			assert(len > 2 && str[len - 2] == '}');
Packit Service f629e6
			str[len - 2] = '\0';
Packit Service f629e6
		}
Packit Service f629e6
		if (input_from_tty) {
Packit Service f629e6
			dbg_prompt = in_commands ? commands_prompt : dgawk_prompt;
Packit Service f629e6
			rl_inhibit_completion = 0;
Packit Service f629e6
		}
Packit Service f629e6
		cmd_idx = find_command("eval", 4);
Packit Service f629e6
		in_eval = false;
Packit Service f629e6
	  }
Packit Service f629e6
	| D_EVAL set_want_nodeval string_node
Packit Service f629e6
	  {
Packit Service f629e6
		NODE *n;
Packit Service f629e6
		CMDARG *arg;
Packit Service f629e6
		n = $3->a_node;
Packit Service f629e6
		arg = append_statement(NULL, (char *) start_EVAL);
Packit Service f629e6
		(void) append_statement(arg, n->stptr);
Packit Service f629e6
		(void) append_statement(arg, (char *) end_EVAL);
Packit Service f629e6
		free_cmdarg(arg_list);
Packit Service f629e6
		arg_list = arg;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
command
Packit Service f629e6
	: D_HELP help_args
Packit Service f629e6
	| D_QUIT
Packit Service f629e6
	| D_RUN
Packit Service f629e6
	| D_FINISH
Packit Service f629e6
	| control_cmd opt_plus_integer
Packit Service f629e6
	| frame_cmd opt_integer
Packit Service f629e6
	  {
Packit Service f629e6
		if (cmdtab[cmd_idx].class == D_FRAME
Packit Service f629e6
				&& $2 != NULL && $2->a_int < 0)
Packit Service f629e6
			yyerror(_("invalid frame number: %d"), $2->a_int);
Packit Service f629e6
	  }
Packit Service f629e6
	| D_INFO D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		int idx = find_argument($2);
Packit Service f629e6
		if (idx < 0)
Packit Service f629e6
			yyerror(_("info: invalid option - \"%s\""), $2->a_string);
Packit Service f629e6
		else {
Packit Service f629e6
			efree($2->a_string);
Packit Service f629e6
			$2->a_string = NULL;
Packit Service f629e6
			$2->type = D_argument;
Packit Service f629e6
			$2->a_argument = argtab[idx].value;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	| D_IGNORE plus_integer D_INT
Packit Service f629e6
	| D_ENABLE enable_args
Packit Service f629e6
	| D_PRINT { want_nodeval = true; } print_args
Packit Service f629e6
	| D_PRINTF { want_nodeval = true; } printf_args
Packit Service f629e6
	| D_LIST list_args
Packit Service f629e6
	| D_UNTIL location
Packit Service f629e6
	| D_CLEAR location
Packit Service f629e6
	| break_cmd break_args
Packit Service f629e6
	| D_SET { want_nodeval = true; } variable '=' node
Packit Service f629e6
	| D_OPTION option_args
Packit Service f629e6
	| D_RETURN { want_nodeval = true; } opt_node
Packit Service f629e6
	| D_DISPLAY { want_nodeval = true; } opt_variable
Packit Service f629e6
	| D_WATCH { want_nodeval = true; } variable condition_exp
Packit Service f629e6
	| d_cmd opt_integer_list
Packit Service f629e6
	| D_DUMP opt_string
Packit Service f629e6
	| D_SOURCE D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		if (in_cmd_src($2->a_string))
Packit Service f629e6
			yyerror(_("source \"%s\": already sourced."), $2->a_string);
Packit Service f629e6
	  }
Packit Service f629e6
	| D_SAVE D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		if (! input_from_tty)
Packit Service f629e6
			yyerror(_("save \"%s\": command not permitted."), $2->a_string);
Packit Service f629e6
	  }
Packit Service f629e6
	| D_COMMANDS commands_arg
Packit Service f629e6
	  {
Packit Service f629e6
		int type = 0;
Packit Service f629e6
		int num;
Packit Service f629e6
Packit Service f629e6
		if ($2 != NULL)
Packit Service f629e6
			num = $2->a_int;
Packit Service f629e6
Packit Service f629e6
		if (errcount != 0)
Packit Service f629e6
			;
Packit Service f629e6
		else if (in_commands)
Packit Service f629e6
			yyerror(_("Can't use command `commands' for breakpoint/watchpoint commands"));
Packit Service f629e6
		else if ($2 == NULL &&  ! (type = has_break_or_watch_point(&num, true)))
Packit Service f629e6
			yyerror(_("no breakpoint/watchpoint has been set yet"));
Packit Service f629e6
		else if ($2 != NULL && ! (type = has_break_or_watch_point(&num, false)))
Packit Service f629e6
			yyerror(_("invalid breakpoint/watchpoint number"));
Packit Service f629e6
		if (type) {
Packit Service f629e6
			in_commands = true;
Packit Service f629e6
			if (input_from_tty) {
Packit Service f629e6
				dbg_prompt = commands_prompt;
Packit Service f629e6
				fprintf(out_fp, _("Type commands for when %s %d is hit, one per line.\n"),
Packit Service f629e6
								(type == D_break) ? "breakpoint" : "watchpoint", num);
Packit Service f629e6
				fprintf(out_fp, _("End with the command \"end\"\n"));
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	| D_END
Packit Service f629e6
	  {
Packit Service f629e6
		if (! in_commands)
Packit Service f629e6
			yyerror(_("`end' valid only in command `commands' or `eval'"));
Packit Service f629e6
		else {
Packit Service f629e6
			if (input_from_tty)
Packit Service f629e6
				dbg_prompt = dgawk_prompt;
Packit Service f629e6
			in_commands = false;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	| D_SILENT
Packit Service f629e6
	  {
Packit Service f629e6
		if (! in_commands)
Packit Service f629e6
			yyerror(_("`silent' valid only in command `commands'"));
Packit Service f629e6
	  }
Packit Service f629e6
	| D_TRACE D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		int idx = find_argument($2);
Packit Service f629e6
		if (idx < 0)
Packit Service f629e6
			yyerror(_("trace: invalid option - \"%s\""), $2->a_string);
Packit Service f629e6
		else {
Packit Service f629e6
			efree($2->a_string);
Packit Service f629e6
			$2->a_string = NULL;
Packit Service f629e6
			$2->type = D_argument;
Packit Service f629e6
			$2->a_argument = argtab[idx].value;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	| D_CONDITION plus_integer { want_nodeval = true; } condition_exp
Packit Service f629e6
	  {
Packit Service f629e6
		int type;
Packit Service f629e6
		int num = $2->a_int;
Packit Service f629e6
		type = has_break_or_watch_point(&num, false);
Packit Service f629e6
		if (! type)
Packit Service f629e6
			yyerror(_("condition: invalid breakpoint/watchpoint number"));
Packit Service f629e6
	  }
Packit Service f629e6
	| eval_cmd
Packit Service f629e6
	  {
Packit Service f629e6
		if (in_commands) {
Packit Service f629e6
			/* Prepend command 'eval' to argument list */
Packit Service f629e6
			CMDARG *arg;
Packit Service f629e6
			arg = mk_cmdarg(D_string);
Packit Service f629e6
			arg->a_string = estrdup("eval", 4);
Packit Service f629e6
			arg->next = arg_list;
Packit Service f629e6
			arg_list = arg;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
condition_exp
Packit Service f629e6
	: opt_string_node
Packit Service f629e6
	  {
Packit Service f629e6
		if ($1 != NULL) {
Packit Service f629e6
			NODE *n = $1->a_node;
Packit Service f629e6
			$1->type = D_string;
Packit Service f629e6
			$1->a_string = n->stptr;
Packit Service f629e6
			freenode(n);
Packit Service f629e6
		}
Packit Service f629e6
		$$ = $1;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
commands_arg
Packit Service f629e6
	: opt_plus_integer
Packit Service f629e6
	| error
Packit Service f629e6
	  {	$$ = NULL; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_param_list
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| param_list
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
param_list
Packit Service f629e6
	: D_VARIABLE
Packit Service f629e6
	| param_list D_VARIABLE
Packit Service f629e6
	| param_list ',' D_VARIABLE
Packit Service f629e6
	| error
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_string_node
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| string_node
Packit Service f629e6
	| error
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
string_node
Packit Service f629e6
	: D_NODE
Packit Service f629e6
	  {
Packit Service f629e6
		NODE *n;
Packit Service f629e6
		n = $1->a_node;
Packit Service f629e6
		if ((n->flags & STRING) == 0)
Packit Service f629e6
			yyerror(_("argument not a string"));
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
option_args
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		if (find_option($1->a_string) < 0)
Packit Service f629e6
			yyerror(_("option: invalid parameter - \"%s\""), $1->a_string);
Packit Service f629e6
 	  }
Packit Service f629e6
	| D_STRING '=' D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		if (find_option($1->a_string) < 0)
Packit Service f629e6
			yyerror(_("option: invalid parameter - \"%s\""), $1->a_string);
Packit Service f629e6
 	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
func_name
Packit Service f629e6
	: D_STRING
Packit Service f629e6
	  {
Packit Service f629e6
		NODE *n;
Packit Service f629e6
		n = lookup($1->a_string);
Packit Service f629e6
		if (n == NULL || n->type != Node_func)
Packit Service f629e6
			yyerror(_("no such function - \"%s\""), $1->a_string);
Packit Service f629e6
		else {
Packit Service f629e6
			$1->type = D_func;
Packit Service f629e6
			efree($1->a_string);
Packit Service f629e6
			$1->a_string = NULL;
Packit Service f629e6
			$1->a_node = n;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
location
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| plus_integer
Packit Service f629e6
	| func_name
Packit Service f629e6
	| D_STRING ':' plus_integer
Packit Service f629e6
	| D_STRING ':' func_name
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
break_args
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| plus_integer { want_nodeval = true; } condition_exp
Packit Service f629e6
	| func_name
Packit Service f629e6
	| D_STRING ':' plus_integer { want_nodeval = true; } condition_exp
Packit Service f629e6
	| D_STRING ':' func_name
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_variable
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| variable
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_string
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| D_STRING
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_node
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| node
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
help_args
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	| D_STRING
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
enable_args
Packit Service f629e6
	: opt_integer_list
Packit Service f629e6
	| D_STRING opt_integer_list
Packit Service f629e6
	  {
Packit Service f629e6
		int idx = find_argument($1);
Packit Service f629e6
		if (idx < 0)
Packit Service f629e6
			yyerror(_("enable: invalid option - \"%s\""), $1->a_string);
Packit Service f629e6
		else {
Packit Service f629e6
			efree($1->a_string);
Packit Service f629e6
			$1->a_string = NULL;
Packit Service f629e6
			$1->type = D_argument;
Packit Service f629e6
			$1->a_argument = argtab[idx].value;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
print_exp
Packit Service f629e6
	: variable
Packit Service f629e6
	| '@' D_VARIABLE
Packit Service f629e6
	  {
Packit Service f629e6
		$2->type = D_array;	/* dump all items */
Packit Service f629e6
		$2->a_count = 0;
Packit Service f629e6
	  }
Packit Service f629e6
	| '@' D_VARIABLE subscript_list /* dump sub-array items*/
Packit Service f629e6
	  {
Packit Service f629e6
		$2->type = D_array;
Packit Service f629e6
		$2->a_count = num_dim;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
print_args
Packit Service f629e6
	: print_exp
Packit Service f629e6
	| print_args print_exp
Packit Service f629e6
	| print_args ',' print_exp
Packit Service f629e6
	| error
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
printf_exp
Packit Service f629e6
	: D_NODE
Packit Service f629e6
	| variable
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
printf_args
Packit Service f629e6
	: printf_exp
Packit Service f629e6
	| printf_args ',' printf_exp
Packit Service f629e6
	| error
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
list_args
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| '+'
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| '-'
Packit Service f629e6
	  {
Packit Service f629e6
		CMDARG *a;
Packit Service f629e6
		a = mk_cmdarg(D_int);
Packit Service f629e6
		a->a_int = -1;
Packit Service f629e6
		append_cmdarg(a);
Packit Service f629e6
	  }
Packit Service f629e6
	| plus_integer
Packit Service f629e6
	| func_name
Packit Service f629e6
	| integer_range
Packit Service f629e6
	| D_STRING ':' plus_integer
Packit Service f629e6
	| D_STRING ':' func_name
Packit Service f629e6
	| D_STRING ':' integer_range
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
integer_range
Packit Service f629e6
	: plus_integer '-' plus_integer
Packit Service f629e6
	  {
Packit Service f629e6
		if ($1->a_int > $3->a_int)
Packit Service f629e6
			yyerror(_("invalid range specification: %d - %d"),
Packit Service f629e6
				$1->a_int, $3->a_int);
Packit Service f629e6
		else
Packit Service f629e6
			$1->type = D_range;
Packit Service f629e6
		$$ = $1;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_integer_list
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| integer_list
Packit Service f629e6
	| error
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
integer_list
Packit Service f629e6
	: plus_integer
Packit Service f629e6
	| integer_range
Packit Service f629e6
	| integer_list plus_integer
Packit Service f629e6
	| integer_list integer_range
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
exp_list
Packit Service f629e6
	: node
Packit Service f629e6
	  { $$ = $1; }
Packit Service f629e6
	| exp_list ',' node
Packit Service f629e6
	  { $$ = $1; }
Packit Service f629e6
	| error
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
subscript
Packit Service f629e6
	: '[' exp_list ']'
Packit Service f629e6
	  {
Packit Service f629e6
		CMDARG *a;
Packit Service f629e6
		NODE *subs;
Packit Service f629e6
		int count = 0;
Packit Service f629e6
Packit Service f629e6
		for (a = $2; a != NULL; a = a->next)
Packit Service f629e6
			count++;
Packit Service f629e6
		subs = concat_args($2, count);
Packit Service f629e6
		free_cmdarg($2->next);
Packit Service f629e6
		$2->next = NULL;
Packit Service f629e6
		$2->type = D_node;
Packit Service f629e6
		$2->a_node = subs;
Packit Service f629e6
		$$ = $2;
Packit Service f629e6
	  }
Packit Service f629e6
	| '[' exp_list error
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
subscript_list
Packit Service f629e6
	: subscript
Packit Service f629e6
	  { $$ = $1; num_dim = 1; }
Packit Service f629e6
	| subscript_list subscript
Packit Service f629e6
	  {	$$ = $1; num_dim++; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
variable
Packit Service f629e6
	: D_VARIABLE
Packit Service f629e6
	| '$' D_NODE
Packit Service f629e6
	  {
Packit Service f629e6
		NODE *n = $2->a_node;
Packit Service f629e6
		if ((n->flags & NUMBER) == 0)
Packit Service f629e6
			yyerror(_("non-numeric value for field number"));
Packit Service f629e6
		else
Packit Service f629e6
			$2->type = D_field;
Packit Service f629e6
		$$ = $2;
Packit Service f629e6
	  }
Packit Service f629e6
	| D_VARIABLE subscript_list
Packit Service f629e6
	  {
Packit Service f629e6
		/* a_string is array name, a_count is dimension count */
Packit Service f629e6
		$1->type = D_subscript;
Packit Service f629e6
		$1->a_count = num_dim;
Packit Service f629e6
		$$ = $1;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
node
Packit Service f629e6
	: D_NODE
Packit Service f629e6
	  { $$ = $1; }
Packit Service f629e6
	| '+' D_NODE
Packit Service f629e6
	  {
Packit Service f629e6
		NODE *n = $2->a_node;
Packit Service f629e6
		if ((n->flags & NUMBER) == 0)
Packit Service f629e6
			yyerror(_("non-numeric value found, numeric expected"));
Packit Service f629e6
		$$ = $2;
Packit Service f629e6
	  }
Packit Service f629e6
	| '-' D_NODE
Packit Service f629e6
	  {
Packit Service f629e6
		NODE *n = $2->a_node;
Packit Service f629e6
		if ((n->flags & NUMBER) == 0)
Packit Service f629e6
			yyerror(_("non-numeric value found, numeric expected"));
Packit Service f629e6
		else
Packit Service f629e6
			negate_num(n);
Packit Service f629e6
		$$ = $2;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_plus_integer
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| plus_integer
Packit Service f629e6
	  { $$ = $1; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
opt_integer
Packit Service f629e6
	: /* empty */
Packit Service f629e6
	  { $$ = NULL; }
Packit Service f629e6
	| integer
Packit Service f629e6
	  { $$ = $1; }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
plus_integer
Packit Service f629e6
	: D_INT
Packit Service f629e6
	  {
Packit Service f629e6
		if ($1->a_int == 0)
Packit Service f629e6
			yyerror(_("non-zero integer value"));
Packit Service f629e6
		$$ = $1;
Packit Service f629e6
	  }
Packit Service f629e6
	| '+' D_INT
Packit Service f629e6
	  {
Packit Service f629e6
		if ($2->a_int == 0)
Packit Service f629e6
			yyerror(_("non-zero integer value"));
Packit Service f629e6
		$$ = $2;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
integer
Packit Service f629e6
	: D_INT
Packit Service f629e6
	  { $$ = $1; }
Packit Service f629e6
	| '+' D_INT
Packit Service f629e6
	  { $$ = $2; }
Packit Service f629e6
	| '-' D_INT
Packit Service f629e6
	  {
Packit Service f629e6
		$2->a_int = - $2->a_int;
Packit Service f629e6
		$$ = $2;
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
nls
Packit Service f629e6
	: '\n'
Packit Service f629e6
	  {
Packit Service f629e6
		if (lexptr_begin != NULL) {
Packit Service f629e6
			if (input_from_tty && lexptr_begin[0] != '\0')
Packit Service f629e6
				add_history(lexptr_begin);
Packit Service f629e6
			efree(lexptr_begin);
Packit Service f629e6
			lexptr_begin = NULL;
Packit Service f629e6
		}
Packit Service f629e6
	  }
Packit Service f629e6
	;
Packit Service f629e6
Packit Service f629e6
%%
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* append_statement --- append 'stmt' to the list of eval awk statements */
Packit Service f629e6
Packit Service f629e6
static CMDARG *
Packit Service f629e6
append_statement(CMDARG *stmt_list, char *stmt)
Packit Service f629e6
{
Packit Service f629e6
	CMDARG *a, *arg;
Packit Service f629e6
	char *s;
Packit Service f629e6
	int len, slen, ssize;
Packit Service f629e6
Packit Service f629e6
#define EVALSIZE	512
Packit Service f629e6
Packit Service f629e6
	if (stmt == start_EVAL) {
Packit Service f629e6
		len = sizeof(start_EVAL);
Packit Service f629e6
		for (a = stmt_list; a != NULL; a = a->next)
Packit Service f629e6
			len += strlen(a->a_string) + 1;	/* 1 for ',' */
Packit Service f629e6
		len += EVALSIZE;
Packit Service f629e6
Packit Service f629e6
		emalloc(s, char *, (len + 1) * sizeof(char), "append_statement");
Packit Service f629e6
		arg = mk_cmdarg(D_string);
Packit Service f629e6
		arg->a_string = s;
Packit Service f629e6
		arg->a_count = len;	/* kludge */
Packit Service f629e6
Packit Service f629e6
		slen = sizeof("function @eval(") - 1;
Packit Service f629e6
		memcpy(s, start_EVAL, slen);
Packit Service f629e6
Packit Service f629e6
		for (a = stmt_list; a != NULL; a = a->next) {
Packit Service f629e6
			len = strlen(a->a_string);
Packit Service f629e6
			memcpy(s + slen, a->a_string, len);
Packit Service f629e6
			slen += len;
Packit Service f629e6
			if (a->next != NULL)
Packit Service f629e6
				s[slen++] = ',';
Packit Service f629e6
		}
Packit Service f629e6
		s[slen++] = ')';
Packit Service f629e6
		s[slen++] = '{';
Packit Service f629e6
		s[slen] = '\0';
Packit Service f629e6
		return arg;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	len = strlen(stmt) + 1;	/* 1 for newline */
Packit Service f629e6
	s = stmt_list->a_string;
Packit Service f629e6
	slen = strlen(s);
Packit Service f629e6
	ssize = stmt_list->a_count;
Packit Service f629e6
	if (len > ssize - slen) {
Packit Service f629e6
		ssize = slen + len + EVALSIZE;
Packit Service f629e6
		erealloc(s, char *, (ssize + 1) * sizeof(char), "append_statement");
Packit Service f629e6
		stmt_list->a_string = s;
Packit Service f629e6
		stmt_list->a_count = ssize;
Packit Service f629e6
	}
Packit Service f629e6
	memcpy(s + slen, stmt, len);
Packit Service f629e6
	slen += len;
Packit Service f629e6
	if (slen >= 2 && s[slen - 2] != '\n') {
Packit Service f629e6
		s[slen - 1] = '\n';
Packit Service f629e6
		s[slen] = '\0';
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (stmt == end_EVAL)
Packit Service f629e6
		erealloc(stmt_list->a_string, char *, slen + 1, "append_statement");
Packit Service f629e6
	return stmt_list;
Packit Service f629e6
Packit Service f629e6
#undef EVALSIZE
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* command names sorted in ascending order */
Packit Service f629e6
Packit Service f629e6
struct cmdtoken cmdtab[] = {
Packit Service f629e6
{ "backtrace", "bt", D_backtrace, D_BACKTRACE, do_backtrace,
Packit Service f629e6
	gettext_noop("backtrace [N] - print trace of all or N innermost (outermost if N < 0) frames.") },
Packit Service f629e6
{ "break", "b", D_break, D_BREAK, do_breakpoint,
Packit Service f629e6
	gettext_noop("break [[filename:]N|function] - set breakpoint at the specified location.") },
Packit Service f629e6
{ "clear", "", D_clear, D_CLEAR, do_clear,
Packit Service f629e6
	gettext_noop("clear [[filename:]N|function] - delete breakpoints previously set.") },
Packit Service f629e6
{ "commands", "", D_commands, D_COMMANDS, do_commands,
Packit Service f629e6
	gettext_noop("commands [num] - starts a list of commands to be executed at a breakpoint(watchpoint) hit.") },
Packit Service f629e6
{ "condition", "", D_condition, D_CONDITION, do_condition,
Packit Service f629e6
	gettext_noop("condition num [expr] - set or clear breakpoint or watchpoint condition.") },
Packit Service f629e6
{ "continue", "c", D_continue, D_CONTINUE, do_continue,
Packit Service f629e6
	gettext_noop("continue [COUNT] - continue program being debugged.") },
Packit Service f629e6
{ "delete", "d", D_delete, D_DELETE, do_delete_breakpoint,
Packit Service f629e6
	gettext_noop("delete [breakpoints] [range] - delete specified breakpoints.") },
Packit Service f629e6
{ "disable", "", D_disable, D_DISABLE, do_disable_breakpoint,
Packit Service f629e6
	gettext_noop("disable [breakpoints] [range] - disable specified breakpoints.") },
Packit Service f629e6
{ "display", "", D_display, D_DISPLAY, do_display,
Packit Service f629e6
	gettext_noop("display [var] - print value of variable each time the program stops.") },
Packit Service f629e6
{ "down", "", D_down, D_DOWN, do_down,
Packit Service f629e6
	gettext_noop("down [N] - move N frames down the stack.") },
Packit Service f629e6
{ "dump", "", D_dump, D_DUMP, do_dump_instructions,
Packit Service f629e6
	gettext_noop("dump [filename] - dump instructions to file or stdout.") },
Packit Service f629e6
{ "enable", "e", D_enable, D_ENABLE, do_enable_breakpoint,
Packit Service f629e6
	gettext_noop("enable [once|del] [breakpoints] [range] - enable specified breakpoints.") },
Packit Service f629e6
{ "end", "", D_end, D_END, do_commands,
Packit Service f629e6
	gettext_noop("end - end a list of commands or awk statements.") },
Packit Service f629e6
{ "eval", "", D_eval, D_EVAL, do_eval,
Packit Service f629e6
	gettext_noop("eval stmt|[p1, p2, ...] - evaluate awk statement(s).") },
Packit Service f629e6
{ "exit", "", D_quit, D_QUIT, do_quit,
Packit Service f629e6
	gettext_noop("exit - (same as quit) exit debugger.") },
Packit Service f629e6
{ "finish", "", D_finish, D_FINISH, do_finish,
Packit Service f629e6
	gettext_noop("finish - execute until selected stack frame returns.") },
Packit Service f629e6
{ "frame", "f", D_frame, D_FRAME, do_frame,
Packit Service f629e6
	gettext_noop("frame [N] - select and print stack frame number N.") },
Packit Service f629e6
{ "help", "h", D_help, D_HELP, do_help,
Packit Service f629e6
	gettext_noop("help [command] - print list of commands or explanation of command.") },
Packit Service f629e6
{ "ignore", "", D_ignore, D_IGNORE, do_ignore_breakpoint,
Packit Service f629e6
	gettext_noop("ignore N COUNT - set ignore-count of breakpoint number N to COUNT.") },
Packit Service f629e6
{ "info", "i", D_info, D_INFO, do_info,
Packit Service f629e6
	gettext_noop("info topic - source|sources|variables|functions|break|frame|args|locals|display|watch.") },
Packit Service f629e6
{ "list", "l", D_list, D_LIST, do_list,
Packit Service f629e6
	gettext_noop("list [-|+|[filename:]lineno|function|range] - list specified line(s).") },
Packit Service f629e6
{ "next", "n", D_next, D_NEXT, do_next,
Packit Service f629e6
	gettext_noop("next [COUNT] - step program, proceeding through subroutine calls.") },
Packit Service f629e6
{ "nexti", "ni", D_nexti, D_NEXTI, do_nexti,
Packit Service f629e6
	gettext_noop("nexti [COUNT] - step one instruction, but proceed through subroutine calls.") },
Packit Service f629e6
{ "option", "o", D_option, D_OPTION, do_option,
Packit Service f629e6
	gettext_noop("option [name[=value]] - set or display debugger option(s).") },
Packit Service f629e6
{ "print", "p", D_print, D_PRINT, do_print_var,
Packit Service f629e6
	gettext_noop("print var [var] - print value of a variable or array.") },
Packit Service f629e6
{ "printf", "", D_printf, D_PRINTF, do_print_f,
Packit Service f629e6
	gettext_noop("printf format, [arg], ... - formatted output.") },
Packit Service f629e6
{ "quit", "q", D_quit, D_QUIT, do_quit,
Packit Service f629e6
	gettext_noop("quit - exit debugger.") },
Packit Service f629e6
{ "return", "", D_return, D_RETURN, do_return,
Packit Service f629e6
	gettext_noop("return [value] - make selected stack frame return to its caller.") },
Packit Service f629e6
{ "run", "r", D_run, D_RUN, do_run,
Packit Service f629e6
	gettext_noop("run - start or restart executing program.") },
Packit Service f629e6
#ifdef HAVE_LIBREADLINE
Packit Service f629e6
{ "save", "", D_save, D_SAVE, do_save,
Packit Service f629e6
	gettext_noop("save filename - save commands from the session to file.") },
Packit Service f629e6
#endif
Packit Service f629e6
{ "set", "", D_set, D_SET, do_set_var,
Packit Service f629e6
	gettext_noop("set var = value - assign value to a scalar variable.") },
Packit Service f629e6
{ "silent", "", D_silent, D_SILENT, do_commands,
Packit Service f629e6
	gettext_noop("silent - suspends usual message when stopped at a breakpoint/watchpoint.") },
Packit Service f629e6
{ "source", "", D_source, D_SOURCE, do_source,
Packit Service f629e6
	gettext_noop("source file - execute commands from file.") },
Packit Service f629e6
{ "step", "s", D_step, D_STEP, do_step,
Packit Service f629e6
	gettext_noop("step [COUNT] - step program until it reaches a different source line.") },
Packit Service f629e6
{ "stepi", "si", D_stepi, D_STEPI, do_stepi,
Packit Service f629e6
	gettext_noop("stepi [COUNT] - step one instruction exactly.") },
Packit Service f629e6
{ "tbreak", "t", D_tbreak, D_TBREAK, do_tmp_breakpoint,
Packit Service f629e6
	gettext_noop("tbreak [[filename:]N|function] - set a temporary breakpoint.") },
Packit Service f629e6
{ "trace", "", D_trace, D_TRACE, do_trace_instruction,
Packit Service f629e6
	gettext_noop("trace on|off - print instruction before executing.") },
Packit Service f629e6
{ "undisplay",	"", D_undisplay, D_UNDISPLAY, do_undisplay,
Packit Service f629e6
	gettext_noop("undisplay [N] - remove variable(s) from automatic display list.") },
Packit Service f629e6
{ "until", "u", D_until, D_UNTIL, do_until,
Packit Service f629e6
	gettext_noop("until [[filename:]N|function] - execute until program reaches a different line or line N within current frame.") },
Packit Service f629e6
{ "unwatch", "", D_unwatch, D_UNWATCH, do_unwatch,
Packit Service f629e6
	gettext_noop("unwatch [N] - remove variable(s) from watch list.") },
Packit Service f629e6
{ "up",	"", D_up, D_UP, do_up,
Packit Service f629e6
	gettext_noop("up [N] - move N frames up the stack.") },
Packit Service f629e6
{ "watch", "w", D_watch, D_WATCH, do_watch,
Packit Service f629e6
	gettext_noop("watch var - set a watchpoint for a variable.") },
Packit Service f629e6
{ "where", "", D_backtrace, D_BACKTRACE, do_backtrace,
Packit Service f629e6
	gettext_noop("where [N] - (same as backtrace) print trace of all or N innermost (outermost if N < 0) frames.") },
Packit Service f629e6
{ NULL, NULL, D_illegal, 0, (Func_cmd) 0,
Packit Service f629e6
	 NULL },
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
struct argtoken argtab[] = {
Packit Service f629e6
	{ "args", D_info, A_ARGS },
Packit Service f629e6
	{ "break", D_info, A_BREAK },
Packit Service f629e6
	{ "del", D_enable, A_DEL },
Packit Service f629e6
	{ "display", D_info, A_DISPLAY },
Packit Service f629e6
	{ "frame", D_info, A_FRAME },
Packit Service f629e6
	{ "functions", D_info, A_FUNCTIONS },
Packit Service f629e6
	{ "locals", D_info, A_LOCALS },
Packit Service f629e6
	{ "off", D_trace, A_TRACE_OFF },
Packit Service f629e6
	{ "on", D_trace, A_TRACE_ON },
Packit Service f629e6
	{ "once", D_enable, A_ONCE },
Packit Service f629e6
	{ "source", D_info, A_SOURCE },
Packit Service f629e6
	{ "sources", D_info, A_SOURCES },
Packit Service f629e6
	{ "variables", D_info, A_VARIABLES },
Packit Service f629e6
	{ "watch", D_info, A_WATCH },
Packit Service f629e6
	{ NULL, D_illegal, A_NONE },
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* get_command --- return command handler function */
Packit Service f629e6
Packit Service f629e6
Func_cmd
Packit Service f629e6
get_command(int ctype)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	for (i = 0; cmdtab[i].name != NULL; i++) {
Packit Service f629e6
		if (cmdtab[i].type == ctype)
Packit Service f629e6
			return cmdtab[i].cf_ptr;
Packit Service f629e6
	}
Packit Service f629e6
	return (Func_cmd) 0;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* get_command_name --- return command name given it's type */
Packit Service f629e6
Packit Service f629e6
const char *
Packit Service f629e6
get_command_name(int ctype)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	for (i = 0; cmdtab[i].name != NULL; i++) {
Packit Service f629e6
		if (cmdtab[i].type == ctype)
Packit Service f629e6
			return cmdtab[i].name;
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* mk_cmdarg --- make an argument for command */
Packit Service f629e6
Packit Service f629e6
static CMDARG *
Packit Service f629e6
mk_cmdarg(enum argtype type)
Packit Service f629e6
{
Packit Service f629e6
	CMDARG *arg;
Packit Service f629e6
	ezalloc(arg, CMDARG *, sizeof(CMDARG), "mk_cmdarg");
Packit Service f629e6
	arg->type = type;
Packit Service f629e6
	return arg;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* append_cmdarg --- append ARG to the list of arguments for the current command */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
append_cmdarg(CMDARG *arg)
Packit Service f629e6
{
Packit Service f629e6
	static CMDARG *savetail;
Packit Service f629e6
Packit Service f629e6
	if (arg_list == NULL)
Packit Service f629e6
		arg_list = arg;
Packit Service f629e6
	else
Packit Service f629e6
		savetail->next = arg;
Packit Service f629e6
	savetail = arg;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* free_cmdarg --- free all arguments in LIST */
Packit Service f629e6
Packit Service f629e6
void
Packit Service f629e6
free_cmdarg(CMDARG *list)
Packit Service f629e6
{
Packit Service f629e6
	CMDARG *arg, *nexta;
Packit Service f629e6
Packit Service f629e6
	for (arg = list; arg != NULL; arg = nexta) {
Packit Service f629e6
		nexta = arg->next;
Packit Service f629e6
Packit Service f629e6
		switch (arg->type) {
Packit Service f629e6
		case D_variable:
Packit Service f629e6
		case D_subscript:
Packit Service f629e6
		case D_array:
Packit Service f629e6
		case D_string:
Packit Service f629e6
			if (arg->a_string != NULL)
Packit Service f629e6
				efree(arg->a_string);
Packit Service f629e6
			break;
Packit Service f629e6
		case D_node:
Packit Service f629e6
		case D_field:
Packit Service f629e6
			unref(arg->a_node);
Packit Service f629e6
			break;
Packit Service f629e6
		default:
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
		efree(arg);
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* yyerror --- print a syntax error message */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
yyerror(const char *mesg, ...)
Packit Service f629e6
{
Packit Service f629e6
	va_list args;
Packit Service f629e6
	va_start(args, mesg);
Packit Service f629e6
	fprintf(out_fp, _("error: "));
Packit Service f629e6
	vfprintf(out_fp, mesg, args);
Packit Service f629e6
	fprintf(out_fp, "\n");
Packit Service f629e6
	va_end(args);
Packit Service f629e6
	errcount++;
Packit Service f629e6
	repeat_idx = -1;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* yylex --- read a command and turn it into tokens */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
#ifdef USE_EBCDIC
Packit Service f629e6
yylex_ebcdic(void)
Packit Service f629e6
#else
Packit Service f629e6
yylex(void)
Packit Service f629e6
#endif
Packit Service f629e6
{
Packit Service f629e6
	static char *lexptr = NULL;
Packit Service f629e6
	static char *lexend;
Packit Service f629e6
	int c;
Packit Service f629e6
	char *tokstart;
Packit Service f629e6
	size_t toklen;
Packit Service f629e6
Packit Service f629e6
	yylval = (CMDARG *) NULL;
Packit Service f629e6
Packit Service f629e6
	if (errcount > 0 && lexptr_begin == NULL) {
Packit Service f629e6
		/* fake a new line */
Packit Service f629e6
		errcount = 0;
Packit Service f629e6
		return '\n';
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (lexptr_begin == NULL) {
Packit Service f629e6
again:
Packit Service f629e6
		lexptr_begin = read_a_line(dbg_prompt);
Packit Service f629e6
		if (lexptr_begin == NULL) {	/* EOF or error */
Packit Service f629e6
			if (get_eof_status() == EXIT_FATAL)
Packit Service f629e6
				exit(EXIT_FATAL);
Packit Service f629e6
			if (get_eof_status() == EXIT_FAILURE) {
Packit Service f629e6
				static int seen_eof = 0;
Packit Service f629e6
Packit Service f629e6
				/* force a quit, and let do_quit (in debug.c) exit */
Packit Service f629e6
				if (! seen_eof) {
Packit Service f629e6
					if (errno != 0)	{
Packit Service f629e6
						fprintf(stderr, _("can't read command (%s)\n"), strerror(errno));
Packit Service f629e6
						exit_val = EXIT_FAILURE;
Packit Service f629e6
					} /* else
Packit Service f629e6
						exit_val = EXIT_SUCCESS; */
Packit Service f629e6
Packit Service f629e6
					seen_eof = 1;
Packit Service f629e6
					return '\n';	/* end current command if any */
Packit Service f629e6
				} else if (seen_eof++ == 1) {
Packit Service f629e6
					cmd_idx = find_command("quit", 4);
Packit Service f629e6
					return D_QUIT;	/* 'quit' token */
Packit Service f629e6
				} else
Packit Service f629e6
					return '\n';	/* end command 'quit' */
Packit Service f629e6
			}
Packit Service f629e6
			if (errno != 0)
Packit Service f629e6
				d_error(_("can't read command (%s)"), strerror(errno));
Packit Service f629e6
			if (pop_cmd_src() == 0)
Packit Service f629e6
				goto again;
Packit Service f629e6
			exit(EXIT_FATAL);	/* shouldn't happen */
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		if (! in_commands && ! in_eval	/* history expansion off in 'commands' and 'eval' */
Packit Service f629e6
				&& input_from_tty
Packit Service f629e6
		)
Packit Service f629e6
			history_expand_line(&lexptr_begin);
Packit Service f629e6
Packit Service f629e6
		lexptr = lexptr_begin;
Packit Service f629e6
		lexend = lexptr + strlen(lexptr);
Packit Service f629e6
		if (*lexptr == '\0'		/* blank line */
Packit Service f629e6
				&& repeat_idx >= 0
Packit Service f629e6
				&& input_from_tty
Packit Service f629e6
				&& ! in_eval
Packit Service f629e6
		) {
Packit Service f629e6
#ifdef HAVE_LIBREADLINE
Packit Service f629e6
			HIST_ENTRY *h;
Packit Service f629e6
			h = previous_history();
Packit Service f629e6
			if (h != NULL)
Packit Service f629e6
				add_history(h->line);
Packit Service f629e6
#endif
Packit Service f629e6
			cmd_idx = repeat_idx;
Packit Service f629e6
			return cmdtab[cmd_idx].class;	/* repeat last command */
Packit Service f629e6
		}
Packit Service f629e6
		repeat_idx = -1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	c = *lexptr;
Packit Service f629e6
Packit Service f629e6
	while (c == ' ' || c == '\t')
Packit Service f629e6
		c = *++lexptr;
Packit Service f629e6
Packit Service f629e6
	if (! input_from_tty && c == '#')
Packit Service f629e6
		return '\n';
Packit Service f629e6
Packit Service f629e6
	tokstart = lexptr;
Packit Service f629e6
	if (lexptr >= lexend)
Packit Service f629e6
		return '\n';
Packit Service f629e6
Packit Service f629e6
	if (cmd_idx < 0) {	/* need a command */
Packit Service f629e6
		if (c == '?' && tokstart[1] == '\0'	&& ! in_eval) {
Packit Service f629e6
			lexptr++;
Packit Service f629e6
			cmd_idx = find_command("help", 4);
Packit Service f629e6
			return D_HELP;
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		while (c != '\0' && c != ' ' && c != '\t') {
Packit Service f629e6
			if (! is_alpha(c) && ! in_eval) {
Packit Service f629e6
				yyerror(_("invalid character in command"));
Packit Service f629e6
				return '\n';
Packit Service f629e6
			}
Packit Service f629e6
			c = *++lexptr;
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		toklen = lexptr - tokstart;
Packit Service f629e6
Packit Service f629e6
		if (in_eval) {
Packit Service f629e6
			if (toklen == 3
Packit Service f629e6
					&& tokstart[3] == '\0'
Packit Service f629e6
					&& tokstart[0] == 'e'
Packit Service f629e6
					&& tokstart[1] == 'n'
Packit Service f629e6
					&& tokstart[2] == 'd'
Packit Service f629e6
			) {
Packit Service f629e6
				cmd_idx = find_command(tokstart, toklen);
Packit Service f629e6
				return D_END;
Packit Service f629e6
			}
Packit Service f629e6
			lexptr = lexend;
Packit Service f629e6
			return D_STATEMENT;
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		cmd_idx = find_command(tokstart, toklen);
Packit Service f629e6
		if (cmd_idx >= 0) {
Packit Service f629e6
			if (in_commands && cmdtab[cmd_idx].type != D_eval) {
Packit Service f629e6
				/* add the actual command string (lexptr_begin) to
Packit Service f629e6
				 * arg_list; command string for 'eval' prepended to the arg_list
Packit Service f629e6
				 * in the grammer above (see eval_cmd non-terminal).
Packit Service f629e6
				 */
Packit Service f629e6
				CMDARG *arg;
Packit Service f629e6
				arg = mk_cmdarg(D_string);
Packit Service f629e6
				arg->a_string = estrdup(lexptr_begin, lexend - lexptr_begin);
Packit Service f629e6
				append_cmdarg(arg);
Packit Service f629e6
			}
Packit Service f629e6
			return cmdtab[cmd_idx].class;
Packit Service f629e6
		} else {
Packit Service f629e6
			yyerror(_("unknown command - \"%.*s\", try help"), toklen, tokstart);
Packit Service f629e6
			return '\n';
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	c = *lexptr;
Packit Service f629e6
Packit Service f629e6
	if (cmdtab[cmd_idx].type == D_option) {
Packit Service f629e6
		if (c == '=')
Packit Service f629e6
			return *lexptr++;
Packit Service f629e6
	} else if (c == '-' || c == '+' || c == ':' || c == '|')
Packit Service f629e6
		return *lexptr++;
Packit Service f629e6
Packit Service f629e6
	if (c == '"') {
Packit Service f629e6
		char *str, *p;
Packit Service f629e6
		int flags = ALREADY_MALLOCED;
Packit Service f629e6
		bool esc_seen = false;
Packit Service f629e6
Packit Service f629e6
		toklen = lexend - lexptr;
Packit Service f629e6
		emalloc(str, char *, toklen + 1, "yylex");
Packit Service f629e6
		p = str;
Packit Service f629e6
Packit Service f629e6
		while ((c = *++lexptr) != '"') {
Packit Service f629e6
			if (lexptr == lexend) {
Packit Service f629e6
err:
Packit Service f629e6
				efree(str);
Packit Service f629e6
				yyerror(_("unterminated string"));
Packit Service f629e6
				return '\n';
Packit Service f629e6
			}
Packit Service f629e6
			if (c == '\\') {
Packit Service f629e6
				c = *++lexptr;
Packit Service f629e6
				esc_seen = true;
Packit Service f629e6
				if (want_nodeval || c != '"')
Packit Service f629e6
					*p++ = '\\';
Packit Service f629e6
			}
Packit Service f629e6
			if (lexptr == lexend)
Packit Service f629e6
				goto err;
Packit Service f629e6
			*p++ = c;
Packit Service f629e6
		}
Packit Service f629e6
		lexptr++;
Packit Service f629e6
		*p = '\0';
Packit Service f629e6
Packit Service f629e6
		if (! want_nodeval) {
Packit Service f629e6
			yylval = mk_cmdarg(D_string);
Packit Service f629e6
			yylval->a_string = str;
Packit Service f629e6
			append_cmdarg(yylval);
Packit Service f629e6
			return D_STRING;
Packit Service f629e6
		} else {	/* awk string */
Packit Service f629e6
			if (esc_seen)
Packit Service f629e6
				flags |= SCAN;
Packit Service f629e6
			yylval = mk_cmdarg(D_node);
Packit Service f629e6
			yylval->a_node = make_str_node(str, p - str, flags);
Packit Service f629e6
			append_cmdarg(yylval);
Packit Service f629e6
			return D_NODE;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! want_nodeval) {
Packit Service f629e6
		while ((c = *++lexptr) != '\0' && c != ':' && c != '-'
Packit Service f629e6
					&& c != ' ' && c != '\t' && c != '=')
Packit Service f629e6
			;
Packit Service f629e6
Packit Service f629e6
		/* Is it an integer? */
Packit Service f629e6
		if (isdigit((unsigned char) tokstart[0]) && cmdtab[cmd_idx].type != D_option) {
Packit Service f629e6
			char *end;
Packit Service f629e6
			long l;
Packit Service f629e6
Packit Service f629e6
			errno = 0;
Packit Service f629e6
			l = strtol(tokstart, &end, 0);
Packit Service f629e6
			if (errno != 0) {
Packit Service f629e6
				yyerror(_("%s"), strerror(errno));
Packit Service f629e6
				errno = 0;
Packit Service f629e6
				return '\n';
Packit Service f629e6
			}
Packit Service f629e6
Packit Service f629e6
			if (lexptr == end) {
Packit Service f629e6
				yylval = mk_cmdarg(D_int);
Packit Service f629e6
				yylval->a_int = l;
Packit Service f629e6
				append_cmdarg(yylval);
Packit Service f629e6
				return D_INT;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		/* Must be string */
Packit Service f629e6
		yylval = mk_cmdarg(D_string);
Packit Service f629e6
		yylval->a_string = estrdup(tokstart, lexptr - tokstart);
Packit Service f629e6
		append_cmdarg(yylval);
Packit Service f629e6
		return D_STRING;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* look for awk number */
Packit Service f629e6
Packit Service f629e6
	if (isdigit((unsigned char) tokstart[0])) {
Packit Service f629e6
		NODE *r = NULL;
Packit Service f629e6
Packit Service f629e6
		errno = 0;
Packit Service f629e6
#ifdef HAVE_MPFR
Packit Service f629e6
		if (do_mpfr) {
Packit Service f629e6
			int tval;
Packit Service f629e6
			r = mpg_float();
Packit Service f629e6
			tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 0, ROUND_MODE);
Packit Service f629e6
			IEEE_FMT(r->mpg_numbr, tval);
Packit Service f629e6
			if (mpfr_integer_p(r->mpg_numbr)) {
Packit Service f629e6
				/* integral value, convert to a GMP type. */
Packit Service f629e6
				NODE *tmp = r;
Packit Service f629e6
				r = mpg_integer();
Packit Service f629e6
				mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
Packit Service f629e6
				unref(tmp);
Packit Service f629e6
			}
Packit Service f629e6
		} else
Packit Service f629e6
#endif
Packit Service f629e6
			r = make_number(strtod(tokstart, & lexptr));
Packit Service f629e6
Packit Service f629e6
		if (errno != 0) {
Packit Service f629e6
			yyerror(strerror(errno));
Packit Service f629e6
			unref(r);
Packit Service f629e6
			errno = 0;
Packit Service f629e6
			return '\n';
Packit Service f629e6
		}
Packit Service f629e6
		yylval = mk_cmdarg(D_node);
Packit Service f629e6
		yylval->a_node = r;
Packit Service f629e6
		append_cmdarg(yylval);
Packit Service f629e6
		return D_NODE;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	c = *lexptr;
Packit Service f629e6
	if (c == '$' || c == '@'
Packit Service f629e6
			|| c == '[' || c == ']'
Packit Service f629e6
			|| c == ',' || c == '=')
Packit Service f629e6
		return *lexptr++;
Packit Service f629e6
Packit Service f629e6
	if (! is_letter(c)) {
Packit Service f629e6
		yyerror(_("invalid character"));
Packit Service f629e6
		return '\n';
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	while (is_identchar(c))
Packit Service f629e6
		c = *++lexptr;
Packit Service f629e6
	toklen = lexptr - tokstart;
Packit Service f629e6
Packit Service f629e6
	/* awk variable */
Packit Service f629e6
	yylval = mk_cmdarg(D_variable);
Packit Service f629e6
	yylval->a_string = estrdup(tokstart, toklen);
Packit Service f629e6
	append_cmdarg(yylval);
Packit Service f629e6
	return D_VARIABLE;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* Convert single-character tokens coming out of yylex() from EBCDIC to
Packit Service f629e6
   ASCII values on-the-fly so that the parse tables need not be regenerated
Packit Service f629e6
   for EBCDIC systems.  */
Packit Service f629e6
#ifdef USE_EBCDIC
Packit Service f629e6
static int
Packit Service f629e6
yylex(void)
Packit Service f629e6
{
Packit Service f629e6
	static char etoa_xlate[256];
Packit Service f629e6
	static int do_etoa_init = 1;
Packit Service f629e6
	int tok;
Packit Service f629e6
Packit Service f629e6
	if (do_etoa_init)
Packit Service f629e6
	{
Packit Service f629e6
		for (tok = 0; tok < 256; tok++)
Packit Service f629e6
			etoa_xlate[tok] = (char) tok;
Packit Service f629e6
#ifdef HAVE___ETOA_L
Packit Service f629e6
		/* IBM helpfully provides this function.  */
Packit Service f629e6
		__etoa_l(etoa_xlate, sizeof(etoa_xlate));
Packit Service f629e6
#else
Packit Service f629e6
# error "An EBCDIC-to-ASCII translation function is needed for this system"
Packit Service f629e6
#endif
Packit Service f629e6
		do_etoa_init = 0;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	tok = yylex_ebcdic();
Packit Service f629e6
Packit Service f629e6
	if (tok >= 0 && tok <= 0xFF)
Packit Service f629e6
		tok = etoa_xlate[tok];
Packit Service f629e6
Packit Service f629e6
	return tok;
Packit Service f629e6
}
Packit Service f629e6
#endif /* USE_EBCDIC */
Packit Service f629e6
Packit Service f629e6
/* find_argument --- find index in 'argtab' for a command option */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
find_argument(CMDARG *arg)
Packit Service f629e6
{
Packit Service f629e6
	/* non-number argument */
Packit Service f629e6
	int idx;
Packit Service f629e6
	char *name, *p;
Packit Service f629e6
	size_t len;
Packit Service f629e6
	assert(cmd_idx >= 0);
Packit Service f629e6
	name = arg->a_string;
Packit Service f629e6
	len = strlen(name);
Packit Service f629e6
	for (idx = 0; (p = (char *) argtab[idx].name) != NULL; idx++) {
Packit Service f629e6
		if (cmdtab[cmd_idx].type == argtab[idx].cmd
Packit Service f629e6
				&& *p == *name
Packit Service f629e6
				&& strlen(p) == len
Packit Service f629e6
				&& strncmp(p, name, len) == 0
Packit Service f629e6
		)
Packit Service f629e6
			return idx;
Packit Service f629e6
	}
Packit Service f629e6
	return -1;	/* invalid option */
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* concat_args --- concatenate argument strings into a single string NODE */
Packit Service f629e6
Packit Service f629e6
static NODE *
Packit Service f629e6
concat_args(CMDARG *arg, int count)
Packit Service f629e6
{
Packit Service f629e6
	NODE *n;
Packit Service f629e6
	NODE **tmp;
Packit Service f629e6
	char *str, *subsep, *p;
Packit Service f629e6
	long len, subseplen;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	if (count == 1) {
Packit Service f629e6
		n = force_string(arg->a_node);
Packit Service f629e6
		return dupnode(n);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	emalloc(tmp, NODE **, count * sizeof(NODE *), "concat_args");
Packit Service f629e6
	subseplen = SUBSEP_node->var_value->stlen;
Packit Service f629e6
	subsep = SUBSEP_node->var_value->stptr;
Packit Service f629e6
	len = -subseplen;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < count; i++) {
Packit Service f629e6
		n = force_string(arg->a_node);
Packit Service f629e6
		len += n->stlen + subseplen;
Packit Service f629e6
		tmp[i] = n;
Packit Service f629e6
		arg = arg->next;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	emalloc(str, char *, len + 1, "concat_args");
Packit Service f629e6
	n = tmp[0];
Packit Service f629e6
	memcpy(str, n->stptr, n->stlen);
Packit Service f629e6
	p = str + n->stlen;
Packit Service f629e6
	for (i = 1; i < count; i++) {
Packit Service f629e6
		if (subseplen == 1)
Packit Service f629e6
			*p++ = *subsep;
Packit Service f629e6
		else if (subseplen > 0) {
Packit Service f629e6
			memcpy(p, subsep, subseplen);
Packit Service f629e6
			p += subseplen;
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		n = tmp[i];
Packit Service f629e6
		memcpy(p, n->stptr, n->stlen);
Packit Service f629e6
		p += n->stlen;
Packit Service f629e6
	}
Packit Service f629e6
	str[len] = '\0';
Packit Service f629e6
	efree(tmp);
Packit Service f629e6
	return make_str_node(str, len, ALREADY_MALLOCED);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* find_command --- find the index in 'cmdtab' using exact,
Packit Service f629e6
 *                  abbreviation or unique partial match
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static int
Packit Service f629e6
find_command(const char *token, size_t toklen)
Packit Service f629e6
{
Packit Service f629e6
	char *name, *abrv;
Packit Service f629e6
	int i, k;
Packit Service f629e6
	bool try_exact = true;
Packit Service f629e6
	int abrv_match = -1;
Packit Service f629e6
	int partial_match = -1;
Packit Service f629e6
Packit Service f629e6
#if 'a' == 0x81 /* it's EBCDIC */
Packit Service f629e6
	/* make sure all lower case characters in token (sorting
Packit Service f629e6
	 * isn't the solution in this case)
Packit Service f629e6
	 */
Packit Service f629e6
	for (i = 0; i < toklen; i++) {
Packit Service f629e6
		if (token[i] != tolower(token[i]))
Packit Service f629e6
			return -1;
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	k = sizeof(cmdtab)/sizeof(cmdtab[0]) - 1;
Packit Service f629e6
	for (i = 0; i < k; i++) {
Packit Service f629e6
		name = (char *) cmdtab[i].name;
Packit Service f629e6
		if (try_exact && *token == *name
Packit Service f629e6
				&& toklen == strlen(name)
Packit Service f629e6
				&& strncmp(name, token, toklen) == 0
Packit Service f629e6
		)
Packit Service f629e6
			return i;
Packit Service f629e6
Packit Service f629e6
		if (*name > *token || i == (k - 1))
Packit Service f629e6
			try_exact = false;
Packit Service f629e6
Packit Service f629e6
		if (abrv_match < 0) {
Packit Service f629e6
			abrv = cmdtab[i].abbrvn;
Packit Service f629e6
			if (abrv[0] == token[0]) {
Packit Service f629e6
				if (toklen == 1 && ! abrv[1])
Packit Service f629e6
					abrv_match = i;
Packit Service f629e6
				else if (toklen == 2 && abrv[1] == token[1])
Packit Service f629e6
					abrv_match = i;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
		if (! try_exact && abrv_match >= 0)
Packit Service f629e6
			return abrv_match;
Packit Service f629e6
		if (partial_match < 0) {
Packit Service f629e6
			if (*token == *name
Packit Service f629e6
					&& toklen < strlen(name)
Packit Service f629e6
					&& strncmp(name, token, toklen) == 0
Packit Service f629e6
			) {
Packit Service f629e6
				if ((i == k - 1 || strncmp(cmdtab[i + 1].name, token, toklen) != 0)
Packit Service f629e6
					&& (i == 0 || strncmp(cmdtab[i - 1].name, token, toklen) != 0)
Packit Service f629e6
				)
Packit Service f629e6
					partial_match = i;
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	return partial_match;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* do_help -- help command */
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
do_help(CMDARG *arg, int cmd)
Packit Service f629e6
{
Packit Service f629e6
	int i;
Packit Service f629e6
	if (arg == NULL) {
Packit Service f629e6
		initialize_pager(out_fp);
Packit Service f629e6
		if (setjmp(pager_quit_tag) == 0) {
Packit Service f629e6
			for (i = 0; cmdtab[i].name != NULL; i++) {
Packit Service f629e6
				gprintf(out_fp, "%s:\n", cmdtab[i].name);
Packit Service f629e6
				gprintf(out_fp, "\t%s\n", _(cmdtab[i].help_txt));
Packit Service f629e6
			}
Packit Service f629e6
		}
Packit Service f629e6
	} else if (arg->type == D_string) {
Packit Service f629e6
		char *name;
Packit Service f629e6
		name = arg->a_string;
Packit Service f629e6
		i = find_command(name, strlen(name));
Packit Service f629e6
		if (i >= 0) {
Packit Service f629e6
			fprintf(out_fp, "%s\n", cmdtab[i].help_txt);
Packit Service f629e6
			if (strcmp(cmdtab[i].name, "option") == 0)
Packit Service f629e6
				option_help();
Packit Service f629e6
		} else
Packit Service f629e6
			fprintf(out_fp, _("undefined command: %s\n"), name);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return false;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_LIBREADLINE
Packit Service f629e6
Packit Service f629e6
/* next_word --- find the next word in a line to complete
Packit Service f629e6
 *               (word seperation characters are space and tab).
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
next_word(char *p, int len, char **endp)
Packit Service f629e6
{
Packit Service f629e6
	char *q;
Packit Service f629e6
	int i;
Packit Service f629e6
Packit Service f629e6
	if (p == NULL || len <= 0)
Packit Service f629e6
		return NULL;
Packit Service f629e6
	for (i = 0; i < len; i++, p++)
Packit Service f629e6
		if (*p != ' ' && *p != '\t')
Packit Service f629e6
			break;
Packit Service f629e6
	if (i == len)
Packit Service f629e6
		return NULL;
Packit Service f629e6
	if (endp != NULL) {
Packit Service f629e6
		for (i++, q = p + 1; i < len; i++, q++)
Packit Service f629e6
			if (*q == ' ' || *q == '\t')
Packit Service f629e6
				break;
Packit Service f629e6
		*endp = q;
Packit Service f629e6
	}
Packit Service f629e6
	return p;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* command_completion --- attempt to complete based on the word number in line;
Packit Service f629e6
 *    try to complete on command names if this is the first word; for the next
Packit Service f629e6
 *    word(s), the type of completion depends on the command name (first word).
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#ifndef RL_READLINE_VERSION		/* < 4.2a */
Packit Service f629e6
#define rl_completion_matches(x, y) completion_matches((char *) (x), (y))
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
char **
Packit Service f629e6
command_completion(const char *text, int start, int end)
Packit Service f629e6
{
Packit Service f629e6
	char *cmdtok, *e;
Packit Service f629e6
	int idx;
Packit Service f629e6
	int len;
Packit Service f629e6
Packit Service f629e6
	rl_attempted_completion_over = true;	/* no default filename completion please */
Packit Service f629e6
Packit Service f629e6
	this_cmd = D_illegal;
Packit Service f629e6
	len = start;
Packit Service f629e6
	if ((cmdtok = next_word(rl_line_buffer, len, &e)) == NULL)	/* no first word yet */
Packit Service f629e6
		return  rl_completion_matches(text, command_generator);
Packit Service f629e6
	len -= (e - rl_line_buffer);
Packit Service f629e6
Packit Service f629e6
	idx = find_command(cmdtok, e - cmdtok);
Packit Service f629e6
	if (idx < 0)
Packit Service f629e6
		return NULL;
Packit Service f629e6
	this_cmd = cmdtab[idx].type;
Packit Service f629e6
Packit Service f629e6
	if (! next_word(e, len, NULL)) {
Packit Service f629e6
		switch (this_cmd) {
Packit Service f629e6
		case D_break:
Packit Service f629e6
		case D_list:
Packit Service f629e6
		case D_until:
Packit Service f629e6
		case D_tbreak:
Packit Service f629e6
		case D_clear:
Packit Service f629e6
			return rl_completion_matches(text, srcfile_generator);
Packit Service f629e6
		case D_info:
Packit Service f629e6
		case D_enable:
Packit Service f629e6
		case D_trace:
Packit Service f629e6
		case D_help:
Packit Service f629e6
			return rl_completion_matches(text, argument_generator);
Packit Service f629e6
		case D_option:
Packit Service f629e6
			return rl_completion_matches(text, option_generator);
Packit Service f629e6
		case D_print:
Packit Service f629e6
		case D_printf:
Packit Service f629e6
		case D_set:
Packit Service f629e6
		case D_display:
Packit Service f629e6
		case D_watch:
Packit Service f629e6
			return rl_completion_matches(text, variable_generator);
Packit Service f629e6
		default:
Packit Service f629e6
			return NULL;
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (this_cmd == D_print || this_cmd == D_printf)
Packit Service f629e6
		return rl_completion_matches(text, variable_generator);
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* command_generator --- generator function for command completion */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
command_generator(const char *text, int state)
Packit Service f629e6
{
Packit Service f629e6
	static size_t textlen;
Packit Service f629e6
	static int idx = 0;
Packit Service f629e6
	char *name;
Packit Service f629e6
Packit Service f629e6
	if (! state) {	/* first time */
Packit Service f629e6
		textlen = strlen(text);
Packit Service f629e6
		idx = 0;
Packit Service f629e6
	}
Packit Service f629e6
	while ((name = (char *) cmdtab[idx].name) != NULL) {
Packit Service f629e6
		idx++;
Packit Service f629e6
		if (strncmp(name, text, textlen) == 0)
Packit Service f629e6
			return estrdup(name, strlen(name));
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* srcfile_generator --- generator function for source file completion */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
srcfile_generator(const char *text, int state)
Packit Service f629e6
{
Packit Service f629e6
	static size_t textlen;
Packit Service f629e6
	static SRCFILE *s;
Packit Service f629e6
	char *name;
Packit Service f629e6
	extern SRCFILE *srcfiles;
Packit Service f629e6
Packit Service f629e6
	if (! state) {	/* first time */
Packit Service f629e6
		textlen = strlen(text);
Packit Service f629e6
		s = srcfiles->next;
Packit Service f629e6
	}
Packit Service f629e6
	while (s != srcfiles) {
Packit Service f629e6
		if (s->stype != SRC_FILE && s->stype != SRC_INC) {
Packit Service f629e6
			s = s->next;
Packit Service f629e6
			continue;
Packit Service f629e6
		}
Packit Service f629e6
		name = s->src;
Packit Service f629e6
		s = s->next;
Packit Service f629e6
		if (strncmp(name, text, textlen) == 0)
Packit Service f629e6
			return estrdup(name, strlen(name));
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* argument_generator --- generator function for non-number argument completion */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
argument_generator(const char *text, int state)
Packit Service f629e6
{
Packit Service f629e6
	static size_t textlen;
Packit Service f629e6
	static int idx;
Packit Service f629e6
	const char *name;
Packit Service f629e6
Packit Service f629e6
	if (! state) {	/* first time */
Packit Service f629e6
		textlen = strlen(text);
Packit Service f629e6
		idx = 0;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (this_cmd == D_help) {
Packit Service f629e6
		while ((name = cmdtab[idx++].name) != NULL) {
Packit Service f629e6
			if (strncmp(name, text, textlen) == 0)
Packit Service f629e6
				return estrdup(name, strlen(name));
Packit Service f629e6
		}
Packit Service f629e6
	} else {
Packit Service f629e6
		while ((name = argtab[idx].name) != NULL) {
Packit Service f629e6
			if (this_cmd != argtab[idx++].cmd)
Packit Service f629e6
				continue;
Packit Service f629e6
			if (strncmp(name, text, textlen) == 0)
Packit Service f629e6
				return estrdup(name, strlen(name));
Packit Service f629e6
		}
Packit Service f629e6
	}
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* variable_generator --- generator function for variable name completion */
Packit Service f629e6
Packit Service f629e6
static char *
Packit Service f629e6
variable_generator(const char *text, int state)
Packit Service f629e6
{
Packit Service f629e6
	static size_t textlen;
Packit Service f629e6
	static int idx = 0;
Packit Service f629e6
	static NODE *func = NULL;
Packit Service f629e6
	static NODE **vars = NULL;
Packit Service f629e6
	const char *name;
Packit Service f629e6
	NODE *r;
Packit Service f629e6
Packit Service f629e6
	if (! state) {	/* first time */
Packit Service f629e6
		textlen = strlen(text);
Packit Service f629e6
		if (vars != NULL)
Packit Service f629e6
			efree(vars);
Packit Service f629e6
		vars = variable_list();
Packit Service f629e6
		idx = 0;
Packit Service f629e6
		func = get_function();  /* function in current context */
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* function params */
Packit Service f629e6
	while (func != NULL) {
Packit Service f629e6
		if (idx >= func->param_cnt) {
Packit Service f629e6
			func = NULL;	/* don't try to match params again */
Packit Service f629e6
			idx = 0;
Packit Service f629e6
			break;
Packit Service f629e6
		}
Packit Service f629e6
		name = func->fparms[idx++].param;
Packit Service f629e6
		if (strncmp(name, text, textlen) == 0)
Packit Service f629e6
			return estrdup(name, strlen(name));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* globals */
Packit Service f629e6
	while ((r = vars[idx++]) != NULL) {
Packit Service f629e6
		name = r->vname;
Packit Service f629e6
		if (strncmp(name, text, textlen) == 0)
Packit Service f629e6
			return estrdup(name, strlen(name));
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return NULL;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* history_expand_line ---  history expand the LINE */
Packit Service f629e6
Packit Service f629e6
static void
Packit Service f629e6
history_expand_line(char **line)
Packit Service f629e6
{
Packit Service f629e6
	int ret;
Packit Service f629e6
	char *expansion;
Packit Service f629e6
Packit Service f629e6
	if (! *line || input_fd != 0 || ! input_from_tty)
Packit Service f629e6
		return;
Packit Service f629e6
	using_history();
Packit Service f629e6
	ret = history_expand(*line, &expansion);
Packit Service f629e6
	if (ret < 0 || ret == 2)
Packit Service f629e6
		efree(expansion);
Packit Service f629e6
	else {
Packit Service f629e6
		efree(*line);
Packit Service f629e6
		*line = expansion;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#endif