Logo Search packages:      
Sourcecode: gambas version File versions  Download package

gbx_trace.c

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

  trace.c

  The debugger

  (c) 2000-2004 Benoît Minisini <gambas@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 1, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

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

#define __GBX_TRACE_C

#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_common_case.h"

#include <unistd.h>
#include <signal.h>
#include <fcntl.h>

#include "gb_error.h"
#include "gbx_type.h"
#include "gbx_debug.h"
#include "gb_limit.h"
#include "gbx_stack.h"
#include "gbx_class.h"
#include "gbx_exec.h"
#include "gbx_local.h"
#include "gbx_object.h"
#include "gbx_c_application.h"

#include "gbx_eval.h"

#include "gbx_trace.h"

/*#define DEBUG_ME*/

PUBLIC TRACE_GLOBAL TRACE = { 0 };

PRIVATE TRACE_BREAK *Breakpoint;
PRIVATE bool Error;

EVAL_INTERFACE EVAL;

static int _fdr;
static int _fdw;
static FILE *_out;
static FILE *_in;



PUBLIC void TRACE_break_on_next_line(void)
{
  TRACE.stop = TRUE;
  TRACE.fp = NULL;
  TRACE.bp = NULL;
}


PRIVATE void new_line(void)
{
  fprintf(_out, "\n");
}


PRIVATE void signal_user(int sig)
{
  signal(SIGUSR1, signal_user);

  #ifdef DEBUG_ME
  fprintf(stderr, "Got SIGUSR1\n");
  #endif

  /*CAPP_got_signal();*/
  TRACE_break_on_next_line();
}


PRIVATE boolean calc_line_from_position(CLASS *class, FUNCTION *func, PCODE *addr, ushort *line)
{
  int i;
  ushort pos = addr - func->code;
  ushort *post;

  if (func->debug)
  {
    post =  func->debug->pos;
    for (i = 0; i < (func->debug->nline - 1); i++)
    {
      if (pos >= post[i] && pos < post[i + 1])
      {
        *line = i + func->debug->line;
        return FALSE;
      }
    }

    /*printf("pos = %d addr=%p func->code=%p\n", pos, addr, func->code);*/
  }

  return TRUE;
}


PRIVATE boolean calc_position_from_line(CLASS *class, ushort line, FUNCTION **function, PCODE **addr)
{
  int i;
  ushort pos, pos_after;
  FUNCTION *func = NULL;
  FUNC_DEBUG *debug = NULL;

  for (i = 0; i < class->load->n_func; i++)
  {
    func = &class->load->func[i];
    debug = func->debug;
    if (debug && line >= debug->line && line < (debug->line + debug->nline))
      break;
  }

  if (i >= class->load->n_func)
    return TRUE;

  line -= debug->line;

  for(;;)
  {
    pos = debug->pos[line];
    pos_after = debug->pos[line + 1];
    if (pos != pos_after)
      break;

    line++;
    if (line >= debug->nline)
      return TRUE;
  }

  *function = func;
  *addr = &func->code[pos];

  /*printf("%s.%d -> %04X\n", class->name, line + debug->line, **addr);*/

  return FALSE;
}


