/* xyz */

/*
 * Copyright (c) 1991, 1992, 1993, 1994, 1995 by Wayne C. Gramlich.
 * All rights reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * for any purpose is hereby granted without fee provided that the above
 * copyright notice and this permission are retained.  The author makes
 * no representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 */

/* The command loop for the debugger: */

#ifndef ERROR_EXPORTS_H
#include "error_exports.h"
#endif

#ifndef FILE_DEFS_H
#include "file_defs.h"
#endif

#ifndef HEAP_EXPORTS_H
#include "heap_exports.h"
#endif

#ifndef LINT_H
#include "lint.h"
#endif

#ifndef LIBC_EXPORTS_H
#include "libc_exports.h"
#endif

#ifndef ROUTINE_INFO_DEFS_H
#include "routine_info_defs.h"
#endif

#ifndef RUN_TIME_DEFS_H
#include "run_time_defs.h"
#endif

#ifndef STHEADERS_H
#include "stheaders.h"
#endif

#ifndef STR_EXPORTS_H
#include "str_exports.h"
#endif

#ifndef UNIX_ASSERT_H
#include "unix_assert.h"
#endif

#ifndef UNIX_CTYPE_H
#include "unix_ctype.h"
#endif

/* #ifndef UNIX_DLFCN_H */
/* #include "unix_dlfcn.h" */
/* #endif */

#ifndef UNIX_FCNTL_H
#include "unix_fcntl.h"
#endif

#ifndef UNIX_MEMORY_H
#include "unix_memory.h"
#endif

#ifndef UNIX_SYS_STAT_H
#include "unix_sys_stat.h"
#endif

#ifndef UNIX_STDLIB_H
#include "unix_stdlib.h"
#endif

#ifndef UNIX_UNISTD_H
#include "unix_unistd.h"
#endif

#ifndef VECTOR_DEFS_H
#include "vector_defs.h"
#endif

typedef void *Out_stream;

Out_stream out_stream__standard;	/* Total kludge (common symbol */

extern Run_time run__time__global;

LOCAL void	alias_command(Run_time);
LOCAL int	alias_compare(Alias, Alias, int);
LOCAL void	button_command(Run_time);
LOCAL void	cd_command(Run_time);
LOCAL int	continue_command(Run_time);
LOCAL void	debug_command(Run_time);
LOCAL void	delete_command(Run_time);
LOCAL void	echo_command(Run_time);
LOCAL void	help_command(Run_time);
LOCAL void	in_command(Run_time);
LOCAL void	module_command(Run_time);
LOCAL void	out_command(Run_time);
LOCAL void	print_command(Run_time);
LOCAL void	printenv_command(Run_time);
LOCAL void	quit_command(Run_time);
LOCAL void	rerun_command(Run_time);
LOCAL void	run_command(Run_time);
LOCAL void	setenv_command(Run_time);
LOCAL void	show_command(Run_time);
LOCAL void	source_command(Run_time);
LOCAL void	stack_command(Run_time);
LOCAL void	status_command(Run_time);
LOCAL int	step_command(Run_time);
LOCAL int	step_in_command(Run_time);
LOCAL int	step_out_command(Run_time);
LOCAL int	step_over_command(Run_time);
LOCAL int	step_to_command(Run_time);
LOCAL void	stop_at_command(Run_time);
LOCAL void	stop_command(Run_time);
LOCAL void	stop_in_command(Run_time);
LOCAL void	unalias_command(Run_time);
LOCAL void	unbutton_command(Run_time);
LOCAL void	undebug_command(Run_time);
LOCAL void	unstop_at_command(Run_time);
LOCAL void	unstop_command(Run_time);
LOCAL void	unstop_in_command(Run_time);
LOCAL void	unsetenv_command(Run_time);

/*
 * alias_command(run_time)
 *	This routine will parse and execute an alias command.
 */
LOCAL void
alias_command(
	Run_time	run_time)
{
	Alias		alias;
	Vec(Alias)	aliases;
	Str		command;
	int		index;
	Str		name;
	int		size;

	if (run__time__eol_test(run_time)) {
		run__time__eol_read(run_time);
		aliases = run_time->aliases;
		vec_sort(Alias, aliases, alias_compare, 0);
		size = vec_size(Alias, aliases);
		for (index = 0; index < size; index++) {
			alias = vec_fetch(Alias, aliases, index);
			(void)printf("%8s - %s\n", alias->name, alias->command);
		}
	} else {
		name = run__time__argument_read(run_time, "No alias name");
		command = run__time__argument_read(run_time, "No alias value");
		run__time__eol_read(run_time);
		if (command != (Str)0) {
			run__time__alias_set(run_time, name, command);
		}
	}
}

/*
 * alias_compare(alias1, alias2, zilch)
 *	This routine will return -1, 0, or 1, depending upon whether the
 *	name of "alias1" is lexically less than, equal to, or greater than
 *	the name of "alias2".
 */
