version 0.5.2
[fw/sdcc] / sim / ucsim / cmd.src / newcmd.cc
index c1ca1db61f3281cb81d2a209f7b50f4f0ce422f0..cf32c05c4f610af5932f7eb0d0be499334679f8e 100644 (file)
@@ -45,12 +45,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <unistd.h>
 #include "i_string.h"
 
+#include "cmdlexcl.h"
+#include "cmdpars.h"
+
 // prj
 #include "globals.h"
+#include "utils.h"
 
 // sim
 #include "simcl.h"
 #include "argcl.h"
+#include "appcl.h"
 
 // local
 #include "newcmdcl.h"
@@ -60,676 +65,67 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 extern "C" int vasprintf(char **strp, const  char *format, va_list ap);
 extern "C" int vsnprintf(char *str, size_t size,const char *format,va_list ap);
 
-static int
-cmd_do_print(FILE *f, char *format, va_list ap)
-{
-  int ret;
-#ifdef HAVE_VASPRINTF
-  char *msg= NULL;
-  vasprintf(&msg, format, ap);
-  ret= fprintf(f, "%s", msg);
-  free(msg);
-#else
-#  ifdef HAVE_VSNPRINTF
-  char msg[80*25];
-  vsnprintf(msg, 80*25, format, ap);
-  ret= fprintf(f, "%s", msg);
-#  else
-#    ifdef HAVE_VPRINTF
-  char msg[80*25];
-  vsprintf(msg, format, ap); /* Dangerous */
-  ret= fprintf(f, "%s", msg);
-#    else
-#      ifdef HAVE_DOPRNT
-  /* ??? */
-  /*strcpy(msg, "Unimplemented printf has called.\n");*/
-#      else
-  /*strcpy(msg, "printf can not be implemented, upgrade your libc.\n");*/
-#      endif
-#    endif
-#  endif
-#endif
-  fflush(f);
-  return(ret);
-}
-
 
 /*
- * Command line
- *____________________________________________________________________________
+ * Options of console
  */
 
-cl_cmdline::cl_cmdline(char *acmd, class cl_console *acon)
-{
-  cmd= strdup(acmd);
-  params= new cl_list(2, 2);
-  tokens= new cl_ustrings(2, 2);
-  name= 0;
-  matched_syntax= 0;
-  con= acon;
-}
-
-cl_cmdline::~cl_cmdline(void)
+cl_prompt_option::cl_prompt_option(class cl_console *console):
+  cl_optref(console)
 {
-  if (cmd)
-    free(cmd);
-  if (name)
-    free(name);
-  delete params;
-  delete tokens;
+  con= console;
 }
 
 int