PRIVATE bool get_value(const char *sym, long len, GB_VARIANT *ret)
{
  int i;
  VALUE value;
  LOCAL_SYMBOL *lp;
  GLOBAL_SYMBOL *gp;
  CLASS_VAR *var;
  char *addr;

  if (TRACE.fp)
  {
    for (i = 0; i < TRACE.fp->debug->n_local; i++)
    {
      lp = &TRACE.fp->debug->local[i];
      if (len == lp->sym.len && strncasecmp(sym, lp->sym.name, len) == 0)
      {
        value = TRACE.bp[lp->value];
        goto __FOUND;
      }
    }
  }

  if (TRACE.cp)
  {
    for (i = 0; i < TRACE.cp->load->n_global; i++)
    {
      gp = &TRACE.cp->load->global[i];
      if (len != gp->sym.len || strncasecmp(sym, gp->sym.name, len) != 0)
        continue;
        
      if (CTYPE_get_kind(gp->ctype) != TK_VARIABLE)
        continue;
        
      if (!CTYPE_is_static(gp->ctype) && TRACE.op)
      {
        var = &TRACE.cp->load->dyn[gp->value];
        addr = (char *)TRACE.op + var->pos;
      }
      else
      {
        var = &TRACE.cp->load->stat[gp->value];
        addr = (char *)TRACE.cp->stat + var->pos;
      }

      VALUE_class_read(TRACE.cp, &value, addr, var->type);
      goto __FOUND;
    }
  }

  /*printf("Unknown symbol %.*s\n", (int)len, sym);

  ret->type = GB_T_NULL;*/
  return TRUE;

__FOUND:

  /*printf("%.*s =", (int)len, sym);
  print_value(&value);*/

  BORROW(&value);
  if (value.type == T_ARRAY)
    value._array.keep = TRUE;
  else
    VALUE_conv(&value, T_VARIANT);
  UNBORROW(&value);

  *((VALUE *)ret) = value;
  return FALSE;
}


PUBLIC void TRACE_init(void)
{
  char path[MAX_PATH];

  if (!EXEC_debug)
    return;

  LIBRARY_get_interface_by_name("gb.eval", EVAL_INTERFACE_VERSION, &EVAL);
  
  if (EXEC_fifo)
  {
    sprintf(path, "/tmp/gambas.%d/%d.out", getuid(), getppid());
    _fdr = open(path, O_RDONLY);
    sprintf(path, "/tmp/gambas.%d/%d.in", getuid(), getppid());
    _fdw = open(path, O_WRONLY);
    
    _in = fdopen(_fdr, "r");
    _out = fdopen(_fdw, "w");
    
    if (!_in || !_out)
      ERROR_panic("Cannot open fifos");
    
    setlinebuf(_in); /*setvbuf(_in, NULL, _IOLBF, 0);*/
    setlinebuf(_out); /*setvbuf(_out, NULL, _IOLBF, 0);*/
  }
  else
  {
    _in = stdin;
    _out = stdout;
  }
  
  ARRAY_create(&Breakpoint);
  signal(SIGUSR1, signal_user);
  signal(SIGPIPE, SIG_IGN);
}

/*
PUBLIC void TRACE_check_signal(void)
{
  static bool msg = FALSE;
  struct sigaction action;

  if (msg)
    return;

  sigaction(SIGUSR1, NULL, &action);
  if (action.sa_handler != signal_user)
  {
    fprintf(stderr, "SIGUSR1 handler has changed !\n");
    msg = TRUE;
  }
  else
  {
    fprintf(stderr, "OK\n");
  }
}
*/

PUBLIC void TRACE_exit(void)
{
  ARRAY_delete(&Breakpoint);

  /*  
  if (EXEC_fifo)
  {
    fclose(_in);
    fclose(_out);
  }
  */
}


PRIVATE int find_free_breakpoint(void)
{
  int i;
  char used[MAX_BREAKPOINT];

  memset(used, FALSE, MAX_BREAKPOINT);

  for (i = 0; i < ARRAY_count(Breakpoint); i++)
    used[Breakpoint[i].id - 1] = TRUE;

  for (i = 0; i < MAX_BREAKPOINT; i++)
    if (!used[i])
      return (i + 1);

  return 0;
}