/* ARGSUSED */
LOCAL int
alias_compare(
	Alias		alias1,
	Alias		alias2,
	int		zilch)
{
	return strcmp(alias1->name, alias2->name);
}

/*
 * button_command(run_time)
 *	This routine will parse and execute a button command.
 */
LOCAL void
button_command(
	Run_time	run_time)
{
	Str		button_name;
	Dbx_button	selection;
	Str		selection_name;
	int		chr;

	selection_name = run__time__argument_read(run_time,
				"No selection specified");
	chr = run__time__chr_non_white_peek(run_time);
	if ((chr == '"') || (chr == '\'')) {
		button_name = run__time__string_read(run_time,
				"No button name specified");
	} else {
		button_name = run__time__argument_read(run_time,
				"No button name specfied");
	}
	run__time__eol_read(run_time);
	if (button_name == (Str)0) {
		/* Error already printed */
		return;
	}
	if (strequal(selection_name, "ignore")) {
		selection = Dbx_button_ignore;
	} else if (strequal(selection_name, "expand")) {
		selection = Dbx_button_expand;
	} else if (strequal(selection_name, "literal")) {
		selection = Dbx_button_literal;
	} else {
		(void)fprintf(stderr, "`%s' is not a valid button selection; "
		    "try `ignore' instead!\n", selection_name);
		return;
	}
	run__time__button(run_time, button_name, selection);
}

/*
 * cd_command(run_time)
 *	This routine will parse and execute a cd command.
 */
LOCAL void
cd_command(
	Run_time	run_time)
{
	char		buffer[2000];
	Str		directory;

	directory = run__time__argument_read(run_time,
					     "No directory specified");
	run__time__eol_read(run_time);
	if (chdir(directory) != 0) {
		(void)fprintf(stderr, "Could not change directory to `%s'!\n",
		    directory);
		return;
	}
	assert(getcwd(buffer, sizeof buffer) != (Str)0);
	run_time->directory = strdupl(buffer, run_time->heap);
	if (run_time->last_in_file != (Stdio)0) {
		(void)fclose(run_time->last_in_file);
	}
	run_time->last_file_name = (Str)0;
	run_time->last_in_file = (Stdio)0;
	run_time->last_module = (module___object *)0;
}

/*
 * continue_command(run_time)
 *	This routine will parse and execute a continue command.
 */
LOCAL int
continue_command(
	Run_time		run_time)
{
	activation___object	*activation;
	routine___object	*routine;
	routine__info__type	routine_info;

	run__time__eol_read(run_time);
	run_time->run_mode = Run_mode_continue;
	activation = run_time->leaf_activation;
	if (activation == (activation___object *)0) {
		return 1;
	}
	routine = activation->routine;
	routine_info = run__time__routine_info_get(run_time, routine);
	activation->breakpoints = routine_info->breakpoints;
	return 1;
}

/*
 * debug_command(run_time)
 *	This routine will parse and execute a debug command.
 */
LOCAL void
debug_command(
	Run_time	run_time)
{
	char		command[2000];
	int		fd;
	Stdio		pipe_file;
	Str		program;

	/* Read in the program name: */
	program = run__time__argument_read(run_time,
					   "No program name specified");
	run__time__eol_read(run_time);
	if (program == (Str)0) {
		/* Error already printed. */
		return;
	}

	/* Verify that the file exists: */
	fd = open(program, O_RDONLY, 0);
	if (fd < 0) {
		(void)fprintf(stderr, "`%s' does not appear to be a program!\n",
			      program);
		return;
	}
	(void)close(fd);

#ifdef OLD
	/* Verify that the file is linked w/libstipple.so: */
	(void)sprintf(command,
		      "ldd %s | grep libstipple", program);
	pipe_file = popen(command, "r");
	assert(pipe_file != (Stdio)0);
	if (getc(pipe_file) == EOF) {
		(void)fprintf(stderr,
			      "Program `%s' does not appear "
			      "to be a STIPPLE program!\n",
			      program);
		return;
	}
	(void)fclose(pipe_file);
#endif /* OLD */

	/* We should close all extraneous fd's here! */

	/* Exec the program: */
	run__time__env_state_set(run_time, Std_state_ready);
	run__time__env_str_set(run_time, "STD_ARGC", "0");
	run__time__env_str_set(run_time, "STD_NAME", program);
	run__time__env_int_set(run_time, "STD_PIPE", run_time->pipe_fd);
	run__time__exec(run_time);
	assert_fail();
}

/*
 * delete_command(run_time)
 *	This routine will parse and execute a delete command.
 */
LOCAL void
delete_command(
	Run_time	run_time)
{
	Event		event;
	Vec(Event)	events;
	int		event_number;
	int		size;

	event_number = run__time__int_read(run_time, "No event number");
	run__time__eol_read(run_time);
	if (event_number < 0) {
		/* Error already printed */
		return;
	}
	events = run_time->events;
	size = vec_size(Event, events);
	if (event_number <= size) {
		event = vec_fetch(Event, events, event_number - 1);
		if (event->file_name != (Str)0) {
			event->file_name = (Str)0;
			return;
		}
	}
	(void)fprintf(stderr, "There is no event %d!\n", event_number);
}

