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

tree.c

/* Copyright (C) 1995 Bjoern Beutel. */

/* Description. =============================================================*/

/* Read in and display Malaga Variables. */

/* Includes. ================================================================*/

#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <setjmp.h>
#include <ctype.h>
#include <string.h>
#include <gtk/gtk.h>
#include "basic.h"
#include "scanner.h"
#include "input.h"
#include "canvas.h"
#include "tree.h"

/* Constants. ===============================================================*/

enum {FIRST_STATE, NEXT_STATE, PREV_STATE, LAST_STATE};

/* Types. ===================================================================*/

typedef enum {INTER_NODE, BREAK_NODE, FINAL_NODE, UNFINAL_NODE,
            PRUNED_NODE} tree_node_type_t;

typedef struct tree_node 
{ 
  struct tree_node *parent; /* Parent of this tree node. */
  struct tree_node *sibling; /* Next sibling of this tree node. */
  struct tree_node *child; /* First successor of this tree node. */
  int_t index; /* Index of this tree node. */
  tree_node_type_t type; /* Type of this node. */
  string_t rule_name; /* Name of rule that created this node. */
  string_t link_surf;
  string_t link_fs;
  string_t result_surf;
  string_t result_fs;
  string_t rule_set;
  bool_t result_path;

  /* The following items are used to display the tree node. */
  bool_t in_path; /* TRUE iff this node is in displayed path. */
  int_t x, y; /* Node position. */
  pos_string_t *pos_rule_name; /* Positioned rule name. */
  pos_string_t *pos_link_surf; /* Positioned link surface. */
} tree_node_t;

typedef struct
{
  list_node_t *next; /* Next path node in this list. */
  pos_string_t *index;
  pos_string_t *link_surf;
  pos_value_t *link_fs;
  pos_string_t *rule_name;
  pos_string_t *result_surf;
  pos_value_t *result_fs;
  pos_string_t *rule_set;
} path_node_t;

/* Global variables. ========================================================*/

rectangle_t tree_geometry, path_geometry;
string_t tree_font_name, path_font_name;
int_t tree_font_size, path_font_size;

/* Variables. ===============================================================*/

/* Information in Tree window. */
static pos_string_t *result_surf;
static tree_node_t *tree_nodes;
static tree_node_t **nodes; /* A dynamic array of node pointers. */
static int_t node_count; /* Size of the array NODES. */
static int_t width, height; /* Width and height of tree window. */
static canvas_t *tree_canvas;
static enum {FULL_TREE, NO_DEAD_ENDS, RESULT_PATHS} tree_mode;

/* Information in Path window. */
static list_t path_nodes;
static canvas_t *path_canvas;
static pos_string_t *plus;
static tree_node_t *path_begin, *path_end;
static bool_t in_line; /* If TRUE, feature structures are shown in line. */

/* Forward declarations. ====================================================*/

static void goto_state( canvas_t *canvas, guint action );

/* Functions. ===============================================================*/

static string_t
parse_optional_value( string_t *input )
/* Parse "{}" or "{VALUE}" in *INPUT and return NULL or VALUE, resp.
 * Update *INPUT. The result must bee freed after use. */
{
  string_t s, value;
  
  if (**input != '{') 
    complain( "Missing \"{\"." );
  for (s = *input + 1; *s != '}'; s++)
  {
    if (*s == EOS) 
      complain( "Missing \"}\"." );
    if (*s == '\"') 
    {
      for (s++; *s != '\"'; s++)
      {
      if (*s == EOS) 
        complain( "Missing '\"'." );
      if (s[0] == '\\' && s[1] == '\"') 
        s++;
      }
    }
  }
  if (s > *input + 1) 
    value = new_string( *input + 1, s );
  else 
    value = NULL;
  *input = s + 1;
  parse_whitespace( input );
  return value;
}

/*---------------------------------------------------------------------------*/