PRIVATE boolean set_breakpoint(CLASS *class, ushort line)
{
  PCODE *addr = NULL;
  TRACE_BREAK *brk;
  int id;
  FUNCTION *func;

  if (ARRAY_count(Breakpoint) >= MAX_BREAKPOINT)
  {
    fprintf(_out, "Too many breakpoints (max = %d)\n", MAX_BREAKPOINT);
    return TRUE;
  }

  if (CLASS_is_native(class) || !class->debug)
  {
    fprintf(_out, "No debugging information\n");
    return TRUE;
  }

  if (calc_position_from_line(class, line, &func, &addr))
  {
    fprintf(_out, "Cannot calc position from line number\n");
    return TRUE;
  }

  if (!PCODE_is_breakpoint(*addr))
  {
    fprintf(_out, "Not a line beginning ?\n");
    return TRUE;
  }

  if (*addr & 0xFF)
  {
    fprintf(_out, "Breakpoint already set\n");
    return TRUE;
  }

  id = find_free_breakpoint();
  if (id == 0)
  {
    fprintf(_out, "Cannot create breakpoint\n");
    return TRUE;
  }

  brk = ARRAY_add(&Breakpoint);

  brk->id = id;
  /*brk->func = func;*/
  brk->addr = addr;
  brk->class = class;
  brk->line = line;

  *addr = PCODE_BREAKPOINT(id);
  
  #ifdef DEBUG_ME
  fprintf(stderr, "set_breakpoint: %s.%d\n", class->name, line);
  #endif

  return FALSE;
}


PRIVATE boolean unset_breakpoint(CLASS *class, ushort line)
{
  int i;

  for (i = 0; i < ARRAY_count(Breakpoint); i++)
  {
    if (Breakpoint[i].class == class && Breakpoint[i].line == line)
    {
      *(Breakpoint[i].addr) = PCODE_BREAKPOINT(0);
      ARRAY_remove(&Breakpoint, i);
      
      #ifdef DEBUG_ME
      fprintf(stderr, "unset_breakpoint: %s.%d\n", class->name, line);
      #endif

      return FALSE;
    }
  }

  fprintf(_out, "Unknown breakpoint\n");
  return TRUE;
}


/*
PRIVATE boolean reset_breakpoint(int num)
{
  TRACE_BREAK *tb;

  if (num < 0 || num >= MAX_BREAKPOINT)
    return TRUE;

  tb = &Breakpoint[num];

  if (tb->addr == NULL)
    return TRUE;

  *(tb->addr) = tb->value;

  EXEC_stop_next = TRUE;
  Reset_breakpoint = num;

  return FALSE;
}


PUBLIC ushort TRACE_get_current_line(void)
{
  int i;
  ushort pos = PC - FP->code;

  if (FP->debug)
  {
    for (i = 0; i < (FP->debug->nline - 1); i++)
    {
      if (pos >= FP->debug->pos[i] && pos < FP->debug->pos[i + 1])
        return i + FP->debug->line;
    }
  }

  return 0;
}
*/


PRIVATE void command_quit(const char *cmd)
{
  exit(1);
}

PRIVATE void command_go(const char *cmd)
{
  TRACE.stop = FALSE;
  TRACE.fp = NULL;
  TRACE.bp = NULL;
}

PRIVATE void command_step(const char *cmd)
{
  TRACE_break_on_next_line();
}

PRIVATE void command_next(const char *cmd)
{
  TRACE.stop = TRUE;
  TRACE.fp = FP;
  TRACE.bp = BP;
}

PRIVATE void command_from(const char *cmd)
{
  STACK_CONTEXT *sc = STACK_get_current();

  if (sc)
  {
    TRACE.stop = TRUE;
    TRACE.fp = sc->fp;
    TRACE.bp = sc->bp;
  }
  else
    command_go(cmd);
}


PRIVATE void command_set_breakpoint(const char *cmd)
{
  char class_name[64];
  CLASS *class;
  ushort line;

  if (sscanf(cmd, "+%64[^.].%hu", class_name, &line) != 2)
    fprintf(_out, "Syntax error\n");
  else
  {
    class = CLASS_find(class_name);
    CLASS_load_without_init(class);
    set_breakpoint(class, line);
  }
}