/*
 * echo_command(run_time)
 *	This routine will parse and execute an echo command.
 */
LOCAL void
echo_command(
	Run_time	run_time)
{
	Str		arg;
	Vec(Str)	args;
	int		index;
	int		size;

	args = vec_create(Str, run_time->heap);
	while (!run__time__eol_test(run_time)) {
		arg = run__time__argument_read(run_time, "No argument");
		vec_append(Str, args, arg);
	}
	run__time__eol_read(run_time);
	(void)printf("echo");
	size = vec_size(Str, args);
	for (index = 0; index < size; index++) {
		arg = vec_fetch(Str, args, index);
		(void)printf(" %s", arg);
	}
	(void)printf("\n");
}

/*
 * help_command(run_time)
 *	This routine will parse and execute the help command.
 */
LOCAL void
help_command(
	Run_time	run_time)
{
	Str		*cmds;
	Debug_cmd	debug_cmd;
	Str		*helps;

	run__time__eol_read(run_time);
	cmds = &run_time->debug_cmds[0];
	helps = &run_time->debug_help[0];
	for (debug_cmd = (Debug_cmd)0;
	     debug_cmd < Debug_cmd_last; debug_cmd++) {
		(void)printf("%10s - %s\n", cmds[(int)debug_cmd],
			     helps[(int)debug_cmd]);
	}
}

/*
 * in_command(run_time)
 *	This routine will parse and execute an in command.
 */
LOCAL void
in_command(
	Run_time	run_time)
{
	activation___object	*activation;

	run__time__eol_read(run_time);
	if (run_time->leaf_activation == run_time->current_activation) {
		(void)fprintf(stderr, "Already at deepest frame!\n");
		return;
	}
	for (activation = run_time->leaf_activation;
	     activation != (activation___object *)0;
	     activation = activation->previous) {
		if (activation->previous == run_time->current_activation) {
			run_time->current_activation = activation;
			break;
		}
	}
}

/*
 * module_command(run_time)
 *	This routine will parse and execute a module command.
 */
LOCAL void
module_command(
	Run_time	run_time)
{
	int		index;
	module___object	*module;
	Vec(module___object *) modules;
	Str		module_name;
	int		size;

	modules = run_time->modules;
	size = vec_size(module___object, modules);
	if (run__time__eol_test(run_time)) {
		/* List all modules: */
		run__time__eol_read(run_time);
		for (index = 0; index < size; index++) {
			module = vec_fetch(module___object *, modules, index);
			(void)printf("%s %s\n", module->module_name,
				     module->file_name);
		}
	} else {
		/* Goto a selected module: */
		module_name = run__time__argument_read(run_time,
						"No module name specified");
		run__time__eol_read(run_time);
		if (module_name == (Str)0) {
			/* Error already printed */
			return;
		}
		for (index = 0; index < size; index++) {
			module = vec_fetch(module___object *, modules, index);
			if (strequal(module->module_name, module_name)) {
				break;
			}
		}
		if (index >= size) {
			(void)fprintf(stderr,"Could not find module `%s'!\n",
				      module_name);
		} else {
			(void)printf("Found it!\n");
		}
	}
}

/*
 * out_command(run_time)
 *	This routine will parse and execute an out command.
 */
LOCAL void
out_command(
	Run_time		run_time)
{
	activation___object	*activation;

	run__time__eol_read(run_time);
	activation = run_time->current_activation;
	if (activation->previous == (activation___object *)0) {
		(void)fprintf(stderr, "Already at main()!\n");
		return;
	}
	activation = activation->previous;
	run_time->current_activation = activation;
}

/*
 * print_command(run_time)
 *	This routine will parse and print a print command.
 */
