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

#define C_OFLAG (1 << C_LFLG_SHFT)

void sizeof_usage(command_t*);

/*
 * sizeof_cmd() -- Find an item in the symbol table that is either
 *                 a struct, field, etc.
 */
int
sizeof_cmd(command_t *cmd)
{
	int i, size, offset;
	char *ptr0, *ptr1, *ptr2;
	char *typestring;

        if (!strcmp(cmd->command, "offset")) {
                cmd->flags |= C_OFLAG;
	}
	for (i = 0; i < cmd->nargs; i++) {
		offset = -1;
		typestring = ptr0 = kl_str_to_block(cmd->args[i], K_TEMP);
		if ((ptr1 = strtok(cmd->args[i], "."))) {
			if ((ptr2 = strtok(NULL, "."))) {
				size = kl_member_size(ptr1, ptr2);
				if(cmd->flags & C_OFLAG) {
					offset = kl_member_offset(ptr1, ptr2);
				}
				if(strtok(NULL,".")) {
					fprintf(cmd->efp,
						"Invalid command line.\n");
					sizeof_usage(cmd);
					return(1);
				}
			} else {
				/* catch case of multiterm types */
				if((ptr2 = strtok(ptr1, "\""))) {
					typestring = ptr2;
					size = kl_struct_len(ptr2);
				} else {
					size = kl_struct_len(ptr1);
				}
			}
		} else {
			size = kl_struct_len(ptr1);
		}
		if (size) {
			if(cmd->flags & C_OFLAG) {
				if(offset > -1){
					fprintf(cmd->ofp, "Offset: %d bytes.\n",
						offset);
				} else {
					fprintf(cmd->efp, "ERROR: Could not "
						"determine offset for %s.\n",
						typestring);
				}
			} else {
				fprintf(cmd->ofp, "Size of \"%s\": %d bytes\n", 
					typestring, size);
			}
		} else if (ptr2) {
			if (kl_is_member(ptr1, ptr2)) {
				fprintf(cmd->ofp, "Size of \"%s\": %d bytes\n", 
					typestring, size);
			} else {
				fprintf(cmd->efp, "%s: structure/field not "
					"found.\n", typestring);
			}
		} else {
			fprintf(cmd->efp, "%s: type info not found.\n",
				typestring);
		}
		kl_free_block(ptr0);
	}
	return(0);
}

#define _SIZEOF_USAGE \
"\n        type | structure.field [...]"\
"\n        -o structure.field [...]"\
"\n        [-w outfile]"

#define _OFFSET_USAGE \
"\n        structure.field [...]"\
"\n        [-w outfile]"

#define _SIZEOF_HELP \
"Display size of data types in bytes. Additionally display offsets for\n"\
"members of structs.\n"\
"\nOPTIONS:"\
"\n type | structure.field [...]"\
"\n       Print size of types (basic types, structs, typedefs) or"\
"\n       member of structures in bytes."\
"\n -o structure.field [...]"\
"\n       Determine the member offset. Only arguments of the form"\
"\n       'structure.field' are allowed.\n"\
"\nTo request size for multi-worded types (e.g. \"short int\") specify the"\
"\ntype whithin \"\".\n"\
"\nNote: An alias \"offset\" exists for the calling sequence \"sizeof -o\"."

/* #define _OFFSET_HELP \ */
/* "Display offsets for members of structs.\n"\ */
/* "\"offset\" is an alias for \"sizeof -o\"\n"  */

/*
 * sizeof_usage() -- Print the usage string for the 'sizeof' command.
 */
void
sizeof_usage(command_t *cmd)
{
	if(!strcmp(cmd->command,"offset")){
		CMD_USAGE(cmd, _OFFSET_USAGE);
	} else {
	CMD_USAGE(cmd, _SIZEOF_USAGE);
	}
}

/*
 * sizeof_help() -- Print the help information for the 'sizeof' command.
 */
void
sizeof_help(command_t *cmd)
{
/* 	if(!strcmp(cmd->command, "offset")){ */
/* 		CMD_HELP(cmd, _OFFSET_USAGE, _OFFSET_HELP); */
/* 	} else { */
	CMD_HELP(cmd, _SIZEOF_USAGE, _SIZEOF_HELP);
/* 	} */
}

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

	if (set_cmd_flags(cmd, (C_WRITE|C_TRUE|C_NEXT), "o")) {
		return(1);
	}
	op = cmd->options;
	while (op) {
		switch(op->op_char) {
			case 'o':
				cmd->flags |= C_OFLAG;
		}
		op = op->op_next;
	}

	return(0);
}

/*
 * sizeof_complete() -- Complete arguments of 'sizeof' command.
 */
char *
sizeof_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");
	sizeof_usage(cmd);
	return(DRAW_NEW_ENTIRE_LINE);
}