PRIVATE void command_unset_breakpoint(const char *cmd)
{
  char class_name[64];
  CLASS *class;
  ushort line;

  if (sscanf(cmd, "-%64[^.].%hu", class_name, &line) != 2)
    fprintf(_out, "Syntax error\n");
  else
  {
    class = CLASS_find(class_name);
    CLASS_load_without_init(class);
    unset_breakpoint(class, line);
  }
}


PRIVATE void command_where(const char *cmd)
{
  int i;
  STACK_CONTEXT *context;
  ushort line;

  if (CP)
    fprintf(_out, "%s", TRACE_get_current_position());
  else
    fprintf(_out, "?");

  for (i = 0; i < (STACK_frame_count - 1); i++)
  {
    context = &STACK_frame[i];

    if (context->pc)
    {
      line = 0;
      if (calc_line_from_position(context->cp, context->fp, context->pc, &line))
        fprintf(_out, " %s.?.?", context->cp->name);
      else
        fprintf(_out, " %s.%s.%d", context->cp->name, context->fp->debug->name, line);
    }
    else if (context->cp)
      fprintf(_out, " ?");
  }

  if (Error)
  {
    fprintf(_out, "*");
    ERROR_print_at(_out);
  }
  else
    new_line();
}


PRIVATE void to_string(VALUE *value, char **addr, long *len, boolean *more)
{
  static void *jump[16] = {
    &&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__DATE,
    &&__STRING, &&__STRING, &&__VARIANT, &&__ARRAY, &&__STRUCT, &&__FUNCTION, &&__CLASS, &&__NULL
    };

  VALUE conv;

  *more = FALSE;

__CONV:

  if (TYPE_is_object(value->type))
    goto __OBJECT;
  else
    goto *jump[value->type];

__NULL:

  *addr = "NULL";
  *len = 4;
  return;

__BOOLEAN:

  if (value->_boolean.value)
  {
    *addr = "TRUE";
    *len = 4;
  }
  else
  {
    *addr = "FALSE";
    *len = 5;
  }
  return;

__BYTE:
__SHORT:
__INTEGER:

  *len = sprintf(COMMON_buffer, "%ld", value->_integer.value);
  *addr = COMMON_buffer;

  return;

__DATE:

  LOCAL_format_date(DATE_split(value), LF_STANDARD, NULL, 0, addr, len);
  return;

__FLOAT:

  LOCAL_format_number(value->_float.value, LF_STANDARD, NULL, 0, addr, len, TRUE);
  return;

__STRING:

  {
    int i;
    char *d;
    const char *s;
    uchar c;

    s = value->_string.addr + value->_string.start;
    d = COMMON_buffer;

    *d++ = '"';

    for (i = 0; i < value->_string.len; i++)
    {
      if (i > 128)
      {
        strcat(d, "...");
        *len += 3;
        break;
      }

      c = s[i];

      if (c < 32)
      {
        *d++ = '\\';

        if (c == 10)
          *d++ = 'n';
        else if (c == 13)
          *d++ = 'r';
        else if (c == 9)
          *d++ = 't';
        else
          d += sprintf(d, "x%02X", c);
      }
      else if (c == '\"')
      {
        *d++ = '\\';
        *d++ = c;
      }
      else
      {
        *d++ = c;
      }
    }

    *d++ = '"';

    *addr = COMMON_buffer;
    *len = d - COMMON_buffer;
  }

  return;

__OBJECT:

  if (VALUE_is_null(value))
    goto __NULL;

  *more = !CLASS_is_native(OBJECT_class(value->_object.object));

  *len = sprintf(COMMON_buffer, "%s %p", OBJECT_class(value->_object.object)->name, value->_object.object);
  *addr = COMMON_buffer;
  return;

__VARIANT:

  conv = *value;
  value = &conv;
  VARIANT_undo(value);
  goto __CONV;

__VOID:

  *addr = "(void)";
  *len = 6;
  return;

__CLASS:

  {
    CLASS *class = value->_class.class;
    *more = (!CLASS_is_native(class) && class->load->n_stat > 0);

    *len = sprintf(COMMON_buffer, "%s %p", class->name, class);
    *addr = COMMON_buffer;
    return;
  }

__ARRAY:

  *len = sprintf(COMMON_buffer, "ARRAY %p", value->_array.addr);
  *addr = COMMON_buffer;
  return;

__LONG:
__STRUCT:
__FUNCTION:

  THROW(E_TYPE, TYPE_get_name(T_STRING), TYPE_get_name(value->type));
}