LOCAL void
print_command(
	Run_time		run_time)
{
	activation___object	*activation;
	int			index;
	routine___object	*routine;
	int			size;
	Str			var_name;
	variable___object	*variable;
	variable___object	*variables;

	var_name = run__time__argument_read(run_time, "No variable specified");
	run__time__eol_read(run_time);
	if (var_name == (Str)0) {
		/* Error already printed */
		return;
	}
	activation = run_time->current_activation;
	routine = activation->routine;
	variables = routine->variables;
	size = routine->variables_count;
	for (index = 0; index < size; index++) {
		variable = &variables[index];
		if ((variable->kind == variable__kind__return) ||
		    !strequal(var_name, variable->name)) {
			continue;
		}
		(void)printf("%s = ", var_name);
		run_time->run_mode = Run_mode_continue;
		switch (variable->flavor) {
		    case variable__flavor__unparam:
		      {
			print__unparam__routine print_routine;

			print_routine = (print__unparam__routine)
						variable->print_routine;
			run__time__signals_enable();
			(*print_routine)(
			    *((void **)((int)activation->frame +
					variable->offset)),
			    (void *)out_stream__standard);
			run__time__signals_disable();
			break;
		      }
		    case variable__flavor__static:
		      {
			print__proc__var *print_routine;

			print_routine = *((print__proc__var **)
					       variable->print_routine);
			run__time__signals_enable();
			(*print_routine->routine)(
			    *((void **)((int)activation->frame +
					variable->offset)),
			    (void *)out_stream__standard,
			    print_routine->block);
			run__time__signals_disable();
			break;
		      }
		    case variable__flavor__block:
		      {
			print__proc__var *print_routine;
			void		*block;

			block = *((void **)activation->frame);
			print_routine = *( (print__proc__var **)((int)block +
					    (int)variable->print_routine) );
			run__time__signals_enable();
			(*print_routine->routine)(
			    *((void **)((int)activation->frame +
					variable->offset)),
			    (void *)out_stream__standard,
			    print_routine->block);
			run__time__signals_disable();
			break;
		      }
		    default:
			assert_fail();
		}
		(void)printf("\n");
		return;
	}
	(void)fprintf(stderr, "`%s' is not a valid variable!\n", var_name);
}

/*
 * printenv_command(run_time)
 *	This routine will parse and print a printenv command.
 */
LOCAL void
printenv_command(
	Run_time	run_time)
{
	extern Str	*environ;
	Str		env_var;
	Str		*env_vars;

	run__time__eol_read(run_time);
	env_vars = environ;
	while ((env_var = *env_vars++) != (Str)0) {
		(void)printf("%s\n", env_var);
	}
}

/*
 * pwd_command(run_time)
 *	This routine will parse and execute a pwd command.
 */
LOCAL void
pwd_command(
	Run_time	run_time)
{
	char		directory[2000];

	run__time__eol_read(run_time);
	if (getcwd(directory, sizeof(directory)) == (Str)0) {
		(void)fprintf(stderr,
			      "Could not get current working directory!\n");
	} else {
		(void)printf("%s\n", directory);
	}
}

/*
 * quit_command(run_time)
 *	This routine will parse and execute a quit command.
 */
LOCAL void
quit_command(
	Run_time	run_time)
{
	extern void _exit(int);

	run__time__eol_read(run_time);
	run__time__pipe_command(run_time, Dbxtool_cmd_quit);
	run__time__pipe_integer(run_time, 0);
	_exit(0);
}

/*
 * rerun_command(run_time)
 *	This routine will parse and execut a rerun command.
 */
LOCAL void
rerun_command(
	Run_time	run_time)
{
	run__time__eol_read(run_time);
	run__time__env_state_set(run_time, Std_state_running);
	run__time__env_int_set(run_time, "STD_ARGC", 0);
	run__time__exec(run_time);
}

/*
 * run_command(run_time)
 *	This routine will parse and execute a run command.
 */
LOCAL void
run_command(
	Run_time	run_time)
{
	Str		arg;
	int		argc;
	char		env_var_name[50];

	argc = 0;
	for (;;) {
		if (run__time__eol_test(run_time)) {
			break;
		}
		arg = run__time__argument_read(run_time, "<Internal error>");
		(void)sprintf(env_var_name, "STD_ARG%d", argc);
		run__time__env_str_set(run_time, env_var_name, arg);
		argc++;
	}
	run__time__eol_read(run_time);
	if (argc > 0) {
		run__time__env_int_set(run_time, "STD_ARGC", argc);
	}
	run__time__env_state_set(run_time, Std_state_running);
	run__time__exec(run_time);
}

/*
 * setenv_command(run_time)
 *	This routine will parse and execute a setenv command.
 */
LOCAL void
setenv_command(
	Run_time	run_time)
{
	int		chr;
	Str		name;
	Str		value;

	name = run__time__argument_read(run_time,
				"No environment variable name specified");
	chr = run__time__chr_non_white_peek(run_time);
	if ((chr == '\'') || (chr == '"')) {
		value = run__time__string_read(run_time,
				"Bad environment variable value");
	} else {
		value = run__time__argument_read(run_time,
				"Bad environment variable value");
	}
	run__time__eol_read(run_time);
	if (value != (Str)0) {
		run__time__env_str_set(run_time, name, value);
	}
}

/*
 * show_command(run_time)
 *	This routine will parse and execute a show command.
 */
LOCAL void
show_command(
	Run_time	run_time)
{
	run__time__eol_read(run_time);
	(void)fprintf(stderr, "`show' not implemented yet!\n");
}

/*
 * source_command(run_time)
 *	This routine will parse and execute a source command.
 */
