/* Quake-style Command Processor */
/* Malloc-less environment. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#define crumb printf

#define CBUFSIZE 16384  /* Size of command buffer. */
#define CMDLEN 64       /* Length of a command name. */
#define MAXCMDS 256     /* Maximum commands in command lookup table. */


typedef enum parse_e {
  START,
  TOKEN,
  QUOTE,
  SEMICOMMENT,
  COMMENT,
  TOKENSEMICOMMENT,
  STOP,
} parse_t;


struct cmdproc_s;  /* forward-declare. */

typedef int (*cmd_f)(struct cmdproc_s *);


/* ringbuffer. */
typedef struct ringbuffer_s {
  /* append text at tail, retrieve text from head. */
  int max;
  int head, tail;
  char buf[CBUFSIZE];
} ringbuffer_t;

/* command arguments. */
typedef struct cmdarg_s {
  int count;
  char arguments[CBUFSIZE];  /* Flat space of strings. */
  char *vector[MAXCMDS];    /* array of pointers into arguments. */
  const char *argstr;      /* arguments string, verbatim copy starting on second token. */
} cmdarg_t;

typedef struct cmdlookup_s {
  int used;           /* in-use */
  cmd_f cmdfunc;      /* Function pointer. */
  char cmdname [CMDLEN];  /* Command name, case-insensitive. */
} cmdlookup_t;

typedef struct cmdproc_s {
  ringbuffer_t cbuf;      /* command buffer. */
  cmdarg_t cmdarg;        /* command arguments. */
  cmdlookup_t lu[MAXCMDS];   /* command lookup table. */
  int maxlu;  /* maximum lookups. */
  char extract[CBUFSIZE];
  int suspend;            /* suspend/wait counter */

  int (*printf)(struct cmdproc_s *, const char *, ...);   /* Output function, formatted. */
  int (*putstr)(struct cmdproc_s *, const char *);        /* Output function, unformatted. */
} cmdproc_t;



/* Command Processor methods. */
int cmdproc_append (cmdproc_t *self, const char *text);
int cmdproc_insert (cmdproc_t *self, const char *text);
int cmdproc_register (cmdproc_t *self, const char *cmdname, cmd_f cmdfunc);
int cmdproc_deregister (cmdproc_t *self, const char *cmdname);
int cmdproc_execute (cmdproc_t *self, const char *text);
int cmdproc_cycle (cmdproc_t *self);

/* Command Processor arguments. */
int cmdproc_argc (cmdproc_t *self);
const char * cmdproc_args (cmdproc_t *self);
const char * cmdproc_argv (cmdproc_t *self, int n);

/* Built-in commands. */
int cmd_crash (cmdproc_t *self);
int cmd_cmdlist (cmdproc_t *self);
int cmd_echo (cmdproc_t *self);
int cmd_exec (cmdproc_t *self);
int cmd_wait (cmdproc_t *self);

/* Processor initialization. */
cmdproc_t * cmdproc_init (cmdproc_t *self);