PUBLIC void print_value(VALUE *value, bool format)
{
  char *pval;
  long lpval;
  boolean more;

  if (format)
    to_string(value, &pval, &lpval, &more);
  else
    VALUE_to_string(value, &pval, &lpval);

  fprintf(_out, "%.*s\n", (int)lpval, pval);
}


PRIVATE void command_local(const char *cmd)
{
  int i;
  LOCAL_SYMBOL *lp;
  bool nl = TRUE;

  if (FP)
  {
    if (cmd[1] == 0)
    {
      for (i = 0; i < FP->debug->n_local; i++)
      {
        lp = &FP->debug->local[i];
        fprintf(_out, "%.*s ", lp->sym.len, lp->sym.name);
      }
    }
    else
    {
      cmd++;

      for (i = 0; i < FP->debug->n_local; i++)
      {
        lp = &FP->debug->local[i];
        if (lp->sym.len == strlen(cmd) && strncasecmp(lp->sym.name, cmd, lp->sym.len) == 0)
        {
          fprintf(_out, "=");
          print_value(&BP[lp->value], TRUE);
          nl = FALSE;
          break;
        }
      }
    }
  }

  if (nl)
    new_line();
}


PRIVATE void print_symbol(GLOBAL_SYMBOL *gp, bool is_static, bool is_public)
{
  if (CTYPE_get_kind(gp->ctype) != TK_VARIABLE)
    return;

  if (CTYPE_is_static(gp->ctype) && !is_static)
    return;

  if (!CTYPE_is_static(gp->ctype) && is_static)
    return;

  if (CTYPE_is_public(gp->ctype) && !is_public)
    return;

  if (!CTYPE_is_public(gp->ctype) && is_public)
    return;

  fprintf(_out, "%.*s ", gp->sym.len, gp->sym.name);
}


PRIVATE void command_object(const char *cmd)
{
  int i;
  GLOBAL_SYMBOL *gp;

  if (CP)
  {
    fprintf(_out, "S: ");

    for (i = 0; i < CP->load->n_global; i++)
    {
      gp = &CP->load->global[i];
      print_symbol(gp, TRUE, TRUE);
    }

    fprintf(_out, "s: ");

    for (i = 0; i < CP->load->n_global; i++)
    {
      gp = &CP->load->global[i];
      print_symbol(gp, TRUE, FALSE);
    }
  }

  if (OP)
  {
    fprintf(_out, "D: ");

    for (i = 0; i < CP->load->n_global; i++)
    {
      gp = &CP->load->global[i];
      print_symbol(gp, FALSE, TRUE);
    }

    fprintf(_out, "d: ");

    for (i = 0; i < CP->load->n_global; i++)
    {
      gp = &CP->load->global[i];
      print_symbol(gp, FALSE, FALSE);
    }
  }

  new_line();
}

/*
PRIVATE void old_command_local(char *cmd)
{
  int i;
  VALUE value;
  int index;
  LOCAL_SYMBOL *lp;

  if (CP == NULL)
    return;

  if (OP)
  {
    value.type = T_OBJECT;
    value._object.class = CP;
    value._object.object = OP;
    print_value("ME", 0, &value);
  }
  else
  {
    value.type = T_CLASS;
    value._class.class = CP;
    print_value("CLASS", 0, &value);
  }

  if (FP == NULL)
    return;

  for (i = 0; i < FP->debug->n_local; i++)
  {
    lp = &FP->debug->local[i];
    index = lp->value;
    value = BP[index];
    print_value(lp->sym.name, lp->sym.len, &value);
  }
}
*/