LOCAL void
source_command(
	Run_time	run_time)
{
	int		duplicate;
	Vec(File)	in_file_stack;
	Str		file_name;
	File		new_in_file;
	int		index;
	int		size;
	File		tmp_in_file;

	in_file_stack = run_time->in_file_stack;
	file_name = run__time__argument_read(run_time,
			"No source file name specified");
	run__time__eol_read(run_time);
	if (file_name == (Str)0) {
		/* Error already printed! */
		return;
	}

	/* Don't permit recursive source statements: */
	duplicate = strequal(file_name,
			     run_time->in_file->file_name);
	size = vec_size(File, in_file_stack);
	for (index = 0; index < size; index++) {
		tmp_in_file =
		    vec_fetch(File, in_file_stack, index);
		if (strequal(file_name,
			     tmp_in_file->file_name)) {
			duplicate = 1;
			break;
		}
	}
	if (duplicate) {
		(void)fprintf(stderr,
			"Recursive source commands are not permitted (%s)!\n",
			file_name);
		return;
	}

	new_in_file = file_open(file_name, 0, run_time->heap);
	if (new_in_file == (File)0) {
		(void)fprintf(stderr, "Could not open %s\n", file_name);
		return;
	}
	vec_append(File, in_file_stack, run_time->in_file);
	run_time->in_file = new_in_file;
}

/*
 * stack_command(run_time)
 *	This routine will parse and execute a stack command.
 */
LOCAL void
stack_command(
	Run_time	run_time)
{
	activation___object	*activation;
	activation___object	*fault;
	Vec(activation___object *) faults;
	int			fault_index;
	routine___object	*routine;
	routine__info__type	routine_info;

	run__time__eol_read(run_time);
	faults = run_time->faults;
	fault_index = vec_size(activation___object *, faults) - 1;
	for (activation = run_time->leaf_activation;
	     activation != (activation___object *)0;
	     activation = activation->previous) {
		routine = activation->routine;
		if (fault_index < 0) {
			fault = (activation___object *)0;
		} else {
			fault = vec_fetch(activation___object *,
					  faults, fault_index);
		}
		if (activation == fault) {
			(void)printf("--- <Hardware Fault> ---\n");
			fault_index--;
		}
		if (activation == run_time->leaf_activation) {
			(void)printf("=> ");
		} else if (activation == run_time->current_activation){
			(void)printf("-> ");
		} else {
			(void)printf("   ");
		}
		routine_info = routine->routine_info;
		assert(routine_info != (routine__info__type)0);
		(void)printf("%s", routine_info->name);
		if (!strequal(routine_info->type_name, "global__")) {
			(void)printf("@%s", routine_info->type_name);
		}
		(void)printf("()\n");
	}
}

/*
 * status_command(run_time)
 *	This routine will parse and execute the status command.
 */
LOCAL void
status_command(
	Run_time	run_time)
{
	Event		event;
	Vec(Event)	events;
	int		index;
	int		size;

	run__time__eol_read(run_time);
	events = run_time->events;
	size = vec_size(Event, events);
	for (index = 0; index < size; index++) {
		event = vec_fetch(Event, events, index);
		switch (event->event_kind) {
		    case Event_kind_deleted:
			break;
		    case Event_kind_stop_at:
			(void)printf("%3d Stop At \"%s\":%d\n", index + 1,
				     event->file_name, event->line_number);
			break;
		    case Event_kind_stop_in:
			if (strequal(event->type_name, "global__")) {
				(void)printf("%3d Stop In %s\n", index + 1,
					     event->routine_name);
			} else {
				(void)printf("%3d Stop In %s@%s\n", index + 1,
					     event->routine_name,
					     event->type_name);
			}
			break;
		    default:
			assert_fail();
		}
	}
}

/*
 * step_command(run_time)
 *	This routine will parse and execute a stop command.
 */
LOCAL int
step_command(
	Run_time	run_time)
{
	Str		arg;
	int		chr;
	int		result;

	chr = run__time__chr_non_white_peek(run_time);
	if ((chr == '\n') || isdigit(chr)) {
		return step_in_command(run_time);
	}
	arg = run__time__argument_read(run_time,
	   "`step' must be followed by `in', `out', `over', `to', or <number>");
	run__time__lower_case(arg);
	if (arg == (Str)0) {
		/* Error already printed */
		result = 0;
	} else if (strequal(arg, "in")) {
		result = step_in_command(run_time);
	} else if (strequal(arg, "out")) {
		result = step_out_command(run_time);
	} else if (strequal(arg, "over")) {
		result = step_over_command(run_time);
	} else if (strequal(arg, "to")) {
		result = step_to_command(run_time);
	} else {
		(void)fprintf(stderr, "`%s' is not valid after `step'!\n", arg);
		return 0;
	}
	return result;
}

/*
 * step_in_command(run_time)
 *	This routine will parse and execute a step_in command.
 */