-cl_cmdline::init(void)
-{
-  split();
+cl_prompt_option::init(void)
+{
+  char *help;
+  help= format_string("Prompt string of console%d", con->get_id());
+  create(con, string_opt, "prompt", help);
+  //fprintf(stderr," **new prompt option %p\"%s\", value=%p str=%p\n",option,object_name(option),option->get_value(),option->get_value()->sval);
+  free(help);
+  default_option("prompt");
+  //fprintf(stderr,"opt=%p\"%s\" value after default set=%p str=%p\n",option,object_name(option),option->get_value(),option->get_value()->sval);
   return(0);
 }
 
-char *
-cl_cmdline::skip_delims(char *start)
-{
-  while (*start &&
-        strchr(" \t\v\r,", *start))
-    start++;
-  return(start);
-}
-
-int
-cl_cmdline::split(void)
-{
-  char *start= cmd;
-  int i;
-
-  name= 0;
-  if (!cmd ||
-      !*cmd)
-    return(0);
-  start+= strspn(start, " \t\v\r,");
-  if (start &&
-      *start == '\n')
-    {
-      name= (char*)malloc(2);
-      strcpy(name, "\n");
-      return(0);
-    }
-  if (!*start)
-    return(0);
-  i= strcspn(start, " \t\v\r,");
-  if (i)
-    {
-      name= (char*)malloc(i+1);
-      strncpy(name, start, i);
-      name[i]= '\0';
-    }
-  start+= i;
-  start= skip_delims(start);
-  // skip delimiters
-  while (*start)
-    {
-      char *end, *param_str;
-      if (*start == '"')
-       {
-         // string
-         start++;
-         end= start;
-         while (*end &&
-                *end != '"')
-           {
-             if (*end == '\\')
-               {
-                 end++;
-                 if (*end)
-                   end++;
-               }
-             else
-               end++;
-           }
-         if (*end == '"')
-           end--;
-         else
-           con->printf("Unterminated string\n");
-         param_str= (char *)malloc(end-start+2);
-         strncpy(param_str, start, 1+end-start);
-         param_str[1+end-start]= '\0';
-         tokens->add(strdup(param_str));
-         params->add(con->sim->mk_cmd_str_arg(param_str));
-         free(param_str);
-         if (*end)
-           end++;
-         if (*end == '"')
-           end++;
-       }
-      else
-       {
-         char *dot;
-         i= strcspn(start, " \t\v\r,");
-         end= start+i;
-         param_str= (char *)malloc(i+1);
-         strncpy(param_str, start, i);
-         param_str[i]= '\0';
-         tokens->add(strdup(param_str));
-         if ((dot= strchr(param_str, '.')) != NULL)
-           {
-             // bit
-             class cl_cmd_arg *sfr, *bit;
-             *dot= '\0';
-             dot++;
-             if (strchr("0123456789", *param_str) != NULL)
-               sfr= con->sim->mk_cmd_int_arg((long long)
-                                              strtol(param_str, 0, 0));
-             else
-               sfr= con->sim->mk_cmd_sym_arg(param_str);
-             if (*dot == '\0')
-               {
-                 bit= 0;
-                 con->printf("Uncomplete bit address\n");
-                 delete sfr;
-               }
-             else
-               {
-                 if (strchr("0123456789", *dot) != NULL)
-                   bit= con->sim->mk_cmd_int_arg((long long)
-                                                  strtol(dot, 0, 0));
-                 else
-                   bit= con->sim->mk_cmd_sym_arg(dot);
-                 params->add(con->sim->mk_cmd_bit_arg(sfr, bit));
-               }
-           }
-         else if ((dot= strchr(param_str, '[')) != NULL)
-           {
-             // array
-             class cl_cmd_arg *aname, *aindex;
-             *dot= '\0';
-             dot++;
-             if (strchr("0123456789", *param_str) != NULL)
-               aname= con->sim->mk_cmd_int_arg((long long)
-                                                strtol(param_str, 0, 0));
-             else
-               aname= con->sim->mk_cmd_sym_arg(param_str);
-             if (*dot == '\0')
-               {
-                 aname= 0;
-                 con->printf("Uncomplete array\n");
-               }
-             else
-               {
-                 char *p;
-                 p= dot + strlen(dot) - 1;
-                 while (p > dot &&
-                        *p != ']')
-                   {
-                     *p= '\0';
-                     p--;
-                   }
-                 if (*p == ']')
-                   *p= '\0';
-                 if (strlen(dot) == 0)
-                   {
-                     con->printf("Uncomplete array index\n");
-                     delete aname;
-                   }
-                 else    
-                   {
-                     if (strchr("0123456789", *dot) != NULL)
-                       aindex= con->sim->mk_cmd_int_arg((long long)
-                                                         strtol(dot, 0, 0));
-                     else
-                       aindex= con->sim->mk_cmd_sym_arg(dot);
-                     params->add(con->sim->mk_cmd_array_arg(aname, aindex));
-                   }
-               }
-           }
-         else if (strchr("0123456789", *param_str) != NULL)
-           {
-             // number
-             params->add(con->sim->mk_cmd_int_arg((long long)
-                                                   strtol(param_str, 0, 0)));
-           }
-         else
-           {
-             // symbol
-             params->add(con->sim->mk_cmd_sym_arg(param_str));
-           }
-         free(param_str);
-       }
-      start= end;
-      start= skip_delims(start);
-    }
-  return(0);
-}
-
-int
-cl_cmdline::shift(void)
-{
-  char *s= skip_delims(cmd);
-
-  free(name);
-  name= NULL;
-  if (s && *s)
-    {
-      while (*s &&
-            strchr(" \t\v\r,", *s) == NULL)
-       s++;
-      s= skip_delims(s);
-      char *p= strdup(s);
-      free(cmd);
-      cmd= p;
-      delete params;
-      params= new cl_list(2, 2);
-      split();
-    }
-  return(name && *name);
-}
-
-int
-cl_cmdline::repeat(void)
-{
-  return(name &&
-        *name == '\n');
-}
-
-class cl_cmd_arg *
-cl_cmdline::param(int num)
-{
-  if (num >= params->count)
-    return(0);
-  return((class cl_cmd_arg *)(params->at(num)));
-}
-
 void
-cl_cmdline::insert_param(int pos, class cl_cmd_arg *param)
-{
-  if (pos >= params->count)
-    params->add(param);
-  else
-    params->add_at(pos, param);
-}
-
-bool
-cl_cmdline::syntax_match(class cl_sim *sim, char *syntax)
+cl_prompt_option::option_changed(void)
 {
-  if (!syntax)
-    return(DD_FALSE);
-  if (!*syntax &&
-      !params->count)
-    {
-      matched_syntax= syntax;
-      return(DD_TRUE);
-    }
-  if (!params->count)
-    return(DD_FALSE);
-  //printf("syntax %s?\n",syntax);
-  char *p= syntax;
-  int iparam= 0;
-  class cl_cmd_arg *parm= (class cl_cmd_arg *)(params->at(iparam));
-  while (*p &&
-        parm)
-    {
-      //printf("Checking %s as %c\n",parm->get_svalue(),*p);
-      switch (*p)
-       {
-       case SY_ADDR:
-         if (!parm->as_address())
-           return(DD_FALSE);
-         //printf("ADDRESS match %lx\n",parm->value.address);
-         break;
-       case SY_NUMBER:
-         if (!parm->as_number())
-           return(DD_FALSE);
-         break;
-       case SY_DATA:
-         if (!parm->as_data())
-           return(DD_FALSE);
-         break;
-       case SY_MEMORY:
-         if (!parm->as_memory())
-           return(DD_FALSE);
-         //printf("MEMORY match %s\n",parm->value.memory->class_name);
-         break;
-       case SY_HW:
-         if (!parm->as_hw(sim->uc))
-           return(DD_FALSE);
-         break;
-       case SY_STRING:
-         if (!parm->as_string())
-           return(DD_FALSE);
-         break;
-       case SY_DATALIST:
-         if (!set_data_list(parm, &iparam))
-           return(DD_FALSE);
-         break;
-       case SY_BIT:
-         if (!parm->as_bit(sim->uc))
-           return(DD_FALSE);
-         break;
-       default:
-         return(DD_FALSE);
-       }
-      p++;
-      iparam++;
-      if (iparam < params->count)
-       parm= (class cl_cmd_arg *)(params->at(iparam));
-      else
-       parm= 0;
-    }
-  if (!*p &&
-      !parm)
-    {
-      matched_syntax= syntax;
-      return(DD_TRUE);
-    }
-  return(DD_FALSE);
-}
-
-bool
-cl_cmdline::set_data_list(class cl_cmd_arg *parm, int *iparm)
-{
-  class cl_cmd_arg *next_parm;
-  int len, i, j;
-  t_mem *array;
-
-  len= 0;
-  array= 0;
-  for (i= *iparm, next_parm= param(i); next_parm; i++, next_parm= param(i))
-    {
-      if (next_parm->is_string())
-       {
-         int l;
-         char *s;
-         //s= proc_escape(next_parm->get_svalue(), &l);
-         if (!next_parm->as_string())
-           continue;
-         s= next_parm->value.string.string;
-         l= next_parm->value.string.len;
-         if (!array)
-           array= (t_mem*)malloc(sizeof(t_mem)*l);
-         else
-           array= (t_mem*)realloc(array, sizeof(t_mem)*(l+len));
-         for (j= 0; j < l; j++)
-           {
-             array[len]= s[j];
-             len++;
-           }
-         //if (s)
-         //free(s);
-       }
-      else
-       {
-         if (!next_parm->as_data())
-           {
-             if (array)
-               free(array);
-             return(DD_FALSE);
-           }
-         if (!array)
-           array= (t_mem*)malloc(sizeof(t_mem));
-         else
-           array= (t_mem*)realloc(array, sizeof(t_mem)*(1+len));
-         array[len]= next_parm->value.data;
-         len++;
-       }
-    }
-  *iparm= i;
-  parm->value.data_list.array= array;
-  parm->value.data_list.len= len;
-  return(DD_TRUE);
-}
-
-
-/*
- * Command
- *____________________________________________________________________________
- */
-
-cl_cmd::cl_cmd(//class cl_sim *asim,
-              char *aname,
-              int can_rep,
-              char *short_hlp,
-              char *long_hlp):
-  cl_base()
-{
-  //sim= asim;
-  names= new cl_strings(1, 1);
-  names->add(aname?strdup(aname):strdup("unknown"));
-  can_repeat= can_rep;
-  short_help= short_hlp?strdup(short_hlp):NULL;
-  long_help= long_hlp?strdup(long_hlp):NULL;
-}
-
-/*cl_cmd::cl_cmd(class cl_sim *asim):
-  cl_base()
-{
-  sim= asim;
-  name= short_help= long_help= 0;
-  can_repeat= 0;
-}*/
-
-cl_cmd::~cl_cmd(void)
-{
-  delete names;
-  if (short_help)
-    free(short_help);
-  if (long_help)
-    free(long_help);
-}
-
-void
-cl_cmd::add_name(char *name)
-{
-  if (name)
-    names->add(strdup(name));
-}
-
-int
-cl_cmd::name_match(char *aname, int strict)
-{
-  int i;
-  
-  if (names->count == 0 &&
-      !aname)
-    return(1);
-  if (!aname)
-    return(0);
-  if (strict)
-    {
-      for (i= 0; i < names->count; i++)
-       {
-         char *n= (char*)(names->at(i));
-         if (strcmp(aname, n) == 0)
-           return(1);
-       }
-    }
-  else
-    {
-      for (i= 0; i < names->count; i++)
-       {
-         char *n= (char*)(names->at(i));
-         if (strstr(n, aname) == n)
-           return(1);
-       }
-    }
-  return(0);
-}
-
-int
-cl_cmd::name_match(class cl_cmdline *cmdline, int strict)
-{
-  return(name_match(cmdline->name, strict));
+  if (!con)
+    return;
+  char *s;
+  option->get_value(&s);
+  con->set_prompt(s);
 }
 
-int
-cl_cmd::syntax_ok(class cl_cmdline *cmdline)
-{
-  return(1);
-}
 
-int
-cl_cmd::work(class cl_sim *sim,
-            class cl_cmdline *cmdline, class cl_console *con)
-{
-  if (!syntax_ok(cmdline))
-    return(0);
-  return(do_work(sim, cmdline, con));
-}
+cl_debug_option::cl_debug_option(class cl_console *console):
+  cl_prompt_option(console)
+{}
 
 int
-cl_cmd::do_work(class cl_sim *sim,
-               class cl_cmdline *cmdline, class cl_console *con)
-{
-  con->printf("Command \"%s\" does nothing.\n", (char*)(names->at(0)));
-  return(0);
-}
-
-
-/*
- * Set of commands
- *____________________________________________________________________________
- */
-
-cl_cmdset::cl_cmdset(class cl_sim *asim):
-  cl_list(5, 5)
-{
-  sim= asim;
-  last_command= 0;
-}
-
-class cl_cmd *
-cl_cmdset::get_cmd(class cl_cmdline *cmdline)
-{
-  int i;
-
-  if (cmdline->repeat())
-    {
-      if (last_command)
-       return(last_command);
-      else
-       return(0);
-    }
-  // exact match
-  for (i= 0; i < count; i++)
-    {
-      class cl_cmd *c= (class cl_cmd *)at(i);
-      if (c->name_match(cmdline, 1))
-       return(c);
-    }
-  // not exact match
-  class cl_cmd *c_matched= 0;
-  for (i= 0; i < count; i++)
-    {
-      class cl_cmd *c= (class cl_cmd *)at(i);
-      if (c->name_match(cmdline, 0))
-       {
-         if (!c_matched)
-           c_matched= c;
-         else
-           return(0);
-       }
-    }
-  return(c_matched);
-  //return(0);
-}
-
-class cl_cmd *
-cl_cmdset::get_cmd(char *cmd_name)
+cl_debug_option::init(void)
 {
-  int i;
-
-  for (i= 0; i < count; i++)
-    {
-      class cl_cmd *c= (class cl_cmd *)at(i);
-      if (c->name_match(cmd_name, 1))
-       return(c);
-    }
+  char *help;
+  help= format_string("Debug messages to console%d", con->get_id());
+  create(con, bool_opt, "debug", help);
+  free(help);
+  default_option("debug");
   return(0);
 }
 
 void
-cl_cmdset::del(char *name)
-{
-  int i;
-
-  if (!name)
-    return;
-  for (i= 0; i < count; i++)
-    {
-      class cl_cmd *cmd= (class cl_cmd *)(at(i));
-      if (cmd->name_match(name, 1))
-       free_at(i);
-    }
-}
-
-void
-cl_cmdset::replace(char *name, class cl_cmd *cmd)
+cl_debug_option::option_changed(void)
 {
-  int i;
-
-  if (!name)
+  if (!con)
     return;
-  for (i= 0; i < count; i++)
-    {
-      class cl_cmd *c= (class cl_cmd *)(at(i));
-      if (c->name_match(name, 1))
-       {
-         delete c;
-         put_at(i, cmd);
-       }
-    }
-}
-
-
-/*
- * Composed command: subset of commands
- *____________________________________________________________________________
- */
-
-cl_super_cmd::cl_super_cmd(//class cl_sim *asim,
-                          char *aname,
-                          int  can_rep,
-                          char *short_hlp,
-                          char *long_hlp,
-                          class cl_cmdset *acommands):
-  cl_cmd(aname, can_rep, short_hlp, long_hlp)
-{
-  commands= acommands;
-}
-
-cl_super_cmd::~cl_super_cmd(void)
-{
-  if (commands)
-    delete commands;
-}
-
-int
-cl_super_cmd::work(class cl_sim *sim,
-                  class cl_cmdline *cmdline, class cl_console *con)
-{
-  class cl_cmd *cmd= 0;
-
-  if (!commands)
-    return(0);
-  
-  if (!cmdline->shift())
-    {
-      if ((cmd= commands->get_cmd("_no_parameters_")) != 0)
-       return(cmd->work(sim, cmdline, con));
-      int i;
-      con->printf("\"%s\" must be followed by the name of a subcommand\n"
-                 "List of subcommands:\n", (char*)(names->at(0)));
-      for (i= 0; i < commands->count; i++)
-       {
-         cmd= (class cl_cmd *)(commands->at(i));
-         con->printf("%s\n", cmd->short_help);
-       }
-      return(0);
-    }
-  if ((cmd= commands->get_cmd(cmdline)) == NULL)
-    {
-      con->printf("Undefined subcommand: \"%s\". Try \"help %s\".\n",
-                 cmdline->name, (char*)(names->at(0)));
-      return(0);
-    }
-  return(cmd->work(sim, cmdline, con));
+  bool b;
+  option->get_value(&b);
+  if (b)
+    con->flags|= CONS_DEBUG;
+  else
+    con->flags&= ~CONS_DEBUG;
 }
 
 
@@ -738,20 +134,19 @@ cl_super_cmd::work(class cl_sim *sim,
  *____________________________________________________________________________
  */
 
-cl_console::cl_console(char *fin, char *fout, class cl_sim *asim):
+cl_console::cl_console(char *fin, char *fout, class cl_app *the_app):
   cl_base()
 {
   FILE *f;
 
-  last_command= NULL;
-  sim= asim;
+  app= the_app;
   in= 0;
   if (fin)
-    if (f= fopen(fin, "r+"), in= f, !f)
+    if (f= fopen(fin, "r"), in= f, !f)
       fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));
   out= 0;
   if (fout)
-    if (f= fopen(fout, "w+"), out= f, !f)
+    if (f= fopen(fout, "w"), out= f, !f)
       fprintf(stderr, "Can't open `%s': %s\n", fout, strerror(errno));
   prompt= 0;
   flags= CONS_NONE;
@@ -759,14 +154,16 @@ cl_console::cl_console(char *fin, char *fout, class cl_sim *asim):
       isatty(fileno(in)))
     flags|= CONS_INTERACTIVE;
   else