#if 0
PRIVATE void command_print(char *cmd)
{
  OBJECT *object;
  CLASS *class;
  int i;
  VALUE value;
  GLOBAL_SYMBOL *gp;
  CLASS_VAR *var;
  char *addr;

  if (CP == NULL)
    return;

  if (sscanf(cmd, "?%p", &object) != 1)
  {
    printf("Syntax error\n");
    return;
  }

  if (object == NULL)
  {
    printf("Null pointer\n");
    return;
  }

  class = OBJECT_class(object);
  if (class == CLASS_Class)
  {
    class = (CLASS *)object;
    object = NULL;
  }
  else
  {
    value.type = T_CLASS;
    value._class.class = class;
    print_value("CLASS", 0, &value);
  }

  if (CLASS_is_native(class))
    return;

  if (object == NULL)
  {
    for (i = 0; i < class->load->n_global; i++)
    {
      gp = &class->load->global[i];

      if (CTYPE_get_kind(gp->ctype) != TK_VARIABLE)
        continue;

      if (!CTYPE_is_static(gp->ctype))
        continue;

      var = &class->load->stat[gp->value];
      addr = (char *)class->stat + var->pos;

      VALUE_class_read(class, &value, addr, var->type);
      print_value(gp->sym.name, gp->sym.len, &value);
    }
  }
  else
  {
    for (i = 0; i < class->load->n_global; i++)
    {
      gp = &class->load->global[i];

      if (CTYPE_get_kind(gp->ctype) != TK_VARIABLE)
        continue;

      if (CTYPE_is_static(gp->ctype))
        continue;

      /*if ((object == NULL) ^ (CTYPE_is_static(gp->ctype)))
        continue;*/

      if (!CTYPE_is_static(gp->ctype))
      {
        var = &class->load->dyn[gp->value];
        addr = (char *)object + var->pos;
      }
      else
      {
        var = &class->load->stat[gp->value];
        addr = (char *)class->stat + var->pos;
      }

      VALUE_class_read(class, &value, addr, var->type);
      print_value(gp->sym.name, gp->sym.len, &value);
    }
  }
}
#endif

PRIVATE void command_error(const char *cmd)
{
  if (Error)
    ERROR_print_at(stdout);
  else
    fprintf(_out, "OK\n");
}

/*
PRIVATE void command_info(char *cmd)
{
  printf("w:\n");
  command_where(cmd);
  printf("l:\n");
  command_local(cmd);
  printf("e:\n");
  command_error(cmd);
}
*/

PRIVATE void command_print(const char *cmd)
{
  EXPRESSION *expr;
  ERROR_INFO save;

  ERROR_save(&save);

  EVAL.New((void **)&expr, &cmd[1], strlen(&cmd[1]));

  if (EVAL.Compile(expr))
    goto __ERROR;

  TRACE.bp = BP;
  TRACE.fp = FP;
  TRACE.op = OP;
  TRACE.cp = CP;

  /*EVAL_debug = TRUE;*/

  if (EVAL.Run(expr, get_value))
    goto __ERROR;

  if (*cmd == '?')
    fprintf(_out, "=");

  print_value(&TEMP, *cmd == '?');

  goto __FREE;

__ERROR:
  fprintf(_out, "%s\n", ERROR_info.msg);

__FREE:
  EVAL.Free((void **)&expr);

  TRACE.cp = NULL;

  ERROR_restore(&save);
}

