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

void print_usage(command_t *);

/*
 * print_cmd() -- Dump out type information.
 */
int
print_cmd(command_t *cmd)
{
	int i, j = 0;
	uint64_t flags = 0;
	char *buf, *next, *end, *exp;
	node_t *np;

	/* If there is nothing to evaluate, just return
	 */
	if (cmd->nargs == 0) {
		return(0);
	}

	/* Set up the flags value. If this command was invoked via
	 * pd, px, or po, then make sure the appropriate flag is set. 
	 */
        if (!strcmp(cmd->command, "pd")) {
		cmd->flags &= ~(C_HEX|C_OCTAL);
                cmd->flags |= C_DECIMAL;
        } else if (!strcmp(cmd->command, "px")) {
		cmd->flags &= ~(C_OCTAL|C_BINARY);
                cmd->flags |= C_HEX;
        } else if (!strcmp(cmd->command, "po")) {
		cmd->flags &= ~(C_HEX|C_BINARY);
                cmd->flags |= C_OCTAL;
        } else if (!strcmp(cmd->command, "pb")) {
		cmd->flags &= ~(C_HEX|C_OCTAL);
                cmd->flags |= C_BINARY;
        }
	if (cmd->flags & C_HEX) {
		flags = K_HEX;
	} else if (cmd->flags & C_OCTAL) {
		flags = K_OCTAL;
	} else if (cmd->flags & C_BINARY) {
		flags = K_BINARY;
	}

	/* Count the number of bytes necessary to hold the entire expression
	 * string.
	 */
	for (i = 0; i < cmd->nargs; i++) {
		j += (strlen(cmd->args[i]) + 1);
	}

	/* Allocate space for the expression string and copy the individual
	 * arguments into it.
	 */
	buf = (char *)kl_alloc_block(j, K_TEMP);
	for (i = 0; i < cmd->nargs; i++) {
		strcat(buf, cmd->args[i]);
		if ((i + 1) < cmd->nargs) {
			strcat(buf, " ");
		}
	}

	/* Walk through the expression string, expression by expression.
	 * Note that a comma (',') is the delimiting character between
	 * expressions.
	 */
	next = buf;
	while (next) {
		if ((end = strchr(next, ','))) {
			*end = (char)0;
		}

		/* Copy the next expression to a separate expression string.
		 * A seperate expresison string is necessary because it is 
		 * likely to get freed up in eval() when variables get expanded.
		 */
		exp = (char *)kl_alloc_block(strlen(next) + 1, K_TEMP);
		strcpy(exp, next);

		/* Evaluate the expression
		 */
		np = eval(&exp, 0);
		if (!np || eval_error) {
			print_eval_error(cmd->command, exp,
				(error_token ? error_token : (char*)NULL), 
				eval_error, CMD_NAME);
			if (np) {
				free_nodes(np);
			}
			kl_free_block((void *)buf);
			kl_free_block((void *)exp);
			free_eval_memory();
			return(1);
		}
		if (print_eval_results(np, cmd->ofp, flags)) {
			free_nodes(np);
			kl_free_block((void *)buf);
			free_eval_memory();
			return(1);
		}
		kl_free_block((void *)exp);

		if (end) {
			next = end + 1;
			fprintf(cmd->ofp, " ");
		} else {
			next = (char*)NULL;
			fprintf(cmd->ofp, "\n");
		}
		free_nodes(np);
	}
	kl_free_block((void *)buf);
	free_eval_memory();
	return(1);
}

#define _PRINT_USAGE "[-d] [-o] [-x] [-b] [-w outfile] expression"
#define _PD_USAGE "[-w outfile] expression"
#define _PX_USAGE "[-w outfile] expression"
#define _PO_USAGE "[-w outfile] expression"
#define _PB_USAGE "[-w outfile] expression"

/*
 * print_usage() -- Print the usage string for the 'print' command.
 */
void
print_usage(command_t *cmd)
{
	if (!strcmp(cmd->command, "pd")) {
		CMD_USAGE(cmd, _PD_USAGE);
	} else if (!strcmp(cmd->command, "px")) {
		CMD_USAGE(cmd, _PX_USAGE);
	} else if (!strcmp(cmd->command, "po")) {
		CMD_USAGE(cmd, _PO_USAGE);
	} else if (!strcmp(cmd->command, "pb")) {
		CMD_USAGE(cmd, _PB_USAGE);
	} else {
		CMD_USAGE(cmd, _PRINT_USAGE);
	}
}

/*
 * print_help() -- Print the help information for the 'print' command.
 */
void
print_help(command_t *cmd)
{
	CMD_HELP(cmd, _PRINT_USAGE,
		"Evaluate an expression and print the result. An "
		"expression can consist of numeric values, operators, "
		"typedefs, struct/union members, symbols, or a "
		"combination of the above. Following are some examples "
		"of valid expressions:\n\n"
		"    (((2*3+4/2)*2+(2/6))/2)"
		"\n\n"
		"    ((struct task_struct *)0xc5c14000)->comm"
		"\n\n"
		"    (*((struct task_struct *)0xc5c14000)->files.fd)."
		"f_flags & 0x8000"
		"\n\n"
		"The pd command is the same as the print command "
		"except that it forces all integers to be displayed as "
		"decimal values."
		"\n\n"
		"The px command is the same as the print command "
		"except that it forces all integers to be displayed as "
		"hexadecimal values."
		"\n\n"
		"The po command is the same as the print command "
		"except that it forces all integers to be displayed as "
		"octal values."
		"\n\n"
		"The pb command is the same as the print command "
		"except that it forces all integer values to be "
		"displayed as binary values. Note that only single "
		"values (numbers, members of structures, etc.) will "
		"be displayed in binary form. Integer values in "
		"complex data types such as structures will be "
		"displayed as decimal values.");
}

/*
 * print_parse() -- Parse the command line arguments for 'print'.
 */
int
print_parse(command_t *cmd)
{
	option_t *op;

	if ((cmd->command[1] == 'd') || (cmd->command[1] == 'x') || 
			(cmd->command[1] == 'o') || (cmd->command[1] == 'b')) {
        	return(set_cmd_flags(cmd, (C_TRUE|C_WRITE|C_NO_OPCHECK), ""));
	} 
        if (set_cmd_flags(cmd, (C_TRUE|C_WRITE|C_NO_OPCHECK), "doxb")) {
                return(1);
        }
        op = cmd->options;
        while (op) {
                switch(op->op_char) {
                        case 'd':
                                cmd->flags |= C_DECIMAL;
                                break;

                        case 'o':
                                cmd->flags |= C_OCTAL;
                                break;

                        case 'x':
                                cmd->flags |= C_HEX;
                                break;

                        case 'b':
                                cmd->flags |= C_BINARY;
                                break;
                }
                op = op->op_next;
	}
	return(0);
}

/*
 * print_complete() -- Complete arguments of 'print' command.
 */
char *
print_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");
	print_usage(cmd);
	return(DRAW_NEW_ENTIRE_LINE);
}