-    printf("Warning: non-interactive console\n");
+    ;//fprintf(stderr, "Warning: non-interactive console\n");
+  rout= 0;
+  id= 0;
+  lines_printed= new cl_ustrings(100, 100, "console_cache");
 }
 
-cl_console::cl_console(FILE *fin, FILE *fout, class cl_sim *asim):
+cl_console::cl_console(FILE *fin, FILE *fout, class cl_app *the_app):
   cl_base()
 {
-  last_command= NULL;
-  sim= asim;
+  app= the_app;
   in = fin;
   out= fout;
   prompt= 0;
@@ -775,7 +172,10 @@ cl_console::cl_console(FILE *fin, FILE *fout, class cl_sim *asim):
       isatty(fileno(in)))
     flags|= CONS_INTERACTIVE;
   else
-    printf("Warning: non-interactive console\n");
+    ;//fprintf(stderr, "Warning: non-interactive console\n");
+  rout= 0;
+  id= 0;
+  lines_printed= new cl_ustrings(100, 100, "console_cache");
 }
 
 /*
@@ -801,27 +201,59 @@ connect_to_port(int portnum)
   return sock;
 }
 
-cl_console::cl_console(int portnumber, class cl_sim *asim)
+cl_console::cl_console(int portnumber, class cl_app *the_app)
 {
   int sock= connect_to_port(portnumber);
 
-  last_command= NULL;
-  sim= asim;
-  if (!(in= fdopen(sock, "r+")))
+  app= the_app;
+  if (!(in= fdopen(sock, "r")))
     fprintf(stderr, "cannot open port for input\n");
-  if (!(out= fdopen(sock, "w+")))
+  if (!(out= fdopen(sock, "w")))
     fprintf(stderr, "cannot open port for output\n");
   //fprintf(stderr, "init socket done\n");
+  id= 0;
+  lines_printed= new cl_ustrings(1, 1, "console_cache");
 }
 #endif
 
+class cl_console *
+cl_console::clone_for_exec(char *fin)
+{
+  FILE *fi= 0, *fo= 0;
+
+  if (!fin)
+    return(0);
+  if (fi= fopen(fin, "r"), !fi)
+    {
+      fprintf(stderr, "Can't open `%s': %s\n", fin, strerror(errno));
+      return(0);
+    }
+  if ((fo= fdopen(dup(fileno(out)), "a")) == 0)
+    {
+      fclose(fi);
+      fprintf(stderr, "Can't re-open output file: %s\n", strerror(errno));
+      return(0);
+    }
+  class cl_console *con= new cl_sub_console(this, fi, fo, app);
+  return(con);
+}
+
 int
 cl_console::init(void)
 {
   cl_base::init();
+  prompt_option= new cl_prompt_option(this);
+  prompt_option->init();
+  null_prompt_option= new cl_optref(this);
+  null_prompt_option->init();
+  null_prompt_option->use("null_prompt");
+  debug_option= new cl_debug_option(this);
+  debug_option->init();
   welcome();
   flags&= ~CONS_PROMPT;
-  print_prompt();
+  //print_prompt();
+  last_command= 0;
+  last_cmdline= 0;
   return(0);
 }
 
@@ -829,12 +261,17 @@ cl_console::~cl_console(void)
 {
   if (in)
     fclose(in);
+  un_redirect();
   if (out)
     {
-      fprintf(out, "\n");
+      if (flags & CONS_PROMPT)
+       fprintf(out, "\n");
       fflush(out);
       fclose(out);
     }
+  delete prompt_option;
+  delete null_prompt_option;
+  delete debug_option;
 #ifdef SOCKET_AVAIL
   /*  if (sock)
     {
@@ -845,6 +282,17 @@ cl_console::~cl_console(void)
 }
 
 
+bool
+cl_console::accept_last(void)
+{
+  if (!in)
+    return(DD_FALSE);
+  if (isatty(fileno(in)))
+    return(DD_TRUE);
+  return(DD_FALSE);
+}
+
+
 /*
  * Output functions
  */