static void
configure_path( canvas_t *canvas, int_t *width_p, int_t *height_p )
/* Do the layout of the path CANVAS. 
 * Return the canvas' total size in *WIDTH_P and *HEIGHT_P. */
{
  int_t width, height;
  path_node_t *node;
  bool_t is_first;
  int_t space_width = get_space_width( canvas );
  int_t font_height = get_font_height( canvas );
  int_t font_ascent = get_font_ascent( canvas );
  int_t border_width = get_border_width( canvas );
  
  config_pos_string( plus, canvas );

  width = height = border_width;
  is_first = TRUE;

  FOREACH( node, path_nodes )
  {
    if (node->link_fs != NULL)
    {
      if (is_first) 
      is_first = FALSE; 
      else 
      height += font_height;
      
      config_pos_string( node->link_surf, canvas );
      node->link_surf->x = border_width + plus->width + space_width;
      width = MAX( width, node->link_surf->x + node->link_surf->width );
      
      config_pos_value( node->link_fs, canvas );
      node->link_fs->x = node->link_surf->x;
      if (in_line)
      {
      node->link_surf->y = height + node->link_fs->ascent - font_ascent;
      node->link_fs->x += node->link_surf->width + 2 * space_width;
      }
      else
      {
      node->link_surf->y = height;
      height += font_height;
      }
      node->link_fs->y = height;
      width = MAX( width, node->link_fs->x + node->link_fs->width );
      height += node->link_fs->height;
    }
    if (node->result_fs != NULL)
    {
      if (is_first) 
      is_first = FALSE; 
      else 
      height += font_height;

      config_pos_string( node->rule_name, canvas );
      node->rule_name->x = border_width;
      node->rule_name->y = height;
      config_pos_string( node->index, canvas );
      node->index->x = (node->rule_name->x + node->rule_name->width 
                  + 2 * space_width);
      node->index->y = height;
      config_pos_string( node->result_surf, canvas );
      node->result_surf->x = (node->index->x + node->index->width 
                        + 2 * space_width);
      node->result_surf->y = height;
      width = MAX( width, node->result_surf->x + node->result_surf->width );
      if (! in_line) 
      height += font_height;

      /* Configure result feature structure. */
      config_pos_value( node->result_fs, canvas );
      node->result_fs->y = height;
      if (in_line)
      {
      node->result_fs->x = (node->result_surf->x + node->result_surf->width
                        + 2 * space_width);
      }
      else
      {
      node->result_fs->x = node->result_surf->x;
      height += node->result_fs->height;
      }
      width = MAX( width, node->result_fs->x + node->result_fs->width );

      /* Configure rule set. */
      config_pos_string( node->rule_set, canvas );
      node->rule_set->y = height;
      if (in_line)
      {
      node->rule_set->x = (node->result_fs->x +node->result_fs->width 
                       + 2 * space_width);
      node->rule_name->y 
        = node->index->y 
        = node->result_surf->y 
        = node->rule_set->y
        = height + node->result_fs->ascent - font_ascent;
      height += node->result_fs->height;
      }
      else
      {
      node->rule_set->x = node->result_surf->x;
      height += font_height;
      }
      width = MAX( width, node->rule_set->x + node->rule_set->width );
    }
  }

  *width_p = width + border_width;
  *height_p = height + border_width;
}

/*---------------------------------------------------------------------------*/

