#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <yafl_usr.h>
#include <yafl_rnt.h>
#include "dbx_rnt.h"
#include "dbx_modu.h"
#include "dbx_type.h"
#include "dbx_vari.h"
#include "dbx_clas.h"
#include "dbx_meth.h"
#include "dbx_cmd.h"
#include "dbx_ctrl.h"
#include "dbx_file.h"
#include "dbx_type.h"
#include "dbx_obar.h"
#include "dbx_fiel.h"
#include "dbx_call.h"
#include "dbx_loca.h"
#include "dbx_list.h"
#include "dbx_fram.h"
#include "dbx_ctxt.h"
#include "dbx_curr.h"
#include "dbx_brea.h"
#include "dbx_watc.h"
#include "dbx_out.h"
#include "dbx_lssw.h"
#include "dbx_auto.h"
#include "dbx_stri.h"
                   
extern void yafl_terminate YPARAMS0;
/***************************************************/
static int max YPARAMS4(int,  a,
                       int,  b)
{
  return (a>b?a:b);
}

static int min YPARAMS4(int,  a,
                       int,  b)
{
  return (a<b?a:b);
}

/* fonctions execs */
/* returning 1 for run/step commands forces return in the main program */
/* returning 0 for others commands to allow more commands to be entered */


/* commands related to program execution */

int exec_r YPARAMS0
{
  mode_run();
  return 1;
}

int exec_e YPARAMS0
{
  mode_end();
  return 1;
}

int exec_t YPARAMS0
{
  mode_trace();
  return 1;
}

int exec_s YPARAMS0
{
  mode_step();
  return 1;
}

int exec_m YPARAMS0
{
  mode_move();
  return 1;
}

int exec_u YPARAMS0
{
  mode_leave();
  return 1;
}

int exec_q YPARAMS0
{
  yafl_terminate();
  exit(0); 
  return 0;
}

/* automatic redraw mechanism */
#define ON_LINES 0
#define ON_CALLS 1
#define ON_BREAKS 2
#define ON_WATCHS 3
#define ON_MODULES 4
#define ON_CLASSES 5
#define ON_METHODS 6
#define ON_DATA 7

static unsigned on_mode = ON_LINES;

void do_w YPARAMS0
{
  dbx_method *pm;
  dbx_class *pc;
  if (current_module())
  {
    pm = line_in_method(current_module(),current_line());
    if (pm)
    {
      writestring(module_name(class_module(method_class(pm))));
      writestring(".");
      writestring(class_name(method_class(pm)));
      writestring(".");
      writestring(method_name(pm));
      writestring(":");
      writeint(current_line());
      writeln();
    }
    else
    {
      pc = line_in_class(current_module(),current_line());
      if (pc)
      {
        writestring(module_name(class_module(pc)));
        writestring(".");
        writestring(class_name(pc));
        writestring(":");
        writeint(current_line());
        writeln();
      }
      else
      {
        writestring(module_name(current_module()));
        writestring(":");
        writeint(current_line());
        writeln();
      }
    }
  }
  else
  {
    writestring("no current module");
    writeln();
  }
}     



/* commands related to source files */
static unsigned page_size = 11;


void do_li YPARAMS0
{
  unsigned first_line,last_line;
  unsigned size;
  unsigned number;
  do_w();
  writeln();
  number = page_size/2;
  if (current_module())
  {
    size = module_endline(current_module());
    if (size <= page_size)
    {
      first_line = 1;
      last_line = size;
    }
    else
    {
      if (current_line() <= number)
      {
        first_line = 1;
        last_line  = page_size;
      }
      else if (current_line() + number > size)
      {
        first_line = size-page_size+1;
        last_line = size;
      }
      else       
      {
        first_line = current_line()-number;
        last_line =  current_line()+number;
      }
    }                      
    list_lines(current_module(),first_line,last_line,current_line());
  }
  else
  {
    writeline("no current module");
  }
}

int exec_li YPARAMS0
{
  if (strlen(get_arg())>0)
    page_size = atoi(get_arg());
  do_li();
  on_mode = ON_LINES;
  return (0);
}

int exec_gu YPARAMS0
{
  if (current_module())
  {
    set_current_line(max(1,current_line()-page_size));
    do_li();
  }
  else
  {
    writeline("no current module");
  }
  return(0);
}

int exec_gd YPARAMS0
{
  if (current_module())
  {
    set_current_line(min(module_endline(current_module()),
                         current_line()+page_size));
    do_li();
  }
  else
  {
    writeline("no current module");
  }
  return(0);
}

