/*
 * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
 */
#include <lcrash.h>

/*
 * task_cmd() -- Run the 'task' command.
 */
int
task_cmd(command_t *cmd)
{
	int i, task_cnt = 0, mode, first_time = TRUE;
	void *tsp;
	kaddr_t task;
	uint64_t value;
	char *s;

	/* Reset the error. */
	kl_reset_error();
	if (cmd->nargs == 0) {
		if (MIP->core_type == dev_kmem) {
			if (cmd->flags & C_RUNABLE) {
				s = "RUNABLE TASKS:\n\n";
			} else if (cmd->flags & C_UNRUNABLE) {
				s = "UNRUNABLE TASKS:\n\n";
			} else if (cmd->flags & C_STOPPED) {
				s = "STOPPED TASKS:\n\n";
			} else {
				s = "ACTIVE TASKS:\n\n";
			}
			fprintf(cmd->ofp, s);
		}
		task_cnt = print_active_tasks(cmd->flags, cmd->ofp);
	} else {
		tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP);
		if (KL_ERROR) {
			return(1);
		}
	        for (i = 0; i < cmd->nargs; i++) {
			kl_get_value(cmd->args[i], &mode, 0, &value);
			if (KL_ERROR) {
				continue;
			}
			task = (kaddr_t)value;
			if (first_time || (cmd->flags & (C_FULL|C_NEXT))) {
				task_struct_banner(cmd->ofp, BANNER|SMAJOR);
				first_time = FALSE;
			}

			if ((mode == 1) || (mode == 2)) {
				unsigned int state;

				if (kl_get_task_struct(task, mode, tsp)) {
					continue;
				}
				if (mode == 1) {
					task = kl_pid_to_task(task);
				}
				state = KL_UINT(tsp, "task_struct", "state");
				if (!(cmd->flags &
					(C_RUNABLE|C_UNRUNABLE|C_STOPPED)) ||
					((cmd->flags & C_RUNABLE) && (state == 0)) ||
					((cmd->flags & C_UNRUNABLE) && (state < 0)) ||
					((cmd->flags & C_STOPPED) && (state > 0))) {
						print_task_struct(task, tsp,
							cmd->flags, cmd->ofp);
						task_cnt++;
				}
			} else {
				fprintf(KL_ERRORFP, "Invalid task : "
					"0x%lx\n", (long unsigned int )task);
			}
		}
		kl_free_block(tsp);
	}
	if (task_cnt) {
		task_struct_banner(cmd->ofp, SMAJOR);
	}
	if (cmd->flags & C_RUNABLE) {
		s = "runable task struct";
	} else if (cmd->flags & C_UNRUNABLE) {
		s = "unrunable task struct";
	} else if (cmd->flags & C_STOPPED) {
		s = "stopped task struct";
	} else {
		s = "active task struct";
	}
	PLURAL(s, task_cnt, cmd->ofp);
	return(0);
}

#define _TASK_USAGE "[-f] [-n] [-w outfile] [-t runable|unrunable|stopped|all] [task list]"


/*
 * task_usage() -- Print the usage string for the 'task' command.
 */
void
task_usage(command_t *cmd)
{
	CMD_USAGE(cmd, _TASK_USAGE);
}

/*
 * task_help() -- Print the help information for the 'task' command.
 */
void
task_help(command_t *cmd)
{
	CMD_HELP(cmd, _TASK_USAGE,
		"Display relevant information for each entry in task_list. If "
		"no entries are specified, display information for all active "
		"tasks.  If the -t flag is given, only runable, unrunable, or "
		"stopped tasks are displayed.  Entries in task_list can take  "
		"the form of a virtual address or a PID (following a '#').");
}

/*
 * task_parse() -- Parse the command line arguments for 'task'.
 */
int
task_parse(command_t *cmd)
{
option_t *op;
char *flag;

	if (set_cmd_flags(cmd, (C_FULL|C_NEXT|C_WRITE), "t:")) {
		return(1);
	}
	op = cmd->options;
	while (op) {
		if (op->op_char != 't') {
			goto cont;
		}
		flag = op->op_arg;
		if (!strcmp(flag, "run") || !strcmp(flag, "runable")) {
			cmd->flags |= C_RUNABLE;
		} else if (!strcmp(flag, "unrun") || !strcmp(flag, "unrunable")) {
			cmd->flags |= C_UNRUNABLE;
		} else if (!strcmp(flag, "stop") || !strcmp(flag, "stopped")) {
			cmd->flags |= C_STOPPED;
		} else if (strcmp(flag, "all")) {
			fprintf(cmd->efp, "%s:  invalid type option.\n", flag);
			return 1;
		}
cont:
		op = op->op_next;
	}
	return(0);
}

/*
 * task_complete() -- Complete arguments of 'task' command.
 */
char *
task_complete(command_t *cmd)
{
	char *ret;

	/* complete standard options (for example, -w option) arguments
	 */
	if ((ret = complete_standard_options(cmd)) != NOT_COMPLETED) {
		return(ret);
	}
	fprintf(cmd->ofp, "\n");
	task_usage(cmd);
	return(DRAW_NEW_ENTIRE_LINE);
}