static void
expose_path( canvas_t *canvas, rectangle_t *area )
{
  path_node_t *node;
  int_t x1, x2, y;
  int_t space_width = get_space_width( canvas );
  int_t font_height = get_font_height( canvas );
  int_t border_width = get_border_width( canvas );

  set_color( BLACK );

  FOREACH( node, path_nodes )
  {
    if (node->link_fs != NULL)
    {
      plus->x = border_width;
      plus->y = node->link_surf->y;
      draw_pos_string( plus, canvas );
      draw_pos_string( node->link_surf, canvas );
      draw_pos_value( node->link_fs, canvas );
    }
    if (node->result_fs != NULL)
    {
      x1 = node->rule_name->x;
      x2 = x1 + node->rule_name->width + space_width;
      y = node->rule_name->y + font_height + 1;
      draw_pos_string( node->rule_name, canvas );
      draw_lines( 2, x1, y, x2, y );
      draw_lines( 3, 
              x2 - space_width, y - space_width / 2,
              x2, y, 
              x2 - space_width, y + space_width / 2 );
      draw_pos_string( node->index, canvas );
      draw_pos_string( node->result_surf, canvas );
      draw_pos_string( node->rule_set, canvas );
      draw_pos_value( node->result_fs, canvas );
    }
  }
}

/*---------------------------------------------------------------------------*/

static void
free_path( void )
{
  path_node_t *path_node;
  int_t i;

  /* Clear old path nodes. */
  FOREACH_FREE( path_node, path_nodes )
  {
    free_pos_string( &path_node->index );
    free_pos_value( &path_node->link_fs );
    free_pos_value( &path_node->result_fs );
  }

  /* Unmark all tree nodes. */
  for (i = 0; i < node_count; i++)
  {
    if (nodes[i] != NULL) 
      nodes[i]->in_path = FALSE;
  }
}

/*---------------------------------------------------------------------------*/

static void
close_path( canvas_t *canvas )
{
  free_path();
  path_begin = path_end = NULL;
  redraw_canvas( tree_canvas );
}

/*---------------------------------------------------------------------------*/

static void 
set_in_line( canvas_t *canvas, guint action, GtkWidget *item )
{
  in_line = GTK_CHECK_MENU_ITEM( item )->active;
  configure_canvas( canvas );
}

/*---------------------------------------------------------------------------*/

static GtkItemFactoryEntry path_items[] = 
{
  { "/Style/Inline", NULL, set_in_line, 0, "<ToggleItem>" },
  { "/End States", NULL, NULL, 0, "<Branch>" },
  { "/End States/Show First", "<Control>F", goto_state, FIRST_STATE, NULL },
  { "/End States/Show Previous", "<Control>P", goto_state, PREV_STATE, NULL },
  { "/End States/Show Next", "<Control>N", goto_state, NEXT_STATE, NULL },
  { "/End States/Show Last", "<Control>L", goto_state, LAST_STATE, NULL }
};

/*---------------------------------------------------------------------------*/

static void 
display_path( void )
{
  tree_node_t *tree_node;
  path_node_t *path_node;
  string_t index, string;

  free_path();
  
  /* Append nodes to the path. */
  for (tree_node = path_end; ; tree_node = tree_node->parent)
  {
    tree_node->in_path = TRUE;
    path_node = new_node( &path_nodes, sizeof( path_node_t ), LIST_START );
    if (path_begin != NULL && tree_node->result_fs != NULL)
    {
      index = int_to_string( tree_node->index );
      string = concat_strings( "(", index, ")", NULL );
      path_node->index = new_pos_string( string );
      free_mem( &string );
      free_mem( &index );
      path_node->rule_name = new_pos_string( tree_node->rule_name );
      path_node->result_surf = new_pos_string( tree_node->result_surf );
      set_scanner_input( tree_node->result_fs );
      path_node->result_fs = parse_pos_value();
      parse_token( EOF );
      set_scanner_input( NULL );
      path_node->rule_set = new_pos_string( tree_node->rule_set );
    }
    if (tree_node == path_begin) 
      break;
    if (tree_node->link_fs != NULL)
    {
      path_node->link_surf = new_pos_string( tree_node->link_surf );
      set_scanner_input( tree_node->link_fs );
      path_node->link_fs = parse_pos_value();
      parse_token( EOF );
      set_scanner_input( NULL );
    }
    if (path_begin == NULL) 
      break;
  }

  if (path_canvas == NULL) 
  {
    path_canvas = create_canvas(
      "Malaga Path", "path.eps", &path_geometry, configure_path, expose_path,
      close_path, NULL, TRUE, 
      path_items, sizeof( path_items ) / sizeof( path_items[0] ) );
  }
  else
  {
    configure_canvas( path_canvas );
    show_canvas( path_canvas );
  }
  redraw_canvas( tree_canvas );
}