int exec_gt YPARAMS0
{
  if (current_module())
  {
    set_current_line(1);
    do_li();
  }
  else
  {
    writestring("no current module");
  }
  return(0);
}

int exec_gb YPARAMS0
{
  if (current_module())
  {
    set_current_line(module_endline(current_module()));
    do_li();
  }
  else
  {
    writeline("no current module");
  }
  return(0);
}

int exec_ci YPARAMS0
{   
  unsigned line;
  dbx_module *pm;
  if (current_module())
  {
    if (strlen(get_arg()) > 0)
      line = atoi(get_arg());
    else
      line = 1;
    pm = current_module();
    if ((line >= 0)&&(line <= module_endline(pm)))
    {
      set_current_line(line);
    }
    else
      writeline("inexistant line");
    do_li();
  }
  else
  {  
    writeline("no current module");
  }
  return(0);
}


/* commands related to modules,classes and methods */

int exec_cm YPARAMS0
{
  dbx_module *pm;
  if (current_module())
  {
    if (get_flag('n'))
      pm = find_next_module(next_module(current_module()),get_arg());
    else if (get_flag('p'))
      pm = find_prev_module(prev_module(current_module()), get_arg());
    else if (get_flag('l'))
      pm = find_prev_module(last_module(), get_arg());
    else
      pm = find_next_module(first_module(),get_arg());
    if (pm)
    {
      set_current_module(pm);
      set_current_line(1);
    }
    else
      writeline("module not found");
  }
  else
    writeline("no modules");
  return(0);
}

int exec_cc YPARAMS0
{
  dbx_class *pc;
  if (current_class())
  {
    if (get_flag('n'))
      pc = find_next_class(next_class(current_class()),get_arg());
    else if (get_flag('p'))
      pc = find_prev_class(prev_class(current_class()), get_arg());
    else if (get_flag('l'))
      pc = find_prev_class(last_class(current_module()), get_arg());
    else
      pc = find_next_class(first_class(current_module()),get_arg());
    if (pc)
    {
      set_current_class(pc);
      set_current_line(class_beginline(pc));
    }
    else
      writeline("class not found");
  }
  else
    writeline("no classes");
  return(0);
}

int exec_cp YPARAMS0
{
  dbx_method *pm;
  if (current_method())
  {
    if (get_flag('n'))
      pm = find_next_method(next_method(current_method()),get_arg());
    else if (get_flag('p'))
      pm = find_prev_method(prev_method(current_method()), get_arg());
    else if (get_flag('l'))
      pm = find_prev_method(last_method(current_class()), get_arg());
    else
      pm = find_next_method(first_method(current_class()),get_arg());
    if (pm)
    {
      set_current_method(pm);
      set_current_line(method_beginline(pm));
    }
    else
      writeline("method not found");
  }
  else
    writeline("no methods");
  return(0);
}

int exec_cf YPARAMS0
{
  dbx_field *pf;
  if (current_field())
  {
    if (get_flag('n'))
      pf = find_next_field(next_field(current_field()), get_arg());
    else if (get_flag('p'))
      pf = find_prev_field(prev_field(current_field()), get_arg());
    else if (get_flag('l'))
      pf = find_prev_field(last_field(current_class()), get_arg());
    else
      pf = find_next_field(first_field(current_class()),get_arg());
    if (pf)
    {
      set_current_field(pf);
/*      set_current_line(field_beginline(pf)); */
    }
    else
      writeline("field not found");
  }
  else
    writeline("no fields");
  return(0);
}

int exec_cl YPARAMS0
{
  dbx_local *pl;
  if (current_local())
  {
    if (get_flag('n'))
      pl = find_next_local(next_local(current_local()), get_arg());
    else if (get_flag('p'))
      pl = find_prev_local(prev_local(current_local()), get_arg());
    else if (get_flag('l'))
      pl = find_prev_local(last_local(current_method()), get_arg());
    else
      pl = find_next_local(first_local(current_method()), get_arg());
    if (pl)
    {
      set_current_local(pl);
/*      set_current_line(local_beginline(pl)); */
    }
    else
      writeline("local not found");
  }
  else
    writeline("no locals");
  return(0);
}

int exec_lm YPARAMS0
{
  list_modules(current_module(), get_arg());
  on_mode = ON_MODULES;
  return(0);
}
  
int exec_lc YPARAMS0
{
  list_classes(current_module(), current_class(), get_arg());
  on_mode = ON_CLASSES;
  return(0);
}
                
