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

#define MAX_ARGS	128
#define MAX_CMDLINE 	256

#define CMD_USAGE(cmd, s) \
    fprintf(cmd->ofp, "USAGE: %s %s\n", cmd->command, s);

typedef struct option_s {
	struct option_s	       *op_next;
	char			op_char;
	char		       *op_arg;
} option_t;

typedef struct command_s {
	int			flags;
	char 			cmdstr[MAX_CMDLINE];
	char 		       *command;
	char		       *cmdline;
	option_t	       *options; 
	int 			nargs;
	char   	       	       *args[MAX_ARGS];
	char 		       *pipe_cmd;
	FILE   	       	       *ofp;
	FILE		       *efp;
} command_t;

typedef int(*cmdfunc_t) (command_t *);
typedef int(*cmdparse_t) (command_t *);
typedef void(*cmdhelp_t) (command_t *);
typedef void(*cmdusage_t) (command_t *);
typedef char *(*cmdcomplete_t) (command_t *);

typedef struct _command {
	char           *cmd;  	  /* command name */
	char   	       *real_cmd; /* real command name if cmd is alias */
	cmdfunc_t	cmdfunc;  /* base function */
	cmdparse_t 	cmdparse; /* argument parsing function  */
	cmdhelp_t 	cmdhelp;  /* help function */
	cmdusage_t	cmdusage; /* usage string function */
	cmdcomplete_t	cmdcomplete; /* completion function */
} _command_t;

extern _command_t cmdset[];

/* Internal data structure that contains vital information about a 
 * command. Unlike with _command_t, cmd_rec_s structs are inserted
 * into a binary search tree, using command name as the search key.
 * The command tree contains all commands, including those that are
 * part of lcrash by default and those that are registered at runtime.
 */
typedef struct cmd_rec_s {
        btnode_t                bt;        /* Must be first */
        struct cmd_rec_s       *real_cmd;
        cmdfunc_t               cmdfunc;   /* base function */
        cmdparse_t              cmdparse;  /* argument parsing function  */
        cmdhelp_t               cmdhelp;   /* help function */
        cmdusage_t              cmdusage;  /* usage string function */
        cmdcomplete_t           cmdcomplete; /* completion function */
} cmd_rec_t;

#define cmd_name bt.bt_key

extern cmd_rec_t *cmd_tree;

/* Function prototypes
 */
int register_cmd(
	char *			/* command name */,
	char *			/* real command name if this is an alias */,
	int			/* command argument flag */,
	cmdfunc_t 		/* base function */,
	cmdparse_t		/* argument parsing function  */,
	cmdhelp_t		/* help function */,
	cmdusage_t 		/* usage string function */);

int process_commands(void);

void unregister_cmd(char *name);

cmd_rec_t *find_cmd_rec(char *);

cmd_rec_t *first_cmd_rec(void);

cmd_rec_t *last_cmd_rec(void);

cmd_rec_t *next_cmd_rec(
	cmd_rec_t *);

cmd_rec_t *prev_cmd_rec(
	cmd_rec_t *);

#define BANNER		   1
#define SMAJOR		   2
#define SMINOR		   4

/* Standard LCRASH command line flags. There is no requirement that
 * they be used, but it is possible to use them in conjunction with
 * command specific flags (as long as the flag bits do not conflict.
 */
#define C_FALSE         0x00000001   /* Command takes no arguments */
#define C_TRUE          0x00000002   /* Command requires arguments */
#define C_ALL           0x00000004   /* All elements */
#define C_PERM		0x00000008   /* Allocate perminant blocks */
#define C_TEMP			 0   /* For completeness */
#define C_FULL          0x00000010   /* Full output */
#define C_LIST          0x00000020   /* List items */
#define C_NEXT          0x00000040   /* Follow links */
#define C_WRITE         0x00000080   /* Write output to file */
#define C_NO_OPCHECK    0x00000100   /* Don't reject bad cmd line options */

/* Shift value so that commands can define their own local command line 
 * option flags that don't conflict with the standard ones defined above.
 */
#define C_LFLG_SHFT	  12

/* "Local" flags for use by dump_memory(), eval.c module, etc.
 */
#define C_DECIMAL  	(0x0001 << C_LFLG_SHFT)  /* dump memory in decimal */
#define C_OCTAL    	(0x0002 << C_LFLG_SHFT)  /* dump memory in octal */ 
#define C_HEX      	(0x0004 << C_LFLG_SHFT)  /* dump memory in hex */
#define C_BINARY      	(0x0008 << C_LFLG_SHFT)  /* dump memory in binary */
#define C_INSTR      	(0x0010 << C_LFLG_SHFT)  /* dump instruction */
#define C_DWORD    	(0x0020 << C_LFLG_SHFT)  /* Eight byte values */
#define C_WORD     	(0x0040 << C_LFLG_SHFT)  /* Four byte values */
#define C_HWORD    	(0x0080 << C_LFLG_SHFT)  /* two byte values */
#define C_BYTE     	(0x0100 << C_LFLG_SHFT)  /* byte values */ 
#define C_SIZEOF        (0x0200 << C_LFLG_SHFT)  /* eval flag */
#define C_WHATIS        (0x0400 << C_LFLG_SHFT)  /* eval flag */
#define C_NOVARS        (0x0800 << C_LFLG_SHFT)  /* eval flag */
#define C_PADDR         (0x1000 << C_LFLG_SHFT)  /* address is physical */
#define C_RUNABLE      (0x2000 << C_LFLG_SHFT)  /* runable task flag */
#define C_UNRUNABLE    (0x8000 << C_LFLG_SHFT)  /* unrunable task flag */
#define C_STOPPED      (0x10000 << C_LFLG_SHFT)         /* stopped task flag */

/* "Local" flag for use by some commands to pass iteration threshold 
 */
#define C_ITER          (0x1000 << C_LFLG_SHFT)  /* set iteration threshold */

/* "Local" flags for use by walk_structs() 
 */
#define C_STRUCT	(0x01 << C_LFLG_SHFT)  /* dump C-like struct */
#define C_LISTHEAD_N    (0x04 << C_LFLG_SHFT)  /* walk using list_head.next */
#define C_LISTHEAD_P    (0x08 << C_LFLG_SHFT)  /* walk using list_head. prev */
#define C_LISTHEAD      (C_LISTHEAD_N | C_LISTHEAD_P) /* use struct list_head */
#define C_PDSTRUCT      (0x10 << C_LFLG_SHFT)  /* handle "predefined" struct */
#define C_TABLE         (0x20 << C_LFLG_SHFT)  /* output of "list_head-walk" */
                                               /*    in short tabular format */


/* Plural flag definitions.
 */
#define PLURAL(str, cnt, ofp) \
	fprintf(ofp, "%d %s%s found\n", cnt, str, (cnt != 1) ? "s" : "");

#define CMD_HELP(cmd, u, s) \
    char *t = helpformat(s); \
    fprintf(cmd->ofp, "COMMAND: %s %s\n\n%s\n", cmd->command, u, t); \
    kl_free_block(t);

/* Function prototypes
 */
int set_cmd_flags(command_t *, int, char *);
char *helpformat(char *);
int process_cmds(void);
int register_cmds(_command_t *);
char *complete_cmds(char *, int);
char *complete_subcmd_name(char *);
char *complete_standard_options(command_t *);
char *complete_symbol_name(char *, int);
char *complete_file_name(char *, int);

#define NOT_COMPLETED	(char *)-2