/*---------------------------------------------------------------------------*/

static void
configure_node( canvas_t *canvas, tree_node_t *node, int_t x, int_t y,
            int_t font_height )
{
  int_t sub_x;
  tree_node_t *subnode;
  bool_t is_first;

  node->x = x; node->y = y;
  
  is_first = TRUE;
  width = MAX( width, x );
  for (subnode = node->child; subnode != NULL; subnode = subnode->sibling)
  {
    if (tree_mode == NO_DEAD_ENDS && subnode->type == BREAK_NODE) 
      continue;
    if (tree_mode == RESULT_PATHS && ! subnode->result_path) 
      continue;

    if (is_first) 
      is_first = FALSE;
    else 
      height += (5 * font_height) / 2;

    config_pos_string( subnode->pos_link_surf, canvas );
    config_pos_string( subnode->pos_rule_name, canvas );
    sub_x = x + font_height + MAX( subnode->pos_link_surf->width, 
                           subnode->pos_rule_name->width );
    subnode->pos_link_surf->x 
      = (sub_x + x - subnode->pos_link_surf->width) / 2;
    subnode->pos_link_surf->y = height - font_height - 1;
    subnode->pos_rule_name->x 
      = (sub_x + x - subnode->pos_rule_name->width) / 2;
    subnode->pos_rule_name->y = height + 1;
    configure_node( canvas, subnode, sub_x, height, font_height );
  }
}

/*---------------------------------------------------------------------------*/

static void
configure_tree( canvas_t *canvas, int_t *width_p, int_t *height_p )
{
  int_t font_height = get_font_height( canvas );
  int_t border_width = get_border_width( canvas );

  height = border_width;
  width = border_width;

  /* Configure result surface. */
  config_pos_string( result_surf, canvas );
  result_surf->x = border_width;
  result_surf->y = border_width;
  width = MAX( width, border_width + result_surf->width );
  height += font_height;
  if (tree_mode != RESULT_PATHS || tree_nodes->result_path)
  {
    /* Configure tree. */
    height += 2 * font_height;
    configure_node( canvas, tree_nodes, border_width + font_height / 2, height,
                font_height );
  }

  /* Return width and height. */
  *width_p = width + font_height / 2 + border_width;
  *height_p = height + font_height + border_width;
}

/*---------------------------------------------------------------------------*/

static void
expose_node( canvas_t *canvas, tree_node_t *node, int_t font_height )
{
  tree_node_t *subnode;
  int_t x = node->x;
  int_t y = node->y;
  int_t radius1 = font_height / 2;
  int_t radius2 = (radius1 * 3) / 5;
  int_t old_y;

  /* Draw all subnodes. */
  old_y = y;
  for (subnode = node->child; subnode != NULL; subnode = subnode->sibling)
  {
    if (tree_mode == NO_DEAD_ENDS && subnode->type == BREAK_NODE) 
      continue;
    if (tree_mode == RESULT_PATHS && ! subnode->result_path) 
      continue;
    
    if (node->in_path && subnode->in_path)
    {
      set_color( RED );
      old_y = y;
    }
    else 
      set_color( BLACK );
    draw_lines( 3, x, old_y, x, subnode->y, subnode->x, subnode->y );
    old_y = subnode->y;
    if (path_begin == NULL && subnode->in_path) 
      set_color( RED );
    draw_pos_string( subnode->pos_link_surf, canvas );
    set_color( BLACK );
    draw_pos_string( subnode->pos_rule_name, canvas );
    expose_node( canvas, subnode, font_height );
  }

  if (node->type != BREAK_NODE)
  {
    set_color( WHITE );
    draw_circle( TRUE, x, y, radius1 );
  }

  if (node->in_path && path_begin != NULL) 
    set_color( RED );
  else 
    set_color( BLACK );

  /* Finally, draw the node itself. */
  if (node->type == BREAK_NODE)
    draw_rectangle( x - radius1 , y - radius1, 2 * radius1, 2 * radius1 );
  else
  {
    draw_circle( FALSE, x, y, radius1 );
    if (node->type == FINAL_NODE || node->type == UNFINAL_NODE)
      draw_circle( FALSE, x, y, radius2 );
    if (node->type == PRUNED_NODE || node->type == UNFINAL_NODE)
    {
      draw_lines( 2, x - radius1, y - radius1, x + radius1, y + radius1 );
      draw_lines( 2, x + radius1, y - radius1, x - radius1, y + radius1 );
    }
  }
}