int exec_lch YPARAMS0
{
  dbx_class *pc, *qc;
/*  pc = lowest_class(top_objarr(current_context())); */
/*  list_parentclasses(pc); */
  pc = first_subclass(NULL);
  qc = last_subclass(NULL);
  if (!pc)
    printf("NULL pc\n");
  if (!qc)
    printf("NULL qc\n");
  while (pc)
  {
    list_class_hierarchy(pc);
    pc = next_subclass(pc);
  }
  on_mode = ON_CLASSES;
  return(0);
}

int exec_lf YPARAMS0
{
  if (once_class(current_class()))
  {
    list_fields(current_class(),
                current_field(),
                class_once_ptr(current_class()),
                get_arg());
  }
  else
  {
    list_fields(current_class(),
                current_field(),
                NULL,
                get_arg());
  }
  /* on_mode = ON_FIELDS; */
  return(0);
}

int exec_lp YPARAMS0
{
  list_methods(current_class(), current_method(), get_arg());
  on_mode = ON_METHODS;
  return(0);
}

int exec_lph YPARAMS0
{
  dbx_method *pm;
  if (current_module())
  {
    pm = line_in_method(current_module(),current_line());
    if (pm)
      list_method_hierarchy(pm);
    else
      writeline("no method");
  }
  else
  {
    writeline("no current module");
    writeln();
  }
  on_mode = ON_METHODS;
  return(0);
}

int exec_ll YPARAMS0
{
  list_locals(current_method(), current_local(), NULL, get_arg());
  return(0);
}

/* commands related to breakpoints */
extern dbx_list *break_list;

int exec_sb YPARAMS0
{
  unsigned line_number;
  dbx_method *pm;
  int ok;
  if (strlen(get_arg()) > 0)
    line_number = atoi(get_arg());
  else
    line_number = current_line();
  pm = line_in_method(current_module(),line_number);
  ok = is_statement(current_module(),line_number);
  if (pm)
  {
    if (ok||(line_number==method_endline(pm)))
    {
      if (!find_breakpoint(pm,line_number))
      {  
        unsigned step;
        int action; 
        char *string;
        if (get_opt('s'))
          step = atoi(get_opt('s'));  
        else
          step = 1;
        if (get_flag('t'))
        {
          action = BP_IGNORE;
          string = strnew();
        }
        else if (get_opt('l'))
        {
          action = BP_LOG;
          string = strclone(get_opt('l')); 
        }
        else
        {
          action = BP_BREAK;
          string = strnew();
        } 
        writestring("breakpoint on in ");
        writestring(method_name(pm));
        writeln();
        add_breakpoint(pm,line_number,step,action,string);
      }
      else
      {
        writeline("breakpoint already present");	
      }
    }
    else
    {
      writeline("not statement");
    }
  }
  else
  {
    writeline("not in method");    
  }
  return(0);
}

int exec_rb YPARAMS0
{
  if (on_mode == ON_BREAKS)
  {
    if (strlen(get_arg()) > 0)
    {
      int number;
      number = atoi(get_arg());
      if ((number >= 1)&&(number <= list_size(break_list)))
      {
        sub2_breakpoint(number);
      }
      else
        writeline("not found");
    }
    else
    {
    }
  }
  else
  {
    unsigned line_number;
    dbx_method *pm;
    if (strlen(get_arg()) > 0)
      line_number = atoi(get_arg());
    else
      line_number = current_line();
    pm = line_in_method(current_module(),line_number);
    if (find_breakpoint(pm,line_number))
    {  
      writestring("breakpoint off in ");
      writestring(method_name(pm));
      writeln();
      sub_breakpoint(pm,line_number);
    }
    else
      writeline("breakpoint not present");
  }
  return 0;
}

int exec_cb YPARAMS0
{
  unsigned number;
  if (strlen(get_arg())>0)
  {
    number = atoi(get_arg());
    if ((number >= 1)&&(number <= list_size(break_list)))
    {
      go_nth(break_list,number);
    }
    else
    {
      writeline("not found");
    }
  }
  else
  {
    if (get_flag('n'))
    {
      if (current_elem(break_list) != last_elem(break_list))
      {
        go_next(break_list);
      }
      else
      {
        writeline("not found");
      }
    }
    else
    {
      go_first(break_list);
    }     
  }
  return(0);
}

int exec_lb YPARAMS0
{
  list_breakpoints(current_breakpoint(), get_arg());
  on_mode = ON_BREAKS;
  return(0);
}