LOCAL int
step_in_command(
	Run_time		run_time)
{
	activation___object	*activation;
	routine___object	*routine;

	run__time__eol_read(run_time);
	run_time->run_mode = Run_mode_step_in;
	activation = run_time->leaf_activation;
	if (activation == (activation___object *)0) {
		return 1;
	}
	routine = activation->routine;
	run__time__breakpoints_prepare(run_time, routine);
	activation->breakpoints = run_time->breakpoints_stop;
	return 1;
}

/*
 * step_out_command(run_time)
 *	This routine will parse and execute a step_out command.
 */
LOCAL int
step_out_command(
	Run_time		run_time)
{
	activation___object	*activation;
	routine___object	*routine;

	run__time__eol_read(run_time);
	activation = run_time->leaf_activation;
	routine = activation->routine;
	run__time__breakpoints_prepare(run_time, routine);
	activation->breakpoints = run_time->breakpoints_none;
	run_time->run_mode = Run_mode_step_out;
	run_time->out_activation = activation;
	return 1;
}

/* 
 * step_over_command(run_time)
 *	This routine will parse and execute a step_over command.
 */
LOCAL int
step_over_command(
	Run_time	run_time)
{
	activation___object	*activation;
	routine___object	*routine;

	run__time__eol_read(run_time);
	run_time->run_mode = Run_mode_step_over;
	activation = run_time->leaf_activation;
	if (activation == (activation___object *)0) {
		return 1;
	}
	run_time->over_activation = activation;
	routine = activation->routine;
	run__time__breakpoints_prepare(run_time, routine);
	activation->breakpoints = run_time->breakpoints_stop;
	return 1;
}

/*
 * step_to_command(run_time)
 *	This routine will parse and execute a step_to command.
 */
LOCAL int
step_to_command(
	Run_time	run_time)
{
	/* This code is incomplete: */
	run__time__breakpoint_at(run_time, 1);
	run_time->run_mode = Run_mode_continue;
	return 1;
}

/*
 * stop_at_command(run_time)
 *	This routine will parse and execute a stop_at command.
 */
LOCAL void
stop_at_command(
	Run_time	run_time)
{
	run__time__breakpoint_at(run_time, 1);
}

/*
 * stop_command(run_time)
 *	This routine will parse and execute a stop command.
 */
LOCAL void
stop_command(
	Run_time	run_time)
{
	Str		in_or_at;

	in_or_at = run__time__argument_read(run_time,
				"stop must be followed by either `in' or `at'");
	run__time__lower_case(in_or_at);
	if (in_or_at == (Str)0) {
		/* Error message already printed. */
		run__time__eol_read(run_time);
	} else if (strequal(in_or_at, "at")) {
		run__time__breakpoint_at(run_time, 1);
	} else if (strequal(in_or_at, "in")) {
		run__time__breakpoint_in(run_time, 1);
	} else {
		(void)fprintf(stderr, "`%s' is not `in' or `at'!\n", in_or_at);
		run__time__eol_read(run_time);
	}
}

/*
 * stop_in_command(run_time)
 *	This routine will parse and execute a stop_at command.
 */
LOCAL void
stop_in_command(
	Run_time	run_time)
{
	run__time__breakpoint_in(run_time, 1);
}

/*
 * unalias_command(run_time)
 *	This routine will parse and execute an unalias command.
 */
LOCAL void
unalias_command(
	Run_time	run_time)
{
	Alias		alias;
	Vec(Alias)	aliases;
	int		index;
	Str		name;
	int		size;

	name = run__time__argument_read(run_time, "No alias name specified");
	run__time__eol_read(run_time);
	if (name == (Str)0) {
		/* Error already printed. */
		return;
	}
	aliases = run_time->aliases;
	size = vec_size(Alias, aliases);
	for (index = 0; index < size; index++) {
		alias = vec_fetch(Alias, aliases, index);
		if (strequal(name, alias->name)) {
			break;
		}
	}
	if (index >= size) {
		(void)fprintf(stderr, "`%s' is not in alias table!\n", name);
	} else {
		vec_delete(Alias, aliases, index);
	}
}

/*
 * unbutton_command(run_time)
 *	This routine will parse and execute an unbutton command.
 */
LOCAL void
unbutton_command(
	Run_time	run_time)
{
	Str		button_name;
	int		chr;

	chr = run__time__chr_non_white_peek(run_time);
	if ((chr == '"') || (chr == '\'')) {
		button_name = run__time__string_read(run_time,
					"No button name specified");
	} else {
		button_name = run__time__argument_read(run_time,
					"No button name specfied");
	}
	run__time__eol_read(run_time);
	if (button_name == (Str)0) {
		/* Error already printed */
		return;
	}
	run__time__unbutton(run_time, button_name);
}

/*
 * undebug_command(run_time)
 *	This routine will parse and execute an undebug command.
 */
LOCAL void
undebug_command(
	Run_time	run_time)
{
	run__time__eol_read(run_time);
	run__time__env_state_set(run_time, Std_state_none);
	/* We really should exec std here to free up swap! */
}

/*
 * unsetenv_command(run_time)
 *	This routine will parse and execute an unsetenv command.
 */