/*---------------------------------------------------------------------------*/

static void
expose_tree( canvas_t *canvas, rectangle_t *area )
{
  int_t font_height = get_font_height( canvas );

  if (result_surf != NULL) 
  {
    set_color( BLACK );
    draw_pos_string( result_surf, canvas );
  }
  if (tree_nodes == NULL) 
    return;
  if (tree_mode != RESULT_PATHS || tree_nodes->result_path)
    expose_node( canvas, tree_nodes, font_height );
}

/*---------------------------------------------------------------------------*/

static bool_t
in_circle( int_t x, int_t y, int_t circle_x, int_t circle_y, int_t radius )
{
  int_t diff_x = x - circle_x;
  int_t diff_y = y - circle_y;
  
  return (diff_x * diff_x + diff_y * diff_y <= radius * radius);
}

/*---------------------------------------------------------------------------*/

static bool_t
in_pos_string( int_t x, int_t y, pos_string_t *pos_string, int_t height )
{
  return (x >= pos_string->x 
        && x < pos_string->x + pos_string->width
        && y >= pos_string->y 
        && y < pos_string->y + height);
}

/*---------------------------------------------------------------------------*/

static void 
set_tree( canvas_t *canvas, guint mode )
/* Set the tree's display mode to MODE. */
{
  tree_mode = mode;
  if (path_end != NULL
      && ((tree_mode == NO_DEAD_ENDS && path_end->type == BREAK_NODE)
        || (tree_mode == RESULT_PATHS && ! path_end->result_path)))
  {
    hide_canvas( path_canvas );
  }
  configure_canvas( tree_canvas );
}

/*---------------------------------------------------------------------------*/

static void 
goto_state( canvas_t *canvas, guint action )
{
  int_t i = 0;
  bool_t inverse = FALSE; /* TRUE if we search in inverse direction. */

  if (action == FIRST_STATE || action == LAST_STATE
      || (path_begin != NULL && path_begin->type == FINAL_NODE))
  {
    switch (action)
    {
    case FIRST_STATE: 
      i = 0; 
      break;
    case PREV_STATE:
      i = path_begin->index - 1;
      inverse = TRUE;
      break;
    case NEXT_STATE:
      i = path_begin->index + 1;
      break;
    case LAST_STATE: 
      i = node_count - 1; 
      inverse = TRUE; 
      break;
    } 
    while (i >= 0 && i < node_count)
    {
      if (nodes[i] != NULL && nodes[i]->type == FINAL_NODE)
      {
      path_begin = path_end = nodes[i];
      make_visible( tree_canvas, path_begin->x, path_begin->y );
      display_path();
      break;
      }
      if (inverse) 
      i--; 
      else 
      i++;
    }
  }
}

/*---------------------------------------------------------------------------*/