int exec_ib YPARAMS0
{
  dbx_breakpoint *pb;
  unsigned number;
  if (strlen(get_arg())>0)
  {
    number = atoi(get_arg());
    if ((number >= 1)&&(number <= list_size(break_list)))
    {
      pb = find2_breakpoint(number);
      set_current_module(breakpoint_module(pb));
      set_current_line(breakpoint_line(pb));
      do_li();
    }
    else
    {
      writeline("inexistant breakpoint");
    }
  }
  else
  {
  }
  return(0);
}


/* commands related to watches */
extern dbx_list *watch_list;

int exec_sw YPARAMS0
{
  char *expression;
  if (strlen(get_arg()) > 0)
    expression = get_arg();
  else
    expression = context_name(current_context());
  add_watch(strclone(expression));
  return(0);
}

int exec_rw YPARAMS0
{
  unsigned number;
  dbx_elem *pe;
  if (strlen(get_arg())>0)
  {
    number = atoi(get_arg());
    if ((number >= 1)&&(number <= list_size(watch_list)))
    {
      sub_watch(number);
    }
    else
    {
      writeline("not found");
    }
  }
  else
  {
  }  
  return(0);
}
    
int exec_cw YPARAMS0
{
  unsigned number;
  if (strlen(get_arg())>0)
  {
    number = atoi(get_arg());
    if ((number >= 1)&&(number <= list_size(watch_list)))
    {
      go_nth(watch_list,number);
    }
    else
    {
      writeline("not found");
    }
  }
  else
  {
    if (get_flag('n'))
    {
      if (current_elem(watch_list) != last_elem(watch_list))
      {
        go_next(watch_list);
      }
      else
      {
        writeline("not found");
      }
    }
    else
    {
      go_first(watch_list);
    }     
  }
  return(0);
}

int exec_lw YPARAMS0
{
  list_watches(current_watch(), get_arg()); 
  on_mode = ON_WATCHS;
  return(0);
}

int exec_iw YPARAMS0
{
  dbx_watch *pw;
  unsigned number;
  if (strlen(get_arg())>0)
  {
    number = atoi(get_arg());
    if ((number >= 1)&&(number <= list_size(watch_list)))
    {
      pw = find_watch(number);
      apply_descriptor(current_context(),watch_expression(pw));
      return(exec_ld());
    }
    else
    {
      writeline("inexistant watch");
    }
  }
  else
  {
  }
  return(0);
}

/* commands related to stack of calls */

int exec_ls YPARAMS0
{
  if (call_depth() == 0)
  {
    writestring("empty debugger stack");
    writeln();
  }
  else
  {
    list_calls(current_call(), get_arg());
  }
  on_mode = ON_CALLS;
  return(0);
}

int exec_cs YPARAMS0
{
  dbx_call *pc;
  if (current_call())
  {
    if (get_flag('n'))
      pc = find_prev_call(prev_call(current_call()),get_arg()); /* reversed */
    else if (get_flag('p'))
      pc = find_next_call(next_call(current_call()), get_arg()); /* reversed */
    else if (get_flag('l'))
      pc = find_next_call(first_call(), get_arg()); /* reversed */
    else 
      pc = find_prev_call(last_call(),get_arg()); /* reversed */
    if (pc)
    {
      change_call(current_context(),pc);
      set_current_call(pc);
    }
    else 
      writeline("call not found");
  }
  else
    writeline("no calls");
  return(0);
}


/* commands related to data */
void do_cl YPARAMS0
{
  if (current_context())
  {
    dbx_local *pl;
    if (get_flag('n'))
      pl = find_next_local(next_local(context_local(current_context())),
                           get_arg());
    else if (get_flag('p'))
      pl = find_prev_local(prev_local(context_local(current_context())),
                           get_arg());
    else if (get_flag('l'))
      pl = find_prev_local(last_local(context_method(current_context())),
                           get_arg());
    else
      pl = find_next_local(first_local(context_method(current_context())),
                           get_arg());
    if (pl)
    {
      change_local(current_context(),pl);
    }
    else
      writeline("local not found");
  }
  else
    writeline("current context not defined");
}

void do_cf YPARAMS0
{
  dbx_field *pf;
  if (get_flag('n'))
    pf = find_next_field(next_field(top_field(current_context())),
                         get_arg());
  else if (get_flag('p'))
    pf = find_prev_field(prev_field(top_field(current_context())),
                         get_arg());
  else if (get_flag('l'))
    pf = find_prev_field(last_field(top_class(current_context())),
                         get_arg());
  else
    pf = find_next_field(first_field(top_class(current_context())),
                                get_arg());
  if (pf)
  {
    change_top_field(current_context(),pf);
  }
  else
    writeline("field not found");
}

