/* $Revision: 1.2 $ */

#ifndef lint
static char vcid[] = "0.4";
#endif /* lint */

#include <hwdefs.h>
#include <cpu.h>
#include <kern.h>
#include <sem.h>
#include <shell.h>
#include <string.h>
#include <stdio.h>
#include <lcd.h>
#include <beep.h>
#include <trap.h>
#include <string.h>

#define DEFAULT_STACK_SIZE 8192
extern tcb_t *cur_task; /* for trapdummy() */

#define SHELL_PRI	1000	/* pretty high */
char            shell_stack[DEFAULT_STACK_SIZE];

/* TestTask */
extern          test_task()  ;
char            test_stack[DEFAULT_STACK_SIZE+20*1024];
tcb_t           test_tcb;
char 		out[80];

extern char    *optarg;
extern int      optind;

/* aus hsrec.c */
extern u_long Srecord();


u_long test_init(int argc, char **argv) ;
void reset() ;


#define MAX_ARGS 10

static cmd_t    builtins[] =
{
  {"help", "", help, "help command"},
  {"?", "", help, "help command"},
  {"ps", "", ps, "list status of all tasks"},
  {"md", "addr len", md, "display memory"},
  {"trap", "num", do_trap, "trap instruction"},
  {"test", "string", test_init , "a test Task"},
  {"srec", "", Srecord , "download an Srecord"},
  {"restart", "", reset , "Restart the System"},
  {0}
};

u_long help(void){
  cmd_t          *cp = builtins;
  
  kprintf("%20s %20s   %30s\n",
	  "COMMAND", "ARGUMENTS", "DESCRIPTION");
  while (cp->name) {
    if (cp->help)
      kprintf("%20s %20s   %30s\n",
	      cp->name, cp->args ? cp->args : "", cp->help);
    cp++;
  }
  return 1 ;
}

u_long md(int argc, char **argv){
  if (argc < 3) {
    kprintf("usage: md addr len\n");
    return 0 ;
  }
  dump(atoi(argv[1]), atoi(argv[2]));
  return 1 ;
}

u_long do_trap(int argc, char **argv){
  if (argc < 2) {
    kprintf("usage: trap num\n");
    return 0 ;
  }
  trap(atoi(argv[1]));
  return 1 ;
}

cmd_t * valid_cmd(char *s){
  cmd_t          *cp = builtins;
  int             len;

  if (!s)
    return 0;
  while (cp->name) {
    len = strlen(cp->name);
    if (strncmp(cp->name, s, len) == 0)
      return cp;
    cp++;
  }
  return 0;
}


char * skip_spaces(char *str){
  if (!str)
    return 0;
  while (*str && isspace(*str))
    str++;
  if (*str)
    return str;
  return 0;
}

ULONG exec_cmd(cmd_t * cp, char *arg){
  int             len;
  int             i;
  char           *save;
  char           *argv[MAX_ARGS + 1];

  if (!cp->func)
    return 0;
  if (!arg)
    return 0;
  len = strlen(cp->name);
  arg += len;
  argv[0] = cp->name;
  for (i = 1; i < MAX_ARGS; i++) {
    arg = skip_spaces(arg);
    if (arg) {
      save = argv[i] = arg;
      if ( (arg = index(arg, ' ')) ) {
	argv[i][arg - save] = '\0';
	arg++;
      }
    } else
      break;
  }
  argv[i] = 0;
  return (*cp->func) (i, argv);
}

void shell_init(void) {
  tcb_t * shell_tcb ;
  if ( (shell_tcb = spawn("shell", shell_stack,shell_task, sizeof(shell_stack), SHELL_PRI, 0) ) == NULL)
    panic("shell_init: spawn failed for shell\n");
  exec(shell_tcb);
}

int t_printf( int num ){
  printf("trap #%d\n" , num ) ;
  return 0 ;
}

int trapdummy( int num ){
  return 0 ;
}



int shell_task(void){
  int i ;
  ULONG cmdretval = 0UL;
  char            buf[BUFSIZ];	/* XXX */
  char           *cp = buf;
  cmd_t          *kp;

  lcd_init();

  lprintf("-- Free V 0.2 --\n-  For Krabat  -" ) ;

  for( i=0 ; i < 80 ; i++ )
    kprintf("*");
  kprintf("\n");
  kprintf("--- Free For Krabat Version %s           ---\n" , vcid );
  kprintf("--- Compiled with GNU CC on Linux 2.0.33 ---\n" );
  for( i=0 ; i < 80 ; i++ )
    kprintf("*");
  kprintf("\n");

  trap_connect( (USER_TRAP_0) , t_printf, 0 ) ;
  for( i = 1 ; i < 16 ; i ++ ){
    trap_connect( (USER_TRAP_0) + i, trapdummy, i) ;
  }

  for (;;) {
    kprintf("> ");
    if (readline(cp) < 0)
      continue;
    if ( (kp = valid_cmd(cp)) ){
      cmdretval = exec_cmd(kp, cp);
      if ( ! cmdretval ){
	kprintf("%s failed.\n" , cp );
      }else{
	kprintf("%s successfully returned %d.\n" , cp , cmdretval );
      }
    }
    else
      if (strlen(cp))
	kprintf("Invalid command <%s>\n", cp);
  }
}

void backspace(void) {
  kputchar('');
  kputchar(' ');
  kputchar('');
}

int readline(char *s) {
  char           *cp = s;
  char            ch = '\0';
  int i ; 
  
  while (!isnewline(ch)) {
    while((i=getchar())<0) 
      ;
    *cp++ = ch = i ;
    switch (ch) {
    case '':	/* bs */
    case 0x7f:	/* del */
      if (--cp > s) {
	backspace();
	cp--;
      }
      break;
    case '':
      while (--cp > s)
	backspace();
      break;
    case '':
      return -1;
    default:
      kputchar(ch);
      break;
    }
  }
  *--cp = '\0';
  return (int) (cp - s);
}

u_long test_init(int argc, char **argv){
  tcb_t * test_tcb  = spawn( "test"
		    , test_stack
		    , test_task
		    , DEFAULT_STACK_SIZE+22*1024
		    , SHELL_PRI-1
		    , 0) ;
  if ( test_tcb == NULL ){
    printf("test_init: spawn failed for %s\n", test_tcb->tcb_name );
    return FALSE ;
  }
  else{
    strcpy(out , argv[1] ) ;
    exec(test_tcb);
  }
  return TRUE ;
}

void reset(){
  asm(" movea.l #0x101000,%a0");
  asm(" jmp %a0@");
}