PUBLIC void TRACE_main(boolean error)
{
  static TRACE_TYPE last_command = TC_NONE;

  static TRACE_COMMAND Command[] =
  {
    { "q", TC_NONE, command_quit, FALSE },
    { "n", TC_NEXT, command_next, FALSE },
    { "s", TC_STEP, command_step, FALSE },
    { "f", TC_FROM, command_from, FALSE },
    { "g", TC_GO, command_go, FALSE },
    { "+", TC_NONE, command_set_breakpoint, TRUE },
    { "-", TC_NONE, command_unset_breakpoint, TRUE },
    { "w", TC_NONE, command_where, TRUE },
    { "l", TC_NONE, command_local, TRUE },
    { "?", TC_NONE, command_print, TRUE },
    { "!", TC_NONE, command_print, TRUE },
    { "o", TC_NONE, command_object, TRUE },
    { "e", TC_NONE, command_error, TRUE },
    { NULL }
  };


  char cmd[256];
  int len;
  TRACE_COMMAND *tc = NULL;
  /*static int cpt = 0;*/

  Error = error;

  fflush(NULL);

  #ifdef DEBUG_ME
  fprintf(stderr, "TRACE_main {\n");
  #endif

  if (EXEC_fifo)
    fprintf(_out, "!\n");

  do
  {
    /*if (CP == NULL)
      printf("[]:");
    else
      printf("[%s%s]:", TRACE_get_current_position(), Error ? "*" : "");*/

    if (!EXEC_fifo)
    {
      command_where(NULL);
      if (Error)
        fprintf(_out, "*");
      else
        fprintf(_out, ":");
      fflush(NULL);
    }

    *cmd = 0;

    if (fgets(cmd, sizeof(cmd), _in) == NULL)
    {
      ERROR_panic("Debugger cannot read input: %s", strerror(errno));
    }

    len = strlen(cmd);
    if (len > 0 && cmd[len - 1] == '\n')
      cmd[len - 1] = 0;

    #ifdef DEBUG_ME
    fprintf(stderr, "--> %s\n", cmd);
    #endif

    if (*cmd == 0)
    {
      if (last_command == TC_NONE)
        continue;

      for (tc = Command; tc->pattern; tc++)
      {
        if (tc->type == last_command)
        {
          (*tc->func)(cmd);
          break;
        }
      }
    }
    else
    {
      for (tc = Command; tc->pattern; tc++)
      {
        if (strncasecmp(tc->pattern, cmd, strlen(tc->pattern)) == 0)
        {
          if (tc->type != TC_NONE)
            last_command = tc->type;
          (*tc->func)(cmd);
          break;
        }
      }
    }

    if (tc->pattern == NULL)
      fprintf(_out, "Unknown command: %s\n", cmd);

    fflush(_out);
  }
  while (last_command == TC_NONE || tc->pattern == NULL || tc->loop);

  #ifdef DEBUG_ME
  fprintf(stderr, "} TRACE_main\n");
  #endif
}



PUBLIC void TRACE_breakpoint(int id)
{
  TRACE_main(FALSE);
}


PUBLIC const char *TRACE_get_position(CLASS *cp, FUNCTION *fp, PCODE *pc)
{
#if DEBUG_MEMORY
  static char buffer[256];
#endif
  ushort line = 0;

  if (fp != NULL && fp->debug)
    calc_line_from_position(cp, fp, pc, &line);

#if DEBUG_MEMORY
  sprintf(buffer, "%s.%s.%d",
    cp ? cp->name : "?",
    (fp && fp->debug) ? fp->debug->name : "?",
    line);

  return buffer;
#else
  sprintf(COMMON_buffer, "%s.%s.%d",
    cp ? cp->name : "?",
    (fp && fp->debug) ? fp->debug->name : "?",
    line);

  return COMMON_buffer;
#endif
}


PUBLIC const char *TRACE_get_current_position(void)
{
  return TRACE_get_position(CP, FP, PC);
}


PUBLIC void TRACE_where(void)
{
  fprintf(_out ? _out : stdout, "%s: ", TRACE_get_current_position());
}


PUBLIC void TRACE_welcome(void)
{
  if (!EXEC_fifo)
    fprintf(_out, TRACE_WELCOME);
}

Generated by  Doxygen 1.6.0   Back to index