void do_ce YPARAMS0
{
  unsigned index;
  int step;
  if (get_opt('n'))
  {
    if (strlen(get_opt('n')) > 0)
      step = atoi(get_opt('n'));
    else
      step = 1;
    index = top_subscript(current_context()) + step;
  }
  else if (get_opt('p'))
  {
    if (strlen(get_opt('p')) > 0)
      step = atoi(get_opt('p'));
    else
      step = 1;
    index = top_subscript(current_context()) - step;
  }
  else if (get_flag('l'))
    index = array_size(top_objarr(current_context())) - 1;
  else
  {
    if (strlen(get_arg())>0)
      index = atoi(get_arg());
    else
      index = 0;
  }
  if (index < array_size(top_objarr(current_context())))
  {
    change_top_subscript(current_context(),index);
  }
  else
    writeline("out of bounds"); 
}

void do_co YPARAMS0
{
  if (current_context())
  {
    dbx_class *pc;
    if (get_flag('n'))
      pc = find_next_once(next_once(context_once(current_context())),
                          get_arg());
    if (get_flag('p'))
      pc = find_prev_once(prev_once(context_once(current_context())),
                          get_arg());
    else if (get_flag('l'))
      pc = find_prev_once(last_once(), get_arg());
    else
      pc = find_next_once(first_once(),get_arg());
    if (pc)
    {
      change_once(current_context(),pc);
    }
    else
      writeline("once not found");
  }
  else
    writeline("current context not defined");
}


void do_cd YPARAMS0
{
  if (current_context())
  {
    if (empty_context(current_context()))
    {                      
      if (local_context(current_context()))
      {
        if (context_local(current_context()))
        {
          do_cl();
        }
        else
        {
          writeline("no locals");
        }
      }
      else /* global_context(current_context()) */
      {
        if (context_once(current_context()))
        {
          do_co();
        }
        else
        {
          writeline("no onces");
        }
      }
    }
    else
    {
      obj_ptr p = top_objarr(current_context());
      if (is_object(p))
      {
        if (top_field(current_context()))
        {
	  do_cf();
        }
        else
          writeline("no fields");	
      }
      else /* is_array(p) */
      {
        do_ce();
      }
    }
  }
  else
    writeline("current context not defined");
}

int exec_pd YPARAMS0
{
  if (current_context())
  {
    if (strlen(get_arg())>0)
      do_cd();
    expand_context(current_context());
  }
  else
    writeline("current context not defined");
  return (exec_ld());
}

int exec_ud YPARAMS0
{
  if (current_context())
  {
    retract_context(current_context());
  }
  else
    writeline("current context not defined");
  return (exec_ld());
}

int exec_rd YPARAMS0
{
  if (current_context())
  {
    reset_context(current_context());
  }
  else
    writeline("current context not defined");
  return(exec_ld());
}



int exec_cd YPARAMS0
{
  do_cd();
  return(exec_ld());
}

void do_ll YPARAMS0
{
  list_locals(context_method(current_context()),
              context_local(current_context()),
              context_call(current_context()),
              "");
}

void do_lf YPARAMS0
{
  list_fields(top_class(current_context()),
              top_field(current_context()),
              top_objarr(current_context()),
              "");
}

void do_le YPARAMS0
{
  unsigned first_subscript,last_subscript;
  unsigned current_subscript;
  unsigned size;
  unsigned number;
  number = page_size/2;
  size = array_size(top_objarr(current_context()));
  current_subscript = top_subscript(current_context());
  if (size <= page_size)
  {
    first_subscript = 0;
    last_subscript = size-1;
  }
  else
  {
    if (current_subscript < number)
    {
      first_subscript = 0;
      last_subscript  = page_size-1;
    }
    else if (current_subscript + number > size -1)
    {
      first_subscript = size-page_size;
      last_subscript = size-1;
    }
    else       
    {
      first_subscript = current_subscript-number;
      last_subscript =  current_subscript+number;
    }
  }                      
  list_elems(top_objarr(current_context()),
             first_subscript,
             last_subscript,
             current_subscript);
}

void do_lo YPARAMS0
{
  list_onces(context_once(current_context()),"");
}