@@ -852,45 +300,123 @@ cl_console::~cl_console(void)
 void
 cl_console::welcome(void)
 {
-  if (!out)
+  FILE *Out= rout?rout:out;
+
+  if (!Out ||
+      (flags & CONS_NOWELCOME))
     return;
-  fprintf(out, "ucsim %s, Copyright (C) 1997 Daniel Drotos, Talker Bt.\n"
-         "ucsim comes with ABSOLUTELY NO WARRANTY; for details type "
+  fprintf(Out, "uCsim %s, Copyright (C) 1997 Daniel Drotos, Talker Bt.\n"
+         "uCsim comes with ABSOLUTELY NO WARRANTY; for details type "
          "`show w'.\n"
          "This is free software, and you are welcome to redistribute it\n"
          "under certain conditions; type `show c' for details.\n",
          VERSIONSTR);
-  fflush(out);
+  fflush(Out);
+}
+
+void
+cl_console::redirect(char *fname, char *mode)
+{
+  if ((rout= fopen(fname, mode)) == NULL)
+    dd_printf("Unable to open file '%s' for %s: %s\n",
+             fname, (mode[0]=='w')?"write":"append", strerror(errno));
+}
+
+void
+cl_console::un_redirect(void)
+{
+  if (!rout)
+    return;
+  fclose(rout);
+  rout= NULL;
+}
+
+
+int
+cl_console::cmd_do_print(FILE *f, char *format, va_list ap)
+{
+  int ret;
+#ifdef HAVE_VASPRINTF
+  char *msg= NULL;
+  vasprintf(&msg, format, ap);
+  ret= fprintf(f, "%s", msg);
+  free(msg);
+#else
+#  ifdef HAVE_VSNPRINTF
+  char msg[80*25];
+  vsnprintf(msg, 80*25, format, ap);
+  ret= fprintf(f, "%s", msg);
+#  else
+#    ifdef HAVE_VPRINTF
+  char msg[80*25];
+  vsprintf(msg, format, ap); /* Dangerous */
+  ret= fprintf(f, "%s", msg);
+#    else
+#      ifdef HAVE_DOPRNT
+  /* ??? */
+  /*strcpy(msg, "Unimplemented printf has called.\n");*/
+#      else
+  /*strcpy(msg, "printf can not be implemented, upgrade your libc.\n");*/
+#      endif
+#    endif
+#  endif
+#endif
+  fflush(f);
+  return(ret);
 }
 
 void
 cl_console::print_prompt(void)
 {
-  char *p;
+  //char *p;
+  FILE *Out= rout?rout:out;
 
-  if (flags & (CONS_PROMPT|CONS_FROZEN))
+  if (flags & (CONS_PROMPT|CONS_FROZEN|CONS_INACTIVE))
     return;
   flags|= CONS_PROMPT;
-  if (!out)
+  if (!Out)
     return;
-  if (sim->arg_avail('P'))
-    putc('\0', out);
+  if (/*app->args->arg_avail('P')*/null_prompt_option->get_value(bool(0)))
+    putc('\0', Out);
   else
-    fprintf(out, "%s", (prompt && prompt[0])?prompt:
-           ((p= sim->get_sarg(0, "prompt"))?p:"> "));
-  fflush(out);
+    {
+      fprintf(Out, "%d", id);
+      fprintf(Out, "%s", (prompt && prompt[0])?prompt:"> ");
+      //             ((p= app->args->get_sarg(0, "prompt"))?p:"> "));
+    }
+  fflush(Out);
 }
 
 int
-cl_console::printf(char *format, ...)
+cl_console::dd_printf(char *format, ...)
 {
   va_list ap;
   int ret= 0;
+  FILE *Out= rout?rout:out;
 
-  if (out)
+  if (Out)
+    {
+      va_start(ap, format);
+      ret= cmd_do_print(Out, format, ap);
+      va_end(ap);
+    }
+  return(ret);
+}
+
+int
+cl_console::debug(char *format, ...)
+{
+  if ((flags & CONS_DEBUG) == 0)
+    return(0);
+
+  va_list ap;
+  int ret= 0;
+  FILE *Out= rout?rout:out;
+
+  if (Out)
     {
       va_start(ap, format);
-      ret= cmd_do_print(out, format, ap);
+      ret= cmd_do_print(Out, format, ap);
       va_end(ap);
     }
   return(ret);
@@ -900,17 +426,28 @@ void
 cl_console::print_bin(long data, int bits)
 {
   long mask= 1;
+  FILE *Out= rout?rout:out;
 
-  if (!out)
+  if (!Out)
     return;
   mask= mask << ((bits >= 1)?(bits-1):0);
   while (bits--)
     {
-      fprintf(out, "%c", (data&mask)?'1':'0');
+      fprintf(Out, "%c", (data&mask)?'1':'0');
       mask>>= 1;
     }
 }
 
+void
+cl_console::print_char_octal(char c)
+{
+  FILE *Out= rout?rout:out;
+
+  if (Out)
+    ::print_char_octal(c, Out);
+}
+
+
 /*
  * Input functions
  */
@@ -927,6 +464,8 @@ cl_console::match(int fdnum)
 int
 cl_console::get_in_fd(void)
 {
+  if (flags & CONS_INACTIVE)
+    return(-2);
   return(in?fileno(in):-1);
 }
 
@@ -988,6 +527,7 @@ cl_console::proc_input(class cl_cmdset *cmdset)
 {
   int retval= 0;
 
+  un_redirect();
   if (feof(in))
     {
       fprintf(out, "End\n");
@@ -998,26 +538,70 @@ cl_console::proc_input(class cl_cmdset *cmdset)
     return(1);
   if (flags & CONS_FROZEN)
     {
-      sim->stop(resUSER);
+      app->get_sim()->stop(resUSER);
       flags&= ~CONS_FROZEN;
       retval= 0;
     }
   else
     {
-      class cl_cmdline *cmdline;
-      class cl_cmd *cm;
-      cmdline= new cl_cmdline(cmdstr, this);
-      cmdline->init();
-      cm= cmdset->get_cmd(cmdline);
-      if (cm)
-       retval= cm->work(sim, cmdline, this);
-      delete cmdline;
-      if (!cm)
-       retval= interpret(cmdstr);
+      if (cmdstr &&
+         *cmdstr == '\004')
+       retval= 1;
+      else
+       {
+         class cl_cmdline *cmdline= 0;
+         class cl_cmd *cm= 0;
+         if (flags & CONS_ECHO)
+           dd_printf("%s\n", cmdstr);
+         cmdline= new cl_cmdline(app, cmdstr, this);
+         cmdline->init();
+         if (cmdline->repeat() &&
+             accept_last() &&
+             last_command)
+           {
+             cm= last_command;
+             delete cmdline;
+             cmdline= last_cmdline;
+           }
+         else
+           {
+             cm= cmdset->get_cmd(cmdline, accept_last());
+             if (last_cmdline)
+               {
+                 delete last_cmdline;
+                 last_cmdline= 0;
+               }
+             last_command= 0;
+           }
+         if (cm)
+           {
+             retval= cm->work(app, cmdline, this);
+             if (cm->can_repeat)
+               {
+                 last_command= cm;
+                 last_cmdline= cmdline;
+               }
+             else
+               delete cmdline;
+           }
+         else
+           {
+             class YY_cl_ucsim_parser_CLASS *pars;
+             class cl_ucsim_lexer *lexer;
+             lexer= new cl_ucsim_lexer(cmdstr);
+             pars= new YY_cl_ucsim_parser_CLASS(lexer);
+             pars->yyparse();
+             delete cmdline;
+             delete pars;
+           }
+         /*if (!cm)
+           retval= interpret(cmdstr);*/
+       }
     }
   //retval= sim->do_cmd(cmd, this);
-  if (!retval)
-    print_prompt();
+  un_redirect();
+  /*if (!retval)
+    print_prompt();*/
   free(cmdstr);
   return(retval);
 }
@@ -1030,20 +614,43 @@ cl_console::proc_input(class cl_cmdset *cmdset)
 int
 cl_console::interpret(char *cmd)
 {
-  fprintf(out, "New interpreter does not known this command\n");
+  FILE *Out= rout?rout:out;
+
+  fprintf(Out, "Unknown command\n");
   return(0);
 }
 
+void
+cl_console::set_id(int new_id)
+{
+  char *s;
+
+  id= new_id;
+  set_name(s= format_string("console%d", id));
+  free(s);
+}
+
+void
+cl_console::set_prompt(char *p)
+{
+  if (prompt)
+    free(prompt);
+  if (p &&
+      *p)
+    prompt= strdup(p);
+  else
+    prompt= 0;
+}
+
 
 /*
  * This console listen on a socket and can accept connection requests
  */
 #ifdef SOCKET_AVAIL
 
-cl_listen_console::cl_listen_console(int serverport, class cl_sim *asim)
+cl_listen_console::cl_listen_console(int serverport, class cl_app *the_app)
 {
-  last_command= NULL;
-  sim= asim;
+  app= the_app;
   if ((sock= make_server_socket(serverport)) >= 0)
     {
       if (listen(sock, 10) < 0)
@@ -1071,7 +678,9 @@ cl_listen_console::proc_input(class cl_cmdset *cmdset)
   int newsock;
   ACCEPT_SOCKLEN_T size;
   struct sockaddr_in sock_addr;
+  class cl_commander *cmd;
 
+  cmd= app->get_commander();
   size= sizeof(struct sockaddr); 
   newsock= accept(sock, (struct sockaddr*)&sock_addr, &size);
   if (newsock < 0)
@@ -1083,10 +692,9 @@ cl_listen_console::proc_input(class cl_cmdset *cmdset)
     fprintf(stderr, "cannot open port for input\n");
   if (!(out= fdopen(newsock, "w+")))
     fprintf(stderr, "cannot open port for output\n");
-  class cl_console *c= sim->cmd->mk_console(in, out, sim);
+  class cl_console *c= cmd->mk_console(in, out);
   c->flags|= CONS_INTERACTIVE;
-  c->init();
-  sim->cmd->add_console(c);
+  cmd->add_console(c);
   in= out= 0;
   return(0);
 }
@@ -1094,37 +702,108 @@ cl_listen_console::proc_input(class cl_cmdset *cmdset)
 #endif /* SOCKET_AVAIL */
 
 
+/*
+ * Sub-console
+ */
+
+cl_sub_console::cl_sub_console(class cl_console *the_parent,
+                              FILE *fin, FILE *fout, class cl_app *the_app):
+  cl_console(fin, fout, the_app)
+{
+  parent= the_parent;
+}
+
+cl_sub_console::~cl_sub_console(void)
+{
+  class cl_commander *c= app->get_commander();
+
+  if (parent && c)
+    {
+      c->activate_console(parent);
+    }
+}
+
+int
+cl_sub_console::init(void)
+{
+  class cl_commander *c= app->get_commander();
+
+  if (parent && c)
+    {
+      c->deactivate_console(parent);
+    }
+  cl_console::init();
+  flags|= CONS_ECHO;
+  return(0);
+}
+
+
 /*
  * Command interpreter
  *____________________________________________________________________________
  */
 
-cl_commander::cl_commander(class cl_cmdset *acmdset, class cl_sim *asim):
+cl_commander::cl_commander(class cl_app *the_app, class cl_cmdset *acmdset
+                          /*, class cl_sim *asim*/):
   cl_base()
 {
-  cons= new cl_list(1, 1); 
+  app= the_app;
+  cons= new cl_list(1, 1, "consoles"); 
   actual_console= frozen_console= 0;
   cmdset= acmdset;
-  sim= asim;
 }
 
 int
 cl_commander::init(void)
 {
+  class cl_optref console_on_option(this);
+  class cl_optref config_file_option(this);
+  class cl_optref port_number_option(this);
+  class cl_console *con;
+
+  console_on_option.init();
+  console_on_option.use("console_on");
+  config_file_option.init();
+  config_file_option.use("config_file");
+  port_number_option.init();
+
   cl_base::init();
-  if (!sim)
-    return(1);
-  if (sim->arg_avail('c'))
-    add_console(mk_console(sim->get_sarg('c', 0),
-                          sim->get_sarg('c', 0), sim));
+  set_name("Commander");
+  
+  bool need_config= DD_TRUE;
+
 #ifdef SOCKET_AVAIL
-  if (sim->arg_avail('Z'))
-    add_console(mk_console(sim->get_iarg(0, "Zport"), sim));
-  if (sim->arg_avail('r'))
-    add_console(mk_console(sim->get_iarg('r', 0), sim));
+  if (port_number_option.use("port_number"))
+    add_console(mk_console(port_number_option.get_value((long)0)));
 #endif
+
+  char *Config= config_file_option.get_value(Config);
+  char *cn= console_on_option.get_value(cn);
+
+  if (cn)
+    {
+      add_console(con= mk_console(cn, cn));
+      exec_on(con, Config);
+      need_config= DD_FALSE;
+    }
   if (cons->get_count() == 0)
-    add_console(mk_console(stdin, stdout, sim));
+    {
+      add_console(con= mk_console(stdin, stdout));
+      exec_on(con, Config);
+      need_config= DD_FALSE;
+    }
+  if (need_config)
+    {
+      FILE *fc= fopen(Config, "r");
+      if (!fc)
+       fprintf(stderr, "Can't open `%s': %s\n", Config, strerror(errno));
+      else
+       {
+         con= mk_console(fc, stderr);
+         con->flags|= CONS_NOWELCOME|CONS_ECHO;
+         add_console(con);
+       }
+    }
   return(0);
 }
 
@@ -1135,30 +814,33 @@ cl_commander::~cl_commander(void)
 }
 
 class cl_console *
-cl_commander::mk_console(char *fin, char *fout, class cl_sim *asim)
+cl_commander::mk_console(char *fin, char *fout)
 {
-  return(new cl_console(fin, fout, asim));
+  return(new cl_console(fin, fout, app));
 }
 
 class cl_console *
-cl_commander::mk_console(FILE *fin, FILE *fout, class cl_sim *asim)
+cl_commander::mk_console(FILE *fin, FILE *fout)
 {
-  return(new cl_console(fin, fout, asim));
+  return(new cl_console(fin, fout, app));
 }
 
 #ifdef SOCKET_AVAIL
 class cl_console *
-cl_commander::mk_console(int portnumber, class cl_sim *asim)
+cl_commander::mk_console(int portnumber)
 {
-  return(new cl_listen_console(portnumber, asim));
+  return(new cl_listen_console(portnumber, app));
 }
 #endif
 
 void
 cl_commander::add_console(class cl_console *console)
 {
+  if (!console)
+    return;
+  int i=cons->add(console);
+  console->set_id(i);
   console->init();
-  cons->add(console);
   set_fd_set();
 }
 
@@ -1169,6 +851,21 @@ cl_commander::del_console(class cl_console *console)
   set_fd_set();
 }
 
+void
+cl_commander::activate_console(class cl_console *console)
+{
+  console->flags&= ~CONS_INACTIVE;
+  //console->print_prompt();
+  set_fd_set();
+}
+
+void
+cl_commander::deactivate_console(class cl_console *console)
+{
+  console->flags|= CONS_INACTIVE;
+  set_fd_set();
+}
+
 void
 cl_commander::set_fd_set(void)
 {
@@ -1211,16 +908,29 @@ cl_commander::all_printf(char *format, ...)
   for (i= 0; i < cons->count; i++)
     {
       class cl_console *c= (class cl_console*)(cons->at(i));
-      if (c->out)
+      FILE *Out= c->get_out();
+      if (Out)
        {
          va_start(ap, format);
-         ret= cmd_do_print(c->out, format, ap);
+         ret= c->cmd_do_print(Out, format, ap);
          va_end(ap);
        }
     }
   return(ret);
 }
 
+void
+cl_commander::prompt(void)
+{
+  int i;
+  
+  for (i= 0; i < cons->count; i++)
+    {
+      class cl_console *c= (class cl_console*)(cons->at(i));
+      c->print_prompt();
+    }
+}
+
 int
 cl_commander::all_print(char *string, int length)
 {
@@ -1229,10 +939,11 @@ cl_commander::all_print(char *string, int length)
   for (i= 0; i < cons->count; i++)
     {
       class cl_console *c= (class cl_console*)(cons->at(i));
-      if (c->out)
+      FILE *Out= c->get_out();
+      if (Out)
        {
          for (int j= 0; j < length; j++)
-           putc(string[j], c->out);
+           putc(string[j], Out);
        }
     }
   return(0);
@@ -1243,21 +954,70 @@ cl_commander::all_print(char *string, int length)
  */
 
 int
-cl_commander::printf(char *format, ...)
+cl_commander::dd_printf(char *format, ...)
 {
   va_list ap;
   int ret= 0;
+  FILE *f;
+  class cl_console *con;
 
-  if (actual_console &&
-      actual_console->out)
+  if (actual_console)
+    {
+      f= actual_console->get_out();
+      con= actual_console;
+    }
+  else if (frozen_console)
+    {
+      f= frozen_console->get_out();
+      con= frozen_console;
+    }
+  else
+    {
+      f= 0;
+      con= 0;
+    }
+  if (/*actual_console &&
+       actual_console->out*/f &&
+                            con)
     {
       va_start(ap, format);
-      ret= cmd_do_print(actual_console->out, format, ap);
+      ret= con->cmd_do_print(f/*actual_console->out*/, format, ap);
       va_end(ap);
     }
   return(ret);
 }
 
+int
+cl_commander::dd_printf(char *format, va_list ap)
+{
+  int ret= 0;
+  FILE *f;
+  class cl_console *con;
+
+  if (actual_console)
+    {
+      f= actual_console->get_out();
+      con= actual_console;
+    }
+  else if (frozen_console)
+    {
+      f= frozen_console->get_out();
+      con= frozen_console;
+    }
+  else
+    {
+      f= 0;
+      con= 0;
+    }
+  if (/*actual_console &&
+       actual_console->out*/f &&
+                            con)
+    {
+      ret= con->cmd_do_print(f/*actual_console->out*/, format, ap);
+    }
+  return(ret);
+}
+
 /*
  * Printing to consoles which have CONS_DEBUG flag set
  */
@@ -1271,17 +1031,36 @@ cl_commander::debug(char *format, ...)
   for (i= 0; i < cons->count; i++)
     {
       class cl_console *c= (class cl_console*)(cons->at(i));
-      if (c->out &&
+      FILE *Out= c->get_out();
+      if (Out &&
          c->flags & CONS_DEBUG)
        {
          va_start(ap, format);
-         ret= cmd_do_print(c->out, format, ap);
+         ret= c->cmd_do_print(Out, format, ap);
          va_end(ap);
        }
     }
   return(ret);
 }
 
+int
+cl_commander::debug(char *format, va_list ap)
+{
+  int i, ret= 0;
+
+  for (i= 0; i < cons->count; i++)
+    {
+      class cl_console *c= (class cl_console*)(cons->at(i));
+      FILE *Out= c->get_out();
+      if (Out &&
+         c->flags & CONS_DEBUG)
+       {
+         ret= c->cmd_do_print(Out, format, ap);
+       }
+    }
+  return(ret);
+}
+
 int
 cl_commander::flag_printf(int iflags, char *format, ...)
 {
@@ -1291,11 +1070,12 @@ cl_commander::flag_printf(int iflags, char *format, ...)
   for (i= 0; i < cons->count; i++)
     {
       class cl_console *c= (class cl_console*)(cons->at(i));
-      if (c->out &&
+      FILE *Out= c->get_out();
+      if (Out &&
          (c->flags & iflags) == iflags)
        {
          va_start(ap, format);
-         ret= cmd_do_print(c->out, format, ap);
+         ret= c->cmd_do_print(Out, format, ap);
          va_end(ap);
        }
     }
@@ -1333,6 +1113,7 @@ cl_commander::wait_input(void)
   int i;
 
   active_set= read_set;
+  prompt();
   i= select(fd_num, &active_set, NULL, NULL, NULL);
   return(i);
 }
@@ -1367,5 +1148,18 @@ cl_commander::proc_input(void)
   return(0);
 }
 
+void
+cl_commander::exec_on(class cl_console *cons, char *file_name)
+{
+  FILE *fi= fopen(file_name, "r");
+
+  if (!cons ||
+      !fi)
+    return;
+  class cl_console *subcon= cons->clone_for_exec(file_name);
+  subcon->flags|= CONS_NOWELCOME;
+  add_console(subcon);
+}
+
 
 /* End of cmd.src/newcmd.cc */