LOCAL void
unsetenv_command(
	Run_time	run_time)
{
	Str		name;

	name = run__time__argument_read(run_time,
		"No environment variable specified");
	run__time__eol_read(run_time);
	if (name != (Str)0) {
		if (run__time__env_delete(run_time, name)) {
			(void)fprintf(stderr, "`%s' is not an"
			    " enviroment variable!\n", name);
		}
	}
}

/*
 * unstop_at_command(run_time)
 *	This routine will parse and execute a unstop_at command.
 */
LOCAL void
unstop_at_command(
	Run_time	run_time)
{
	run__time__breakpoint_at(run_time, 0);
}

/*
 * unstop_command(run_time)
 *	This routine will parse and execute an unstop command.
 */
LOCAL void
unstop_command(
	Run_time	run_time)
{
	Str		arg;

	arg = run__time__argument_read(run_time,
				"`unstop' must be followed by `at' or `in'");
	run__time__lower_case(arg);
	if (arg == (Str)0) {
		/* Error already printed. */
		return;
	} else if (strequal(arg, "at")) {
		run__time__breakpoint_at(run_time, 0);
	} else if (strequal(arg, "in")) {
		run__time__breakpoint_in(run_time, 0);
	} else {
		(void)fprintf(stderr,
			      "`%s' is not valid; use `in' or `at' instead!\n",
			      arg);
	}
}

/*
 * unstop_in_command(run_time)
 *	This routine will parse and execute a unstop_at command.
 */
LOCAL void
unstop_in_command(
	Run_time	run_time)
{
	run__time__breakpoint_in(run_time, 0);
}

/*
 * run__time__cmd_loop()
 *	This routine performs the debugger command loop.
 */