int exec_ld YPARAMS0
{
  if (current_context())
  {
    exec_p();
	  if (empty_context(current_context()))
	  {
      if (local_context(current_context()))
      {
  	    if(context_call(current_context()))
	      {
          do_ll();
  	    }
        else
        {
          writeline("???");
        }      
      }
      else /* global_context(current_context()) */
      {
        if (context_once(current_context()))
        {
          do_lo();
	      }
	      else
        {
          writeline("???");
        }
      }
	  }
	  else
	  {
	    obj_ptr p = top_objarr(current_context());
      writestring("adress ");
      writehex((unsigned) p);
      writeln();
	    if (is_object(p))
	    {
        writestring("dynamic type ");
        writestring(type_name(dynamic_type(p)));
        writeln();
        if (top_class(current_context()))
        {
          do_lf();
          }
          else
          {
            writeline("no class"); 
          }
	    }
	    else /* is_array(p) */
	    {
        writestring("array size ");
        writeint(array_size(p));
        writeln();
        do_le();
	    }
	  }
  }
  else
    writeline("current context not defined");
  on_mode = ON_DATA;
  return(0);
}

int exec_la YPARAMS0
{
  if (current_context())
  {
    if (empty_context(current_context()))
    {
      writeline("not in object");
    }
    else
    {
      assert(0);
    }
  }
  else 
    writeline("current context not defined");
}

int exec_ca YPARAMS0
{
  dbx_class *pc;
  if (current_context())
  {
    if (empty_context(current_context()))
    {
      writeline("not in object");
    }
    else
    {
      if (is_object(top_objarr(current_context())))
      {
        if (get_flag('n'))
          pc =  search_class(parent_class(top_class(current_context())),get_arg());
        else
          pc = search_class(lowest_class(top_objarr(current_context())),get_arg());
        if (pc)
        {
          change_top_class(current_context(),pc);
        }
        else
          writeline("not found");
      }
      else
        writeline("not in object");
    }
  }
  else 
    writeline("current context not defined");
  return(exec_ld());
}



int exec_id YPARAMS0
{
  int code;
  code =apply_descriptor(current_context(),get_arg());
  if (code != ERR_AUTO_OK)
  {
    if (code != ERR_AUTO_SYNTAX)
    {
      writestring(identifier());
      writestring(" ");
    }
    writestring(error_messg(code));
    writeln();
    writestring(first_part());
    highlight_on();
    writechar(the_current());
    highlight_off();
    writestring(second_part());
    writeln();
  }
  return (exec_ld());
}

int exec_tld YPARAMS0
{
  change_call(current_context(),last_call());
  set_current_call(last_call());
  return(exec_ld());
}

int exec_tgd YPARAMS0
{
  change_once(current_context(),first_once());
  return(exec_ld());
}

int exec_puc YPARAMS0
{
return 0;
}

int exec_poc YPARAMS0
{
return 0;
}


/* various commands */

int exec_p YPARAMS0
{
  if (current_context())
  {
    writeline(context_name(current_context()));
  }
  else
    writeline("current context not defined");
  return (0);
}

int exec_o YPARAMS0
{
  change_call(current_context(),last_call());
  set_current_call(last_call());
  do_li();
  return(0);
}

int exec_w YPARAMS0
{
  do_w();
  return(0);
}
/**************************************************************/
int exec_gc YPARAMS0
{
  garbage_collect();
  return(0);
}