static bool_t
mouse_event(  canvas_t *canvas, int_t x, int_t y, int_t button )
/* Called if mouse has moved to position (X,Y). */
{
  tree_node_t *node, *node2, *new_begin, *new_end;
  int_t i;
  int_t font_height = get_font_height( canvas );

  for (i = 0; i < node_count; i++)
  {
    node = nodes[i];
    if (node == NULL) 
      continue;
    if (tree_mode == NO_DEAD_ENDS && node->type == BREAK_NODE) 
      continue;
    if (tree_mode == RESULT_PATHS && ! node->result_path) 
      continue;
    if (in_circle( x, y, node->x, node->y, font_height / 2 )
      && node->type != BREAK_NODE)
    {
      if (button == 0) 
      set_cursor( canvas, TRUE );
      else
      {
      if (button == 1 || button == 2) 
        new_begin = node;
      else 
        new_begin = path_begin;
      if (button == 2 || button == 3) 
        new_end = node;
      else 
        new_end = path_end;
      node2 = new_end; 
      while (node2 != NULL && node2 != new_begin) 
        node2 = node2->parent;
      if (node2 == NULL) 
        new_begin = new_end = node;
      path_begin = new_begin;
      path_end = new_end;
      display_path();
      }
      return TRUE;
    }
    if (in_pos_string( x, y, node->pos_link_surf, font_height ))
    {
      if (button == 0) 
      set_cursor( canvas, TRUE );
      else
      {
      path_begin = NULL;
      path_end = node;
      display_path();
      }
      return TRUE;
    }
    if (in_pos_string( x, y, node->pos_rule_name, font_height ))
    {
      if (button == 0) 
      set_cursor( canvas, TRUE );
      else
      {
      path_begin = node->parent;
      path_end = node;
      display_path();
      }
      return TRUE;
    }
  }
  set_cursor( canvas, FALSE );
  return FALSE;
}

/*---------------------------------------------------------------------------*/

static GtkItemFactoryEntry tree_items[] = 
{
  { "/Tree", NULL, NULL, 0, "<Branch>" },
  { "/Tree/Full Tree", NULL, set_tree, FULL_TREE, "<RadioItem>" },
  { "/Tree/No Dead Ends", NULL, set_tree, NO_DEAD_ENDS, "/Tree/Full Tree" },
  { "/Tree/Complete Paths", NULL, set_tree, RESULT_PATHS, "/Tree/Full Tree" },
  { "/End States", NULL, NULL, 0, "<Branch>" },
  { "/End States/Show First", "<Control>F", goto_state, FIRST_STATE, NULL },
  { "/End States/Show Previous", "<Control>P", goto_state, PREV_STATE, NULL },
  { "/End States/Show Next", "<Control>N", goto_state, NEXT_STATE, NULL },
  { "/End States/Show Last", "<Control>L", goto_state, LAST_STATE, NULL }
};

/*---------------------------------------------------------------------------*/

static void
free_tree( void )
{
  int_t i;

  /* Clear old variables. */
  free_pos_string( &result_surf );
  free_pos_string( &plus );
  for (i = 0; i < node_count; i++) 
  {
    if (nodes[i] != NULL)
    {
      free_mem( &nodes[i]->rule_name );
      free_mem( &nodes[i]->link_surf );
      free_mem( &nodes[i]->link_fs );
      free_mem( &nodes[i]->result_surf );
      free_mem( &nodes[i]->result_fs );
      free_mem( &nodes[i]->rule_set );
      free_pos_string( &nodes[i]->pos_link_surf );
      free_pos_string( &nodes[i]->pos_rule_name );
      free_mem( &nodes[i] );
    } 
  }
  tree_nodes = NULL;
}

/*---------------------------------------------------------------------------*/

static void
close_tree( canvas_t *canvas )
/* Called by "canvas.c" when CANVAS gets hidden. */
{
  if (path_canvas != NULL) 
    hide_canvas( path_canvas );
  free_tree();
}

/*---------------------------------------------------------------------------*/