void
run__time__cmd_loop(void)
{
	activation___object *activation;
	Alias		alias;
	Vec(Alias)	aliases;
	Str		cmd;
	Str		*cmds;
	activation___object *current_activation;
	Debug_cmd	debug_cmd;
	int		do_prompt;
	Vec(File)	in_file_stack;
	int		index;
	activation___object *last_activation;
	routine___object *routine;
	routine__info__type routine_info;
	Run_time	run_time;
	int		size;

	/* Prompt the user for a command: */
	run__time__signals_disable();
	run_time = run__time__global;
	activation = run_time->leaf_activation;
	if (activation != (activation___object *)0) {
		int		line_number;

		routine = activation->routine;
		routine_info = run__time__routine_info_get(run_time, routine);
		line_number = vec_fetch(int, routine_info->line_numbers,
					activation->breakpoint);
		run__time__line_display(run_time, routine, line_number, 0);
	}
	last_activation = run_time->leaf_activation;
	aliases = run_time->aliases;
	in_file_stack = run_time->in_file_stack;
	cmds = &run_time->debug_cmds[0];
	do_prompt = 1;
	for (;;) {
		current_activation = run_time->current_activation;
		if ((run_time->leaf_activation != (activation___object *)0) &&
		    (current_activation != (activation___object *)0) &&
		    (current_activation != last_activation)) {
			int	breakpoint;
			int	line_number;

			last_activation = run_time->current_activation;
			routine = last_activation->routine;
			routine_info = run__time__routine_info_get(run_time,
								   routine);
			breakpoint = last_activation->breakpoint;
			line_number = vec_fetch(int, routine_info->line_numbers,
						breakpoint);
			run__time__line_display(run_time, routine,
						line_number, 1);
		}
		do_prompt = 1;
		if (vec_empty(File, in_file_stack)) {		
			switch (run_time->eol_chr) {
			    case EOF:
				do_prompt = 0;
				break;
			    case '\n':
				break;
			    case ';':
				do_prompt = 0;
				break;
			    default:
				assert_fail();
			}
		} else {
			do_prompt = 0;
		}
		if (do_prompt) {
			(void)fprintf(stdout, "(std) ");
			(void)fflush(stdout);
		} else if (run_time->echo &&
			   !vec_empty(File, in_file_stack)) {
			(void)fprintf(stdout, "(std%d) ",
				      vec_size(File, in_file_stack));
			(void)fflush(stdout);
		}

		/* Read the command name: */
		if (run__time__eol_test(run_time)) {
			run__time__eol_read(run_time);
			continue;
		}
		cmd = run__time__argument_read(run_time, "Command error");
		if (cmd == (Str)0) {
			run__time__eol_read(run_time);
			continue;
		}

		/* Perform any alias substitution: */
		run__time__lower_case(cmd);
		size = vec_size(Alias, aliases);
		for (index = 0; index < size; index++) {
			alias = vec_fetch(Alias, aliases, index);
			if (strequal(alias->name, cmd)) {
				cmd = alias->command;
				break;
			}
		}

		/* Search for the command: */
		for (debug_cmd = (Debug_cmd)0;
		     debug_cmd < Debug_cmd_last; debug_cmd++) {
			if (strequal(cmd, cmds[(int)debug_cmd])) {
				break;
			}
		}
		if (debug_cmd == Debug_cmd_last) {
			(void)fprintf(stderr,
				      "`%s' is not a valid command!\n", cmd);
			run__time__eol_read(run_time);
			continue;
		}

		/* The following commands are always permitted: */
		switch (debug_cmd) {
		    case Debug_cmd_alias:
			alias_command(run_time);
			continue;
		    case Debug_cmd_button:
			button_command(run_time);
			continue;
		    case Debug_cmd_cd:
			cd_command(run_time);
			continue;
		    case Debug_cmd_debug:
			debug_command(run_time);
			continue;
		    case Debug_cmd_echo:
			echo_command(run_time);
			continue;
		    case Debug_cmd_help:
			help_command(run_time);
			continue;
		    case Debug_cmd_printenv:
			printenv_command(run_time);
			continue;
		    case Debug_cmd_pwd:
			pwd_command(run_time);
			continue;
		    case Debug_cmd_quit:
			quit_command(run_time);
			continue;
		    case Debug_cmd_setenv:
			setenv_command(run_time);
			continue;
		    case Debug_cmd_source:
			source_command(run_time);
			continue;
		    case Debug_cmd_unalias:
			unalias_command(run_time);
			continue;
		    case Debug_cmd_unbutton:
			unbutton_command(run_time);
			continue;
		    case Debug_cmd_unsetenv:
			unsetenv_command(run_time);
			continue;
		}

		/* No other commands are permitted until program is loaded. */
		if (run_time->std_state == Std_state_none) {
			run__time__eol_read(run_time);
			(void)fprintf(stderr, "Please use `debug' command "
					      "to load a program first!\n");
			continue;
		}

		/*
		 * These commands are additionally permitted before and
 		 * after execution.
		 */
		switch (debug_cmd) {
		    case Debug_cmd_delete:
			delete_command(run_time);
			continue;
		    case Debug_cmd_module:
			module_command(run_time);
			continue;
		    case Debug_cmd_rerun:
			rerun_command(run_time);
			continue;
		    case Debug_cmd_run:
			run_command(run_time);
			continue;
		    case Debug_cmd_stack:
			stack_command(run_time);
			continue;
		    case Debug_cmd_status:
			status_command(run_time);
			continue;
		    case Debug_cmd_stop:
			stop_command(run_time);
			continue;
		    case Debug_cmd_stop_at:
			stop_at_command(run_time);
			continue;
		    case Debug_cmd_stop_in:
			stop_in_command(run_time);
			continue;
		    case Debug_cmd_undebug:
			undebug_command(run_time);
			continue;
		    case Debug_cmd_unstop:
			unstop_command(run_time);
			continue;
		    case Debug_cmd_unstop_at:
			unstop_at_command(run_time);
			continue;
		    case Debug_cmd_unstop_in:
			unstop_in_command(run_time);
			continue;
		}

		/* Some commands still work even with a dead program: */
		switch (debug_cmd) {
		    case Debug_cmd_in:
			in_command(run_time);
			continue;
		    case Debug_cmd_out:
			out_command(run_time);
			continue;
		    case Debug_cmd_print:
			print_command(run_time);
			continue;
		    case Debug_cmd_show:
			show_command(run_time);
			continue;
		}

		/* We are either running or the program failed horribly: */
		switch (run_time->std_state) {
		    case Std_state_done:
			(void)fprintf(stderr,
				      "Program execution terminated!\n");
			/* FALLTHRU */
		    case Std_state_ready:
			(void)fprintf(stderr,
				      "Please use `run' or `rerun' command "
				      "to start program execution!\n");
			run__time__eol_read(run_time);
			continue;
		}

		if (run_time->std_state == Std_state_failed) {
			(void)fprintf(stderr,
				      "Program encountered a fatal failure.  "
				      "Execution can not be resumed!\n");
			run__time__eol_read(run_time);
			continue;
		}

		/* We must be running, all other commands are OK: */
		assert(run_time->std_state == Std_state_running);
		switch (debug_cmd) {
		    case Debug_cmd_continue:
			if (continue_command(run_time)) {
				goto resume;
			}
			continue;
		    case Debug_cmd_step:
			if (step_command(run_time)) {
				goto resume;
			}
			continue;
		    case Debug_cmd_step_in:
			if (step_in_command(run_time)) {
				goto resume;
			}
			continue;
		    case Debug_cmd_step_out:
			if (step_out_command(run_time)) {
				goto resume;
			}
			continue;
		    case Debug_cmd_step_over:
			if (step_over_command(run_time)) {
				goto resume;
			}
			continue;
		    case Debug_cmd_step_to:
			if (step_to_command(run_time)) {
				goto resume;
			}
			continue;
		}

		/* All commands should be dispatched by here! */
		assert_fail();
	}
	/* Resume execution: */
    resume:
	run__time__signals_enable();
}