/****************************************/
int exec_h YPARAMS0
{
#define DOCMD(a,b,c) writestring(a);writestring(b);writestring(c);writeln();

  open_table();
  set_column(5);
  set_column(48);
  set_column(24);
  compute_table();
  writestring("name");
  writestring("explanation");
  writestring("arguments,options&flags");
  writeln();
  writestring("");
  writestring("");
  writestring("");
  writeln();
  if (!(get_flag('f')||get_flag('p')||get_flag('d')||get_flag('b')||get_flag('w')))
  {
    writestring("h");
    writestring("Help");
    open_subtable();
    writestring("File");
    writestring("Program");
    writestring("Data");
    writestring("Breakpoints");
    writestring("Watches");
    close_subtable();
    writeln();
    DOCMD("o",    "go to Origin","");
    DOCMD("q",  	"Quit","");
    DOCMD("r",	  "Run program","");
    DOCMD("e",    "execute program to End","");
    DOCMD("m",    "Move into next method","");
    DOCMD("u",    "execute Until return","");
    DOCMD("s",	  "Step over method","");
    DOCMD("t",	  "Trace into method","");
    DOCMD("","","");
  }
  if (get_flag('f'))
  {
    DOCMD("li",	  "List Instructions","");
    DOCMD("ci",    "Change Instruction","number");
    DOCMD("gu",   "Go Up a page","");
    DOCMD("gd",   "Go Down a page","");
    DOCMD("gt",   "Go to Top of file","");
    DOCMD("gb",   "Go to Bottom of file","");
    DOCMD("","","");
  }
  if (get_flag('p'))
  {
    DOCMD("lm",   "List Modules","");
    writestring("cm");
    writestring("Change Module");
    open_subtable();
    writestring("[pattern]");
    writestring("Next");
    writestring("Previous");
    writestring("Last");
    close_subtable();
    writeln();  
    DOCMD("","","");
    DOCMD("lc",   "List Classes","");
    DOCMD("lch",  "List Class Hierarchy","");
    writestring("cc");
    writestring("Change Class");
    open_subtable();
    writestring("[pattern]");
    writestring("Next");
    writestring("Previous");
    writestring("Last");
    close_subtable();
    writeln();
    DOCMD("lf","List Fields","");
    DOCMD("","","");
    DOCMD("lp",   "List Procedures (=methods))","");
    DOCMD("lph",  "List Procedure Hierarchy","");
    writestring("cp");
    writestring("Change Procedure (=method)");
    open_subtable();
    writestring("[pattern]");
    writestring("Next");
    writestring("Previous");
    writestring("Last");
    close_subtable();
    writeln();
    DOCMD("ll","List Locals","");
    DOCMD("","","");
  }
  if (get_flag('d'))
  {
    DOCMD("ls", 	"List Stack of calls","");
    writestring("cs");
    writestring("Change Stack frame");
    open_subtable();
    writestring("[pattern]");
    writestring("Next");
    writestring("Previous");
    writestring("Last");
    close_subtable();
    writeln();
    DOCMD("","","");
    DOCMD("ld",   "List Data","");
    writestring("cd");
    writestring("Change Data");
    open_subtable();
    writestring("[pattern]");
    writestring("Next[number]");
    writestring("Previous[number]");
    writestring("Last");
    close_subtable();
    writeln();
    writestring("ca");
    writestring("Change clAss");
    open_subtable();
    writestring("[pattern]");
    writestring("Next");
    close_subtable();
    writeln();
    DOCMD("pd", 	"Plunge Data","[pattern]");
    DOCMD("ud",	  "Unplunge Data","");
    DOCMD("rd",   "Reset Data","");
    DOCMD("tld",  "Toggle to Local Data","");
    DOCMD("tgd",  "Toggle to semi-Global Data","");
    DOCMD("id",    "Inspect Data","descriptor");
    DOCMD("","","");
  }
  if (get_flag('b'))
  {
    DOCMD("lb",	  "List Breakpoints","");
    writestring("sb");
    writestring("Set Breakpoint");
    open_subtable();
    writestring("[line]");
    writestring("Transparent");
    writestring("Step value");
    writestring("Log string");
    close_subtable();
    writeln();
    DOCMD("rb",   "Reset Breakpoint","[line]/number");
    DOCMD("ib",   "Inspect Breakpoint","number");
    DOCMD("","","");
  }
  if (get_flag('w'))
  {
    DOCMD("lw",   "List Watches","");
    writestring("sw");
    writestring("Set Watch");
    writestring("[descriptor]");
    writeln();
    DOCMD("rw",   "Reset Watch","number");
    DOCMD("iw",   "Inspect Watch","number");
    DOCMD("","","");
  }
  close_table();
  writeline("examples:");
  writeline("h -f -d");
  writeline("pd RESULT");
  writeline("cm -n");
  writeline("sb 145 -lGenerateCode");
  writeline("cs -n Activate");
  
#undef DOCMD  
  return(0);
}
/****************************************/

void redraw YPARAMS0
{
  writestring("mode ");
  writeint(on_mode);
  writeln();
  writestring("size ");
  writeint(page_size);
  writeln();
  if (on_mode == ON_LINES)
    do_li();
  else if (on_mode == ON_CALLS)
    exec_ls();
  else if(on_mode == ON_WATCHS)
    exec_lw();
  else if(on_mode == ON_BREAKS)
    exec_lb();
}

/*****************************************************************/

typedef struct
              {
                char *name;
                char *flags;
                char *opts;
                int  args;
                int (*func) YPARAMS0;
              } cmd_type;