void 
read_tree( void )
/* Read new tree from STDIN. */
{
  string_t line; /* A line of input from STDIN. */
  string_t line_p; /* Part of LINE which is yet to parse. */
  string_t type; /* Node type. */
  tree_node_t *node;
  int_t parent_index, i;
  tree_node_t **node_p;

  if (path_canvas != NULL) 
    hide_canvas( path_canvas );
  free_tree();

  /* Allocate new nodes array. */
  if (node_count == 0)
  {
    node_count = 100;
    nodes = new_vector( sizeof( tree_node_t * ), node_count );
  }

  /* Read new input surface. */
  line = read_line( stdin );
  result_surf = new_pos_string( line );
  free_mem( &line );

  /* Read new tree. */
  while (TRUE) 
  { 
    line = read_line( stdin );
    if (line == NULL) 
      complain( "Premature EOF." );
    if (strcmp_no_case( line, "end" ) == 0) 
      break;

    node = new_mem( sizeof( tree_node_t ) );
    line_p = line;
    node->index = parse_int( &line_p );
    type = parse_word( &line_p );
    if (strcmp_no_case( type, "inter" ) == 0) 
      node->type = INTER_NODE;
    else if (strcmp_no_case( type, "break" ) == 0) 
      node->type = BREAK_NODE;
    else if (strcmp_no_case( type, "final" ) == 0) 
      node->type = FINAL_NODE;
    else if (strcmp_no_case( type, "unfinal" ) == 0) 
      node->type = UNFINAL_NODE;
    else if (strcmp_no_case( type, "pruned" ) == 0) 
      node->type = PRUNED_NODE;
    else 
      complain( "Unknown node type \"%s\".", type );
    free_mem( &type );
    parent_index = parse_int( &line_p );
    node->rule_name = parse_word( &line_p );
    node->link_surf = parse_optional_value( &line_p );
    node->link_fs = parse_optional_value( &line_p );
    node->result_surf = parse_optional_value( &line_p );
    node->result_fs = parse_optional_value( &line_p );
    node->rule_set = parse_word( &line_p );
    parse_end( &line_p );
    free_mem( &line );

    node->pos_link_surf = new_pos_string( node->link_surf );
    node->pos_rule_name = new_pos_string( node->rule_name );

    /* Find parent node. */
    if (parent_index == -1) 
      tree_nodes = node;
    else if (parent_index >= node_count || nodes[ parent_index ] == NULL)
      complain( "Display data corrupted." );
    else 
    { 
      node->parent = nodes[ parent_index ];

      /* Add NODE to be a child of NODE->PARENT. */
      node_p = &node->parent->child;
      while (*node_p != NULL) 
      node_p = &(*node_p)->sibling;
      *node_p = node;
    }

    /* Add node to the indexes. */
    if (node->index >= node_count)
    {
      renew_vector( &nodes, sizeof( tree_node_t * ), 2 * node->index );
      for (i = node_count; i < 2 * node->index; i++) 
      nodes[i] = NULL;
      node_count = 2 * node->index;
    }
    nodes[ node->index ] = node;

    /* If this is a final node, mark it and all its predecessors. */
    if (node->type == FINAL_NODE) 
    {
      for (; node != NULL; node = node->parent) 
      node->result_path = TRUE;
    }
  }
  free_mem( &line );
  if (tree_nodes == NULL) 
    complain( "Missing root node in tree." );

  plus = new_pos_string( "+" );

  if (tree_canvas == NULL) 
  {
    tree_canvas = create_canvas( 
      "Malaga Tree", "tree.eps", &tree_geometry, configure_tree, expose_tree,
       close_tree, mouse_event, 
       FALSE, tree_items, sizeof( tree_items ) / sizeof( tree_items[0] ) );
  }
  else
  {
    configure_canvas( tree_canvas );
    show_canvas( tree_canvas );
  }
}

/* End of file. =============================================================*/

Generated by  Doxygen 1.6.0   Back to index