static cmd_type cmd[] =
              {
                {"o", "", "", 0, exec_o},
                {"h", "fpdbw", "", 0, exec_h},
                {"q", "", "", 0, exec_q},
                {"r", "", "", 0, exec_r},
                {"e", "", "", 0, exec_e},
                {"m", "", "", 0, exec_m},
                {"u", "", "", 0, exec_u},
                {"s", "", "", 0, exec_s},
                {"t", "", "", 0, exec_t},
                {"li", "", "", 1, exec_li},
                {"ci", "npl", "", 1, exec_ci},
                {"gu", "", "", 0, exec_gu},
                {"gd", "", "", 0, exec_gd},
                {"gt", "", "", 0, exec_gt},
                {"gb", "", "", 0, exec_gb},
                {"lm", "", "", 1, exec_lm},
                {"cm", "npl", "", 1, exec_cm},
                {"lc", "", "", 1, exec_lc},
                {"lch", "", "", 0, exec_lch},
                {"cc", "npl", "", 1, exec_cc},
                {"lf", "", "", 1, exec_lf},
                {"cf", "npl", "", 1, exec_cf},
                {"lp", "", "", 1, exec_lp},
                {"lph", "", "", 0, exec_lph},
                {"cp", "npl", "", 1, exec_cp},
                {"ll", "", "", 1, exec_ll},
                {"cl", "npl", "", 1, exec_cl},
                {"ls", "", "", 1, exec_ls},
                {"cs", "npl", "", 1, exec_cs},
                {"ld", "", "", 1, exec_ld},
                {"cd", "npl", "np", 1, exec_cd},
                {"pd", "", "", 1, exec_pd},
                {"ud", "", "", 1, exec_ud},
                {"rd", "", "", 0, exec_rd},
                {"tld", "", "", 0, exec_tld},
                {"tgd", "", "", 0, exec_tgd},
                {"id", "", "", 1, exec_id},
                {"la", "", "", 1, exec_la},
                {"ca", "npl", "", 1, exec_ca},
                {"lb", "", "", 1, exec_lb},
                {"cb", "npl", "", 1, exec_cb},
                {"sb", "t", "bsl", 1, exec_sb},
                {"rb", "", "", 1, exec_rb},
                {"ib", "", "", 1, exec_ib},
                {"lw", "", "", 1, exec_lw},
                {"cw", "npl", "", 1, exec_cw},
                {"sw", "", "", 1, exec_sw},
                {"rw", "", "", 1, exec_rw},
                {"iw", "", "", 1, exec_iw},
                {"gc", "", "", 0, exec_gc},
                {NULL,  NULL, NULL, 0, NULL}
              };

static char g_flag[26];
static char * g_opt[26];
static char * the_arg;


static int do_token YPARAMS4(cmd_type *, cmd,
	                    char *,	a)
{
  char u, l;
  char *flag, *opt;
  if(*a == '-')
    {
      a++;
      u = toupper(*a);
      l = tolower(*a);
      if((u < 'A') || (u > 'Z'))
        return 0;
/*        
      if(strlen(a) == 1) 
        {
          if (!strchr(cmd->flags,tolower(*a)))
            return 0;
          g_flag[b-'A'] = 1;
        }
       else
        {
          if (!strchr(cmd->opts,tolower(*a)))
            return 0;
          g_opt[b-'A'] = a+1;
        }
*/   
      flag = strchr(cmd->flags, l);
      opt = strchr(cmd->opts, l);
      if((!flag)&&(!opt))
        return 0;
      if (flag)
        g_flag[u - 'A'] = 1;
      if (opt)
        g_opt[u - 'A'] = a + 1;
    }
   else
    {
      if(strlen(the_arg)>0)
        return 0;
      the_arg = a;
    }
  return 1;
}

#define DELIMS " \t"

int    exec_cmd YPARAMS2(char *, line)
{
  char *a;
  cmd_type *c;

  memset(g_flag, 0, sizeof(g_flag));
  memset(g_opt,  0, sizeof(g_opt));
  the_arg = "";
  a = strtok(line, DELIMS);
  if (!a)
    return(0);
  c = cmd;
  while(c->name)
    {
      if(strcmp(a, c->name) == 0)
        {
          a = strtok(NULL, DELIMS);
          while(a)
            {
              if(!do_token(c,a))
              {
                writeline("unknown flag/option");
                return 0;
              }
              a = strtok(NULL, DELIMS);
            }
          return((*(c->func))());
        }
      c++;
    }
    writeline("unknown command");
    return 0;
}

int    get_flag YPARAMS2(char, key)
{
  key=toupper(key);
  assert(key>='A');
  assert(key<='Z');
  return g_flag[key-'A'];
}

char * get_opt YPARAMS2(char, key)
{
  char *p, *q;

  key=toupper(key);
  assert(key>='A');
  assert(key<='Z');
  p = g_opt[key-'A'];
  if (p)
  {
    q = strchr(p,' ');
    if(q)
      *q = 0;
  }
  return p;
}

char * get_arg YPARAMS0
{
  return the_arg;
}


