Blame tree.c

Packit d394d9
/* Copyright (C) 2002 Bjoern Beutel. */
Packit d394d9
Packit d394d9
/* Description. =============================================================*/
Packit d394d9
Packit d394d9
/* Read in and display Malaga Variables. */
Packit d394d9
Packit d394d9
/* Includes. ================================================================*/
Packit d394d9
Packit d394d9
#include <stdio.h>
Packit d394d9
#include <stdlib.h>
Packit d394d9
#include <stdarg.h>
Packit d394d9
#include <setjmp.h>
Packit d394d9
#include <string.h>
Packit d394d9
#include <gtk/gtk.h>
Packit d394d9
#include "basic.h"
Packit d394d9
#include "scanner.h"
Packit d394d9
#include "input.h"
Packit d394d9
#include "canvas.h"
Packit d394d9
#include "tree.h"
Packit d394d9
Packit d394d9
/* Constants. ===============================================================*/
Packit d394d9
Packit d394d9
enum {FIRST_STATE, NEXT_STATE, PREV_STATE, LAST_STATE};
Packit d394d9
Packit d394d9
enum {PATH_BEGIN, PATH_END, FROM_ROOT}; /* Items of the tree's pop-up menu. */
Packit d394d9
Packit d394d9
/* Types. ===================================================================*/
Packit d394d9
Packit d394d9
typedef enum {INTER_NODE, BREAK_NODE, FINAL_NODE, UNFINAL_NODE,
Packit d394d9
	      PRUNED_NODE} tree_node_type_t;
Packit d394d9
Packit d394d9
typedef enum {ELEMENT_NODE, ELEMENT_LINK, ELEMENT_RULE} element_t;
Packit d394d9
/* Elements of a node that may be hit by the mouse pointer. */
Packit d394d9
Packit d394d9
typedef struct tree_node 
Packit d394d9
{ 
Packit d394d9
  struct tree_node *parent; /* Parent of this tree node. */
Packit d394d9
  struct tree_node *sibling; /* Next sibling of this tree node. */
Packit d394d9
  struct tree_node *child; /* First successor of this tree node. */
Packit d394d9
  int_t state_index; /* State index of this tree node. */
Packit d394d9
  tree_node_type_t type; /* Type of this node. */
Packit d394d9
  string_t rule_name; /* Name of rule that created this node. */
Packit d394d9
  string_t link_surf;
Packit d394d9
  string_t link_feat;
Packit d394d9
  string_t result_surf;
Packit d394d9
  string_t result_feat;
Packit d394d9
  string_t rule_set;
Packit d394d9
  bool_t result_path;
Packit d394d9
Packit d394d9
  /* The following items are used to display the tree node. */
Packit d394d9
  bool_t in_path; /* TRUE iff this node is in displayed path. */
Packit d394d9
  int_t x, y; /* Node position. */
Packit d394d9
  pos_string_t *pos_rule_name; /* Positioned rule name. */
Packit d394d9
  pos_string_t *pos_link_surf; /* Positioned link surface. */
Packit d394d9
  pos_string_t *pos_state_index; /* Positioned state index. */
Packit d394d9
} tree_node_t;
Packit d394d9
Packit d394d9
typedef struct
Packit d394d9
{
Packit d394d9
  list_node_t *next; /* Next path node in this list. */
Packit d394d9
  pos_string_t *state_index;
Packit d394d9
  pos_string_t *link_surf;
Packit d394d9
  pos_value_t *link_feat;
Packit d394d9
  pos_string_t *rule_name;
Packit d394d9
  pos_string_t *result_surf;
Packit d394d9
  pos_value_t *result_feat;
Packit d394d9
  pos_string_t *rule_set;
Packit d394d9
} path_node_t;
Packit d394d9
Packit d394d9
/* Global variables. ========================================================*/
Packit d394d9
Packit d394d9
rectangle_t tree_geometry, path_geometry;
Packit d394d9
string_t tree_font_family, path_font_family;
Packit d394d9
int_t tree_font_size, path_font_size;
Packit d394d9
tree_mode_t tree_mode;
Packit d394d9
bool_t show_state_indexes;
Packit d394d9
bool_t inline_path;
Packit d394d9
Packit d394d9
/* Variables. ===============================================================*/
Packit d394d9
Packit d394d9
/* Information in Tree window. */
Packit d394d9
static pos_string_t *result_surf;
Packit d394d9
static tree_node_t *tree_nodes;
Packit d394d9
static tree_node_t **states; /* Dynamic array of nodes representing states. */
Packit d394d9
static int_t state_count; /* Size of the array STATES. */
Packit d394d9
static int_t tree_width, tree_height; /* Width and height of tree canvas. */
Packit d394d9
static canvas_t *tree_canvas;
Packit d394d9
static tree_node_t *popup_menu_node;
Packit d394d9
Packit d394d9
static bool_t tree_show_state_indexes; 
Packit d394d9
/* Controls whether state indexes are shown in tree. */
Packit d394d9
Packit d394d9
/* Information in Path window. */
Packit d394d9
static list_t path_nodes;
Packit d394d9
static canvas_t *path_canvas;
Packit d394d9
static pos_string_t *plus;
Packit d394d9
static pos_string_t *comma;
Packit d394d9
static tree_node_t *path_begin, *path_end;
Packit d394d9
Packit d394d9
static bool_t path_show_state_indexes; 
Packit d394d9
/* Controls whether state indexes are shown in path. */
Packit d394d9
Packit d394d9
/* Forward declarations. ====================================================*/
Packit d394d9
Packit d394d9
static void goto_state( canvas_t *canvas, guint action );
Packit d394d9
Packit d394d9
/* Functions. ===============================================================*/
Packit d394d9
Packit d394d9
static string_t
Packit d394d9
parse_optional_value( string_t *input )
Packit d394d9
/* Parse "{}" or "{VALUE}" in *INPUT and return NULL or VALUE, resp.
Packit d394d9
 * Update *INPUT. The result must bee freed after use. */
Packit d394d9
{
Packit d394d9
  string_t s, value;
Packit d394d9
  
Packit d394d9
  if (**input != '{') 
Packit d394d9
    complain( "Missing \"{\"." );
Packit d394d9
  for (s = *input + 1; *s != '}'; s++)
Packit d394d9
  {
Packit d394d9
    if (*s == EOS) 
Packit d394d9
      complain( "Missing \"}\"." );
Packit d394d9
    if (*s == '\"') 
Packit d394d9
    {
Packit d394d9
      for (s++; *s != '\"'; s++)
Packit d394d9
      {
Packit d394d9
	if (*s == EOS) 
Packit d394d9
	  complain( "Missing '\"'." );
Packit d394d9
	if (s[0] == '\\' && s[1] == '\"') 
Packit d394d9
	  s++;
Packit d394d9
      }
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
  if (s > *input + 1) 
Packit d394d9
    value = new_string( *input + 1, s );
Packit d394d9
  else 
Packit d394d9
    value = NULL;
Packit d394d9
  *input = s + 1;
Packit d394d9
  parse_whitespace( input );
Packit d394d9
  return value;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
configure_path( canvas_t *canvas, int_t *width_p, int_t *height_p )
Packit d394d9
/* Do the layout of the path CANVAS. 
Packit d394d9
 * Return the canvas' total size in *WIDTH_P and *HEIGHT_P. */
Packit d394d9
{
Packit d394d9
  int_t path_width, path_height, x, x_dist;
Packit d394d9
  path_node_t *node;
Packit d394d9
  bool_t is_first;
Packit d394d9
  int_t space_width = get_space_width( canvas );
Packit d394d9
  int_t font_height = get_font_height( canvas );
Packit d394d9
  int_t font_ascent = get_font_ascent( canvas );
Packit d394d9
  int_t border_width = get_border_width( canvas );
Packit d394d9
  
Packit d394d9
  config_pos_string( plus, canvas );
Packit d394d9
  config_pos_string( comma, canvas );
Packit d394d9
  x_dist = space_width + comma->width;
Packit d394d9
Packit d394d9
  path_width = path_height = border_width;
Packit d394d9
  is_first = TRUE;
Packit d394d9
Packit d394d9
  FOREACH( node, path_nodes )
Packit d394d9
  {
Packit d394d9
    if (node->link_feat != NULL)
Packit d394d9
    {
Packit d394d9
      if (is_first) 
Packit d394d9
	is_first = FALSE; 
Packit d394d9
      else 
Packit d394d9
	path_height += font_height;
Packit d394d9
      
Packit d394d9
      config_pos_string( node->link_surf, canvas );
Packit d394d9
      node->link_surf->x = border_width + plus->width + space_width;
Packit d394d9
      path_width = MAX( path_width, 
Packit d394d9
			node->link_surf->x + node->link_surf->width );
Packit d394d9
      
Packit d394d9
      config_pos_value( node->link_feat, canvas );
Packit d394d9
      node->link_feat->x = node->link_surf->x;
Packit d394d9
      if (inline_path)
Packit d394d9
      {
Packit d394d9
	node->link_surf->y = (path_height 
Packit d394d9
			      + node->link_feat->ascent - font_ascent);
Packit d394d9
	node->link_feat->x += node->link_surf->width + x_dist;
Packit d394d9
      }
Packit d394d9
      else
Packit d394d9
      {
Packit d394d9
	node->link_surf->y = path_height;
Packit d394d9
	path_height += font_height;
Packit d394d9
      }
Packit d394d9
      node->link_feat->y = path_height;
Packit d394d9
      path_width = MAX( path_width, 
Packit d394d9
			node->link_feat->x + node->link_feat->width );
Packit d394d9
      path_height += node->link_feat->height;
Packit d394d9
    }
Packit d394d9
    if (node->result_feat != NULL)
Packit d394d9
    {
Packit d394d9
      if (is_first)
Packit d394d9
	is_first = FALSE; 
Packit d394d9
      else
Packit d394d9
	path_height += font_height;
Packit d394d9
Packit d394d9
      x = border_width;
Packit d394d9
Packit d394d9
      /* Configure rule name. */
Packit d394d9
      if (node != (path_node_t *) path_nodes.first)
Packit d394d9
      {
Packit d394d9
	config_pos_string( node->rule_name, canvas );
Packit d394d9
	node->rule_name->x = x;
Packit d394d9
	x += node->rule_name->width + 2 * space_width;
Packit d394d9
	if (! inline_path)
Packit d394d9
	  node->rule_name->y = path_height;
Packit d394d9
      }
Packit d394d9
Packit d394d9
      /* Configure state index. */
Packit d394d9
      if (path_show_state_indexes)
Packit d394d9
      {
Packit d394d9
	config_pos_string( node->state_index, canvas );
Packit d394d9
	node->state_index->x = x;
Packit d394d9
	if (inline_path)
Packit d394d9
	  x += node->state_index->width + x_dist;
Packit d394d9
	else
Packit d394d9
	{
Packit d394d9
	  node->state_index->y = path_height;
Packit d394d9
	  path_width = MAX( path_width, x + node->state_index->width );
Packit d394d9
	  path_height += font_height;
Packit d394d9
	}
Packit d394d9
      }
Packit d394d9
Packit d394d9
      /* Configure result surface. */
Packit d394d9
      config_pos_string( node->result_surf, canvas );
Packit d394d9
      node->result_surf->x = x;
Packit d394d9
      if (inline_path) 
Packit d394d9
	x += node->result_surf->width + x_dist;
Packit d394d9
      else
Packit d394d9
      {
Packit d394d9
	node->result_surf->y = path_height;
Packit d394d9
	path_width = MAX( path_width, x + node->result_surf->width );
Packit d394d9
	path_height += font_height;
Packit d394d9
      }
Packit d394d9
Packit d394d9
      /* Configure result feature structure. */
Packit d394d9
      config_pos_value( node->result_feat, canvas );
Packit d394d9
      node->result_feat->x = x;
Packit d394d9
      node->result_feat->y = path_height;
Packit d394d9
      if (inline_path)
Packit d394d9
	x += node->result_feat->width + x_dist;
Packit d394d9
      else
Packit d394d9
      {
Packit d394d9
	path_width = MAX( path_width, x + node->result_feat->width );
Packit d394d9
	path_height += node->result_feat->height;
Packit d394d9
      }
Packit d394d9
Packit d394d9
      /* Configure rule set. */
Packit d394d9
      config_pos_string( node->rule_set, canvas );
Packit d394d9
      node->rule_set->x = x;
Packit d394d9
      if (inline_path)
Packit d394d9
      {
Packit d394d9
	node->rule_name->y 
Packit d394d9
	  = node->state_index->y 
Packit d394d9
	  = node->result_surf->y 
Packit d394d9
	  = node->rule_set->y
Packit d394d9
	  = path_height + node->result_feat->ascent - font_ascent;
Packit d394d9
	path_height += node->result_feat->height;
Packit d394d9
      }
Packit d394d9
      else
Packit d394d9
      {
Packit d394d9
	node->rule_set->y = path_height;
Packit d394d9
	path_height += font_height;
Packit d394d9
      }
Packit d394d9
      path_width = MAX( path_width, x + node->rule_set->width );
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
Packit d394d9
  *width_p = path_width + border_width;
Packit d394d9
  *height_p = path_height + border_width;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
expose_path( canvas_t *canvas, rectangle_t *area )
Packit d394d9
{
Packit d394d9
  path_node_t *node;
Packit d394d9
  int_t x1, x2, y;
Packit d394d9
  int_t space_width = get_space_width( canvas );
Packit d394d9
  int_t font_height = get_font_height( canvas );
Packit d394d9
  int_t border_width = get_border_width( canvas );
Packit d394d9
  int_t line_width = get_line_width( canvas );
Packit d394d9
Packit d394d9
  set_color( BLACK );
Packit d394d9
Packit d394d9
  FOREACH( node, path_nodes )
Packit d394d9
  {
Packit d394d9
    if (node->link_feat != NULL)
Packit d394d9
    {
Packit d394d9
      plus->x = border_width;
Packit d394d9
      plus->y = node->link_surf->y;
Packit d394d9
      draw_pos_string( plus, canvas );
Packit d394d9
      draw_pos_string( node->link_surf, canvas );
Packit d394d9
      draw_pos_value( node->link_feat, canvas );
Packit d394d9
      if (inline_path)
Packit d394d9
      {
Packit d394d9
	comma->x = node->link_surf->x + node->link_surf->width;
Packit d394d9
	comma->y = node->link_surf->y;
Packit d394d9
	draw_pos_string( comma, canvas );
Packit d394d9
      }
Packit d394d9
    }
Packit d394d9
    if (node->result_feat != NULL)
Packit d394d9
    {
Packit d394d9
      if (node != (path_node_t *) path_nodes.first)
Packit d394d9
      {
Packit d394d9
	x1 = node->rule_name->x;
Packit d394d9
	x2 = x1 + node->rule_name->width + space_width;
Packit d394d9
	y = node->rule_name->y + font_height + line_width;
Packit d394d9
	draw_pos_string( node->rule_name, canvas );
Packit d394d9
Packit d394d9
	/* Draw arrow. */
Packit d394d9
	draw_lines( 2, x1, y, x2, y );
Packit d394d9
	draw_lines( 3, 
Packit d394d9
		    x2 - space_width, y - space_width / 2,
Packit d394d9
		    x2, y, 
Packit d394d9
		    x2 - space_width, y + space_width / 2 );
Packit d394d9
      }
Packit d394d9
      if (path_show_state_indexes)
Packit d394d9
	draw_pos_string( node->state_index, canvas );
Packit d394d9
      draw_pos_string( node->result_surf, canvas );
Packit d394d9
      draw_pos_value( node->result_feat, canvas );
Packit d394d9
      draw_pos_string( node->rule_set, canvas );
Packit d394d9
      if (inline_path)
Packit d394d9
      {
Packit d394d9
	comma->x = node->result_surf->x + node->result_surf->width;
Packit d394d9
	comma->y = node->result_surf->y;
Packit d394d9
	draw_pos_string( comma, canvas );
Packit d394d9
	comma->x = node->result_feat->x + node->result_feat->width;
Packit d394d9
	draw_pos_string( comma, canvas );
Packit d394d9
      }
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
unmark_tree_nodes( tree_node_t *node )
Packit d394d9
/* Mark NODE and all its children and siblings *not* to be part of the path. */
Packit d394d9
{
Packit d394d9
  for (; node != NULL; node = node->sibling)
Packit d394d9
  {
Packit d394d9
    node->in_path = FALSE;
Packit d394d9
    unmark_tree_nodes( node->child );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
free_path( void )
Packit d394d9
{
Packit d394d9
  path_node_t *path_node;
Packit d394d9
Packit d394d9
  /* Clear old path nodes. */
Packit d394d9
  FOREACH_FREE( path_node, path_nodes )
Packit d394d9
  {
Packit d394d9
    free_pos_string( &path_node->state_index );
Packit d394d9
    free_pos_value( &path_node->link_feat );
Packit d394d9
    free_pos_value( &path_node->result_feat );
Packit d394d9
  }
Packit d394d9
Packit d394d9
  unmark_tree_nodes( tree_nodes );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
close_path( canvas_t *canvas )
Packit d394d9
{
Packit d394d9
  free_path();
Packit d394d9
  path_begin = path_end = NULL;
Packit d394d9
  redraw_canvas( tree_canvas );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
set_inline_path( canvas_t *canvas, guint action, GtkWidget *item )
Packit d394d9
{
Packit d394d9
  inline_path = GTK_CHECK_MENU_ITEM( item )->active;
Packit d394d9
  configure_canvas( canvas );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
path_index_option( canvas_t *canvas, guint action, GtkWidget *item )
Packit d394d9
{
Packit d394d9
  path_show_state_indexes = GTK_CHECK_MENU_ITEM( item )->active;
Packit d394d9
  configure_canvas( canvas );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static GtkItemFactoryEntry path_items[] = 
Packit d394d9
{
Packit d394d9
  { "/Style/Inline", NULL, set_inline_path, 0, "<ToggleItem>" },
Packit d394d9
  { "/Path", NULL, NULL, 0, "<Branch>" },
Packit d394d9
  { "/Path/Show State Indexes", NULL, path_index_option, 0, "<ToggleItem>" },
Packit d394d9
  { "/End States", NULL, NULL, 0, "<Branch>" },
Packit d394d9
  { "/End States/Show First End State", "<Control>F", goto_state, FIRST_STATE, 
Packit d394d9
    NULL },
Packit d394d9
  { "/End States/Show Previous End State", "<Control>P", goto_state, PREV_STATE,
Packit d394d9
    NULL },
Packit d394d9
  { "/End States/Show Next End State", "<Control>N", goto_state, NEXT_STATE, 
Packit d394d9
    NULL },
Packit d394d9
  { "/End States/Show Last End State", "<Control>L", goto_state, LAST_STATE, 
Packit d394d9
    NULL }
Packit d394d9
};
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
display_path( void )
Packit d394d9
{
Packit d394d9
  tree_node_t *tree_node;
Packit d394d9
  path_node_t *path_node;
Packit d394d9
  string_t state_index, string;
Packit d394d9
Packit d394d9
  free_path();
Packit d394d9
  
Packit d394d9
  /* Create the path nodes. We go backwards from the path end to the path 
Packit d394d9
   * beginning, since this direction is easier to traverse. */
Packit d394d9
  for (tree_node = path_end; ; tree_node = tree_node->parent)
Packit d394d9
  {
Packit d394d9
    tree_node->in_path = TRUE;
Packit d394d9
    path_node = new_node( &path_nodes, sizeof( path_node_t ), LIST_START );
Packit d394d9
    if (path_begin != NULL && tree_node->result_feat != NULL)
Packit d394d9
    {
Packit d394d9
      /* Create a new state in the path. */
Packit d394d9
      state_index = int_to_string( tree_node->state_index );
Packit d394d9
      string = concat_strings( "State ", state_index, ":", NULL );
Packit d394d9
      path_node->state_index = new_pos_string( string );
Packit d394d9
      free_mem( &string );
Packit d394d9
      free_mem( &state_index );
Packit d394d9
      path_node->rule_name = new_pos_string( tree_node->rule_name );
Packit d394d9
      path_node->result_surf = new_pos_string( tree_node->result_surf );
Packit d394d9
      set_scanner_input( tree_node->result_feat );
Packit d394d9
      path_node->result_feat = parse_pos_value();
Packit d394d9
      parse_token( EOF );
Packit d394d9
      set_scanner_input( NULL );
Packit d394d9
      path_node->rule_set = new_pos_string( tree_node->rule_set );
Packit d394d9
    }
Packit d394d9
    if (tree_node == path_begin) 
Packit d394d9
      break;
Packit d394d9
    if (tree_node->link_feat != NULL)
Packit d394d9
    {
Packit d394d9
      /* Create a new link in the path. */
Packit d394d9
      path_node->link_surf = new_pos_string( tree_node->link_surf );
Packit d394d9
      set_scanner_input( tree_node->link_feat );
Packit d394d9
      path_node->link_feat = parse_pos_value();
Packit d394d9
      parse_token( EOF );
Packit d394d9
      set_scanner_input( NULL );
Packit d394d9
    }
Packit d394d9
    if (path_begin == NULL) 
Packit d394d9
      break;
Packit d394d9
  }
Packit d394d9
Packit d394d9
  if (path_canvas == NULL) 
Packit d394d9
  {
Packit d394d9
    path_canvas = create_canvas(
Packit d394d9
      "Malaga Path", "path.eps", &path_geometry, configure_path, expose_path,
Packit d394d9
      close_path, NULL, TRUE, path_items, ARRAY_LENGTH( path_items ) );
Packit d394d9
    path_show_state_indexes = show_state_indexes;
Packit d394d9
    if (path_show_state_indexes)
Packit d394d9
      activate_menu_item( path_canvas, "/Path/Show State Indexes" );
Packit d394d9
    if (inline_path)
Packit d394d9
      activate_menu_item( path_canvas, "/Style/Inline" );
Packit d394d9
  }
Packit d394d9
  else
Packit d394d9
  {
Packit d394d9
    configure_canvas( path_canvas );
Packit d394d9
    show_canvas( path_canvas );
Packit d394d9
  }
Packit d394d9
  redraw_canvas( tree_canvas );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
configure_node( canvas_t *canvas, tree_node_t *node, int_t x, int_t y )
Packit d394d9
{
Packit d394d9
  int_t w, node_width;
Packit d394d9
  tree_node_t *subnode;
Packit d394d9
  bool_t is_first;
Packit d394d9
  int_t font_height = get_font_height( canvas ); 
Packit d394d9
  int_t space_width = get_space_width( canvas );
Packit d394d9
  int_t line_width = get_line_width( canvas );
Packit d394d9
Packit d394d9
  if (tree_show_state_indexes && node->state_index != -1)
Packit d394d9
  {
Packit d394d9
    config_pos_string( node->pos_state_index, canvas );
Packit d394d9
    node_width = MAX( node->pos_state_index->width + space_width, 
Packit d394d9
		      font_height );
Packit d394d9
    node->pos_state_index->x 
Packit d394d9
      = x + (node_width - node->pos_state_index->width) / 2;
Packit d394d9
    node->pos_state_index->y = tree_height - font_height * 3 / 2 + 1;
Packit d394d9
  }
Packit d394d9
  else
Packit d394d9
    node_width = font_height;
Packit d394d9
Packit d394d9
  node->x = x + node_width / 2; 
Packit d394d9
  node->y = y;
Packit d394d9
  x += node_width;
Packit d394d9
  tree_width = MAX( tree_width, x );
Packit d394d9
Packit d394d9
  is_first = TRUE;
Packit d394d9
  for (subnode = node->child; subnode != NULL; subnode = subnode->sibling)
Packit d394d9
  {
Packit d394d9
    if (tree_mode == NO_DEAD_ENDS && subnode->type == BREAK_NODE) 
Packit d394d9
      continue;
Packit d394d9
    if (tree_mode == RESULT_PATHS && ! subnode->result_path) 
Packit d394d9
      continue;
Packit d394d9
Packit d394d9
    if (is_first) 
Packit d394d9
      is_first = FALSE;
Packit d394d9
    else 
Packit d394d9
      tree_height += (5 * font_height) / 2;
Packit d394d9
Packit d394d9
    config_pos_string( subnode->pos_link_surf, canvas );
Packit d394d9
    config_pos_string( subnode->pos_rule_name, canvas );
Packit d394d9
Packit d394d9
    w = MAX( subnode->pos_link_surf->width, subnode->pos_rule_name->width );
Packit d394d9
    w = MAX( w, space_width );
Packit d394d9
    subnode->pos_link_surf->x = x + (w - subnode->pos_link_surf->width) / 2;
Packit d394d9
    subnode->pos_link_surf->y = tree_height - font_height - line_width;
Packit d394d9
    subnode->pos_rule_name->x = x + (w - subnode->pos_rule_name->width) / 2;
Packit d394d9
    subnode->pos_rule_name->y = tree_height + line_width;
Packit d394d9
    configure_node( canvas, subnode, x + w, tree_height );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
configure_tree( canvas_t *canvas, int_t *width_p, int_t *height_p )
Packit d394d9
{
Packit d394d9
  int_t font_height = get_font_height( canvas );
Packit d394d9
  int_t border_width = get_border_width( canvas );
Packit d394d9
Packit d394d9
  tree_width = tree_height = border_width;
Packit d394d9
Packit d394d9
  /* Configure result surface. */
Packit d394d9
  config_pos_string( result_surf, canvas );
Packit d394d9
  result_surf->x = border_width;
Packit d394d9
  result_surf->y = border_width;
Packit d394d9
  tree_width = MAX( tree_width, border_width + result_surf->width );
Packit d394d9
  tree_height += font_height;
Packit d394d9
  if (tree_mode != RESULT_PATHS || tree_nodes->result_path)
Packit d394d9
  {
Packit d394d9
    /* Configure tree. */
Packit d394d9
    tree_height += 2 * font_height;
Packit d394d9
    configure_node( canvas, tree_nodes, border_width, tree_height );
Packit d394d9
  }
Packit d394d9
Packit d394d9
  /* Return width and height. */
Packit d394d9
  *width_p = tree_width + border_width;
Packit d394d9
  *height_p = tree_height + font_height + border_width;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
expose_node( canvas_t *canvas, tree_node_t *node, int_t font_height )
Packit d394d9
{
Packit d394d9
  tree_node_t *subnode;
Packit d394d9
  const int_t x = node->x;
Packit d394d9
  const int_t y = node->y;
Packit d394d9
  const int_t radius1 = font_height / 2;
Packit d394d9
  const int_t radius2 = (radius1 * 3) / 5;
Packit d394d9
  int_t middle = y;
Packit d394d9
  int_t bottom = y;
Packit d394d9
Packit d394d9
  /* Draw all subnodes. */
Packit d394d9
  for (subnode = node->child; subnode != NULL; subnode = subnode->sibling)
Packit d394d9
  {
Packit d394d9
    if (tree_mode == NO_DEAD_ENDS && subnode->type == BREAK_NODE) 
Packit d394d9
      continue;
Packit d394d9
    if (tree_mode == RESULT_PATHS && ! subnode->result_path) 
Packit d394d9
      continue;
Packit d394d9
    
Packit d394d9
    /* Draw horizontal line. */
Packit d394d9
    bottom = subnode->y;
Packit d394d9
    if (node->in_path && subnode->in_path)
Packit d394d9
    {
Packit d394d9
      middle = subnode->y;
Packit d394d9
      set_color( RED );
Packit d394d9
    }
Packit d394d9
    else 
Packit d394d9
      set_color( BLACK );
Packit d394d9
    draw_lines( 2, x, subnode->y, subnode->x, subnode->y );
Packit d394d9
Packit d394d9
    if (path_begin == NULL && subnode->in_path) 
Packit d394d9
      set_color( RED );
Packit d394d9
    draw_pos_string( subnode->pos_link_surf, canvas );
Packit d394d9
    set_color( BLACK );
Packit d394d9
    draw_pos_string( subnode->pos_rule_name, canvas );
Packit d394d9
    expose_node( canvas, subnode, font_height );
Packit d394d9
  }
Packit d394d9
Packit d394d9
  /* Draw vertical line. */
Packit d394d9
  set_color( BLACK );
Packit d394d9
  draw_lines( 2, x, middle, x, bottom ); 
Packit d394d9
  if (middle != y)
Packit d394d9
  {
Packit d394d9
    set_color( RED );
Packit d394d9
    draw_lines( 2, x, y, x, middle );
Packit d394d9
  }
Packit d394d9
Packit d394d9
  /* Draw the node itself. */
Packit d394d9
  if (node->type == BREAK_NODE)
Packit d394d9
  {
Packit d394d9
    set_color( (node->in_path && path_begin != NULL ? RED : BLACK) );
Packit d394d9
    draw_rectangle( x - radius1 , y - radius1, 2 * radius1, 2 * radius1 );
Packit d394d9
  }
Packit d394d9
  else
Packit d394d9
  {
Packit d394d9
    set_color( WHITE );
Packit d394d9
    draw_circle( TRUE, x, y, radius1 );
Packit d394d9
Packit d394d9
    set_color( (node->in_path && path_begin != NULL ? RED : BLACK) );
Packit d394d9
    draw_circle( FALSE, x, y, radius1 );
Packit d394d9
    if (node->type == FINAL_NODE || node->type == UNFINAL_NODE)
Packit d394d9
      draw_circle( FALSE, x, y, radius2 );
Packit d394d9
    if (node->type == PRUNED_NODE || node->type == UNFINAL_NODE)
Packit d394d9
    {
Packit d394d9
      draw_lines( 2, x - radius1, y - radius1, x + radius1, y + radius1 );
Packit d394d9
      draw_lines( 2, x + radius1, y - radius1, x - radius1, y + radius1 );
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
  
Packit d394d9
  /* Draw the state index. */
Packit d394d9
  if (tree_show_state_indexes && node->state_index != -1)
Packit d394d9
  {
Packit d394d9
    set_color( BLUE );
Packit d394d9
    draw_pos_string( node->pos_state_index, canvas );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
expose_tree( canvas_t *canvas, rectangle_t *area )
Packit d394d9
/* Expose AREA on tree CANVAS. */
Packit d394d9
{
Packit d394d9
  int_t font_height = get_font_height( canvas );
Packit d394d9
Packit d394d9
  if (result_surf != NULL) 
Packit d394d9
  {
Packit d394d9
    set_color( BLACK );
Packit d394d9
    draw_pos_string( result_surf, canvas );
Packit d394d9
  }
Packit d394d9
  if (tree_nodes == NULL) 
Packit d394d9
    return;
Packit d394d9
  if (tree_mode != RESULT_PATHS || tree_nodes->result_path)
Packit d394d9
    expose_node( canvas, tree_nodes, font_height );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static bool_t
Packit d394d9
in_circle( int_t x, int_t y, int_t circle_x, int_t circle_y, int_t radius )
Packit d394d9
/* Return TRUE if position (X,Y) lies in disc with center (CIRCLE_X, CIRCLE_Y)
Packit d394d9
 * and RADIUS. */ 
Packit d394d9
{
Packit d394d9
  int_t diff_x = x - circle_x;
Packit d394d9
  int_t diff_y = y - circle_y;
Packit d394d9
  
Packit d394d9
  /* Taking DIFF_X or DIFF_Y to the 2nd power may result in an overflow,
Packit d394d9
   * so we will check first whether DIFF_X and DIFF_Y are small enough. */
Packit d394d9
  return (ABS( diff_x ) < radius && ABS( diff_y ) < radius
Packit d394d9
	  && diff_x * diff_x + diff_y * diff_y <= radius * radius);
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static bool_t
Packit d394d9
in_pos_string( int_t x, int_t y, pos_string_t *pos_string, int_t height )
Packit d394d9
/* Return TRUE if position (X,Y) lies in bounding box of POS_STRING, using font
Packit d394d9
 * height HEIGHT. */
Packit d394d9
{
Packit d394d9
  return (x >= pos_string->x 
Packit d394d9
	  && x < pos_string->x + pos_string->width
Packit d394d9
	  && y >= pos_string->y 
Packit d394d9
	  && y < pos_string->y + height);
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static bool_t
Packit d394d9
in_rectangle( int_t x, int_t y, 
Packit d394d9
	      int_t rect_x, int_t rect_y, int_t width, int_t height )
Packit d394d9
/* Return TRUE if position (X,Y) lies in rectangle with upper left corner 
Packit d394d9
 * (RECT_X, RECT_Y), width WIDTH and height HEIGHT. */
Packit d394d9
{
Packit d394d9
  return (x >= rect_x 
Packit d394d9
	  && x <= rect_x + width 
Packit d394d9
	  && y >= rect_y
Packit d394d9
	  && y <= rect_y + height);
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
set_tree( canvas_t *canvas, guint mode )
Packit d394d9
/* Set the tree's display mode to MODE. */
Packit d394d9
{
Packit d394d9
  tree_mode = mode;
Packit d394d9
  if (path_end != NULL
Packit d394d9
      && ((tree_mode == NO_DEAD_ENDS && path_end->type == BREAK_NODE)
Packit d394d9
	  || (tree_mode == RESULT_PATHS && ! path_end->result_path)))
Packit d394d9
  {
Packit d394d9
    hide_canvas( path_canvas );
Packit d394d9
  }
Packit d394d9
  configure_canvas( tree_canvas );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
goto_state( canvas_t *canvas, guint action )
Packit d394d9
/* Display a certain state, according to ACTION, in the path window. */
Packit d394d9
{
Packit d394d9
  int_t i = 0;
Packit d394d9
  bool_t inverse = FALSE; /* TRUE if we search in inverse direction. */
Packit d394d9
Packit d394d9
  if (action == FIRST_STATE || action == LAST_STATE
Packit d394d9
      || (path_begin != NULL && path_begin->type == FINAL_NODE))
Packit d394d9
  {
Packit d394d9
    switch (action)
Packit d394d9
    {
Packit d394d9
    case FIRST_STATE: 
Packit d394d9
      i = 0; 
Packit d394d9
      break;
Packit d394d9
    case PREV_STATE:
Packit d394d9
      i = path_begin->state_index - 1;
Packit d394d9
      inverse = TRUE;
Packit d394d9
      break;
Packit d394d9
    case NEXT_STATE:
Packit d394d9
      i = path_begin->state_index + 1;
Packit d394d9
      break;
Packit d394d9
    case LAST_STATE: 
Packit d394d9
      i = state_count - 1; 
Packit d394d9
      inverse = TRUE; 
Packit d394d9
      break;
Packit d394d9
    } 
Packit d394d9
    while (i >= 0 && i < state_count)
Packit d394d9
    {
Packit d394d9
      if (states[i] != NULL && states[i]->type == FINAL_NODE)
Packit d394d9
      {
Packit d394d9
	path_begin = path_end = states[i];
Packit d394d9
	make_visible( tree_canvas, path_begin->x, path_begin->y );
Packit d394d9
	display_path();
Packit d394d9
	break;
Packit d394d9
      }
Packit d394d9
      if (inverse) 
Packit d394d9
	i--; 
Packit d394d9
      else 
Packit d394d9
	i++;
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static tree_node_t *
Packit d394d9
tree_node_at_position( tree_node_t *node, int_t x, int_t y, int_t font_height, 
Packit d394d9
		       element_t *element_p)
Packit d394d9
{
Packit d394d9
  tree_node_t *subnode;
Packit d394d9
Packit d394d9
  if (node == NULL) 
Packit d394d9
    return NULL;
Packit d394d9
  for (; node != NULL; node = node->sibling)
Packit d394d9
  {
Packit d394d9
    if (tree_mode == NO_DEAD_ENDS && node->type == BREAK_NODE) 
Packit d394d9
      continue;
Packit d394d9
    if (tree_mode == RESULT_PATHS && ! node->result_path) 
Packit d394d9
      continue;
Packit d394d9
    if ((node->type == BREAK_NODE 
Packit d394d9
	 && in_rectangle( x, y, 
Packit d394d9
			  node->x - font_height / 2, node->y - font_height / 2,
Packit d394d9
			  font_height, font_height ))
Packit d394d9
	|| (node->type != BREAK_NODE 
Packit d394d9
	    && in_circle( x, y, node->x, node->y, font_height / 2 ) ))
Packit d394d9
    {
Packit d394d9
      *element_p = ELEMENT_NODE;
Packit d394d9
      return node;
Packit d394d9
    }
Packit d394d9
    if (in_pos_string( x, y, node->pos_link_surf, font_height ))
Packit d394d9
    {
Packit d394d9
      *element_p = ELEMENT_LINK;
Packit d394d9
      return node;
Packit d394d9
    }
Packit d394d9
    if (in_pos_string( x, y, node->pos_rule_name, font_height ))
Packit d394d9
    { 
Packit d394d9
      *element_p = ELEMENT_RULE;
Packit d394d9
      return node;
Packit d394d9
    }
Packit d394d9
    subnode = tree_node_at_position( node->child, x, y, font_height, 
Packit d394d9
				     element_p );
Packit d394d9
    if (subnode != NULL)
Packit d394d9
      return subnode;
Packit d394d9
  }
Packit d394d9
  return NULL;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
display_node( canvas_t *canvas, guint action )
Packit d394d9
{
Packit d394d9
  tree_node_t *node;
Packit d394d9
Packit d394d9
  if (action == PATH_BEGIN)
Packit d394d9
    path_begin = popup_menu_node;
Packit d394d9
  else if (action == FROM_ROOT)
Packit d394d9
    path_begin = tree_nodes;
Packit d394d9
  if (action == PATH_END || action == FROM_ROOT)
Packit d394d9
    path_end = popup_menu_node;
Packit d394d9
Packit d394d9
  /* Check whether there is a part from PATH_BEGIN to PATH_END. */ 
Packit d394d9
  node = path_end; 
Packit d394d9
  while (node != NULL && node != path_begin) 
Packit d394d9
    node = node->parent;
Packit d394d9
  if (node == NULL) 
Packit d394d9
    path_begin = path_end = popup_menu_node;
Packit d394d9
  
Packit d394d9
  display_path();
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static bool_t
Packit d394d9
mouse_event(  canvas_t *canvas, int_t x, int_t y, int_t button )
Packit d394d9
/* Called if mouse has moved to position (X,Y). */
Packit d394d9
{
Packit d394d9
  tree_node_t *node;
Packit d394d9
  element_t element;
Packit d394d9
Packit d394d9
  node = tree_node_at_position( tree_nodes, x, y, get_font_height( canvas ),
Packit d394d9
				&element );
Packit d394d9
  if (node == NULL)
Packit d394d9
  {
Packit d394d9
    set_cursor( canvas, FALSE );
Packit d394d9
    return FALSE;
Packit d394d9
  }
Packit d394d9
Packit d394d9
  /* No button pressed: we should just update the cursor. */
Packit d394d9
  if (button == 0)
Packit d394d9
  {
Packit d394d9
    set_cursor( canvas, TRUE );
Packit d394d9
    return TRUE;
Packit d394d9
  }
Packit d394d9
Packit d394d9
  switch (element)
Packit d394d9
  {
Packit d394d9
  case ELEMENT_NODE:
Packit d394d9
    if (button == 1) 
Packit d394d9
    {
Packit d394d9
      path_begin = path_end = node;
Packit d394d9
      display_path();
Packit d394d9
    }
Packit d394d9
    else if (button == 3)
Packit d394d9
    {
Packit d394d9
      popup_menu_node = node;
Packit d394d9
      popup_menu( canvas );
Packit d394d9
    }
Packit d394d9
    break;
Packit d394d9
Packit d394d9
  case ELEMENT_LINK:
Packit d394d9
    path_begin = NULL;
Packit d394d9
    path_end = node;
Packit d394d9
    display_path();
Packit d394d9
    break;
Packit d394d9
Packit d394d9
  case ELEMENT_RULE:
Packit d394d9
    path_begin = node->parent;
Packit d394d9
    path_end = node;
Packit d394d9
    display_path();
Packit d394d9
    break;
Packit d394d9
  }
Packit d394d9
  return TRUE;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void 
Packit d394d9
tree_index_option( canvas_t *canvas, guint action, GtkWidget *item )
Packit d394d9
{
Packit d394d9
  tree_show_state_indexes = GTK_CHECK_MENU_ITEM( item )->active;
Packit d394d9
  configure_canvas( canvas );
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static GtkItemFactoryEntry tree_items[] = 
Packit d394d9
{
Packit d394d9
  { "/Tree", NULL, NULL, 0, "<Branch>" },
Packit d394d9
  { "/Tree/Full Tree", NULL, set_tree, FULL_TREE, "<RadioItem>" },
Packit d394d9
  { "/Tree/No Dead Ends", NULL, set_tree, NO_DEAD_ENDS, "/Tree/Full Tree" },
Packit d394d9
  { "/Tree/Complete Paths", NULL, set_tree, RESULT_PATHS, "/Tree/Full Tree" },
Packit d394d9
  { "/Tree/sep1", NULL, NULL, 0, "<Separator>" },
Packit d394d9
  { "/Tree/Show State Indexes", NULL, tree_index_option, 0, "<ToggleItem>" },
Packit d394d9
  { "/End States", NULL, NULL, 0, "<Branch>" },
Packit d394d9
  { "/End States/Show First End State", "<Control>F", goto_state, FIRST_STATE, 
Packit d394d9
    NULL },
Packit d394d9
  { "/End States/Show Previous End State", "<Control>P", goto_state, PREV_STATE,
Packit d394d9
    NULL },
Packit d394d9
  { "/End States/Show Next End State", "<Control>N", goto_state, NEXT_STATE, 
Packit d394d9
    NULL },
Packit d394d9
  { "/End States/Show Last End State", "<Control>L", goto_state, LAST_STATE, 
Packit d394d9
    NULL }
Packit d394d9
};
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static GtkItemFactoryEntry popup_items[] = 
Packit d394d9
{
Packit d394d9
  { "/Set Path Begin", NULL, display_node, PATH_BEGIN, "<Item>" },
Packit d394d9
  { "/Set Path End", NULL, display_node, PATH_END, "<Item>" },
Packit d394d9
  { "/Show Path From Root", NULL, display_node, FROM_ROOT, "<Item>" }
Packit d394d9
};
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
free_tree_nodes( tree_node_t *node )
Packit d394d9
/* Free *NODE_P and all its siblings and children. Set *NODE_P to NULL. */
Packit d394d9
{
Packit d394d9
  tree_node_t *next;
Packit d394d9
Packit d394d9
  for (; node != NULL; node = next)
Packit d394d9
  {
Packit d394d9
    /* Remove node from state index. */
Packit d394d9
    if (node->state_index != -1)
Packit d394d9
      states[ node->state_index ] = NULL;
Packit d394d9
Packit d394d9
    free_tree_nodes( node->child );
Packit d394d9
    free_mem( &node->rule_name );
Packit d394d9
    free_mem( &node->link_surf );
Packit d394d9
    free_mem( &node->link_feat );
Packit d394d9
    free_mem( &node->result_surf );
Packit d394d9
    free_mem( &node->result_feat );
Packit d394d9
    free_mem( &node->rule_set );
Packit d394d9
    free_pos_string( &node->pos_link_surf );
Packit d394d9
    free_pos_string( &node->pos_rule_name );
Packit d394d9
    free_pos_string( &node->pos_state_index );
Packit d394d9
    next = node->sibling;
Packit d394d9
    free( node );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
free_tree( void )
Packit d394d9
{
Packit d394d9
  /* Clear old variables. */
Packit d394d9
  free_pos_string( &result_surf );
Packit d394d9
  free_pos_string( &plus );
Packit d394d9
  free_pos_string( &comma );
Packit d394d9
  free_tree_nodes( tree_nodes );
Packit d394d9
  tree_nodes = NULL;
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
static void
Packit d394d9
close_tree( canvas_t *canvas )
Packit d394d9
/* Called by "canvas.c" when CANVAS gets hidden. */
Packit d394d9
{
Packit d394d9
  if (path_canvas != NULL) 
Packit d394d9
    hide_canvas( path_canvas );
Packit d394d9
  free_tree();
Packit d394d9
}
Packit d394d9
Packit d394d9
/*---------------------------------------------------------------------------*/
Packit d394d9
Packit d394d9
void 
Packit d394d9
read_tree( void )
Packit d394d9
/* Read new tree from STDIN. */
Packit d394d9
{
Packit d394d9
  string_t line; /* A line of input from STDIN. */
Packit d394d9
  string_t line_p; /* Part of LINE which is yet to parse. */
Packit d394d9
  string_t type; /* Node type. */
Packit d394d9
  string_t state_index;
Packit d394d9
  tree_node_t *node;
Packit d394d9
  int_t parent_state_index, i;
Packit d394d9
  tree_node_t **node_p;
Packit d394d9
Packit d394d9
  if (path_canvas != NULL) 
Packit d394d9
    hide_canvas( path_canvas );
Packit d394d9
  free_tree();
Packit d394d9
Packit d394d9
  /* Allocate new nodes array. */
Packit d394d9
  if (state_count == 0)
Packit d394d9
  {
Packit d394d9
    state_count = 100;
Packit d394d9
    states = new_vector( sizeof( tree_node_t * ), state_count );
Packit d394d9
  }
Packit d394d9
Packit d394d9
  /* Read new input surface. */
Packit d394d9
  line = read_line( stdin );
Packit d394d9
  result_surf = new_pos_string( line );
Packit d394d9
  free_mem( &line );
Packit d394d9
Packit d394d9
  /* Read new tree. */
Packit d394d9
  while (TRUE) 
Packit d394d9
  { 
Packit d394d9
    line = read_line( stdin );
Packit d394d9
    if (line == NULL) 
Packit d394d9
      complain( "Premature EOF." );
Packit d394d9
    if (strcmp_no_case( line, "end" ) == 0) 
Packit d394d9
      break;
Packit d394d9
Packit d394d9
    node = new_mem( sizeof( tree_node_t ) );
Packit d394d9
    line_p = line;
Packit d394d9
    node->state_index = parse_int( &line_p );
Packit d394d9
    type = parse_word( &line_p );
Packit d394d9
    if (strcmp_no_case( type, "inter" ) == 0) 
Packit d394d9
      node->type = INTER_NODE;
Packit d394d9
    else if (strcmp_no_case( type, "break" ) == 0) 
Packit d394d9
      node->type = BREAK_NODE;
Packit d394d9
    else if (strcmp_no_case( type, "final" ) == 0) 
Packit d394d9
      node->type = FINAL_NODE;
Packit d394d9
    else if (strcmp_no_case( type, "unfinal" ) == 0) 
Packit d394d9
      node->type = UNFINAL_NODE;
Packit d394d9
    else if (strcmp_no_case( type, "pruned" ) == 0) 
Packit d394d9
      node->type = PRUNED_NODE;
Packit d394d9
    else 
Packit d394d9
      complain( "Unknown node type \"%s\".", type );
Packit d394d9
    free_mem( &type );
Packit d394d9
    parent_state_index = parse_int( &line_p );
Packit d394d9
    node->rule_name = parse_word( &line_p );
Packit d394d9
    node->link_surf = parse_optional_value( &line_p );
Packit d394d9
    node->link_feat = parse_optional_value( &line_p );
Packit d394d9
    node->result_surf = parse_optional_value( &line_p );
Packit d394d9
    node->result_feat = parse_optional_value( &line_p );
Packit d394d9
    node->rule_set = parse_word( &line_p );
Packit d394d9
    parse_end( &line_p );
Packit d394d9
    free_mem( &line );
Packit d394d9
Packit d394d9
    node->pos_link_surf = new_pos_string( node->link_surf );
Packit d394d9
    node->pos_rule_name = new_pos_string( node->rule_name );
Packit d394d9
    if (node->state_index != -1)
Packit d394d9
    {
Packit d394d9
      state_index = int_to_string( node->state_index );
Packit d394d9
      node->pos_state_index = new_pos_string( state_index );
Packit d394d9
      free_mem( &state_index );
Packit d394d9
    }
Packit d394d9
Packit d394d9
    /* Find parent node. */
Packit d394d9
    if (parent_state_index == -1) 
Packit d394d9
      tree_nodes = node; /* This is the root node. */
Packit d394d9
    else if (parent_state_index < 0 || parent_state_index >= state_count 
Packit d394d9
	     || states[ parent_state_index ] == NULL)
Packit d394d9
    {
Packit d394d9
      complain( "Display data corrupted." );
Packit d394d9
    }
Packit d394d9
    else 
Packit d394d9
    { 
Packit d394d9
      node->parent = states[ parent_state_index ];
Packit d394d9
Packit d394d9
      /* Add NODE to be a child of NODE->PARENT. */
Packit d394d9
      node_p = &node->parent->child;
Packit d394d9
      while (*node_p != NULL) 
Packit d394d9
	node_p = &(*node_p)->sibling;
Packit d394d9
      *node_p = node;
Packit d394d9
    }
Packit d394d9
Packit d394d9
    /* Add node to the STATES array. */
Packit d394d9
    if (node->state_index >= state_count)
Packit d394d9
    {
Packit d394d9
      renew_vector( &states, sizeof( tree_node_t * ), 2 * node->state_index );
Packit d394d9
      for (i = state_count; i < 2 * node->state_index; i++) 
Packit d394d9
	states[i] = NULL;
Packit d394d9
      state_count = 2 * node->state_index;
Packit d394d9
    }
Packit d394d9
    if (node->state_index != -1)
Packit d394d9
      states[ node->state_index ] = node;
Packit d394d9
Packit d394d9
    /* If this is a final node, mark it and all its predecessors. */
Packit d394d9
    if (node->type == FINAL_NODE) 
Packit d394d9
    {
Packit d394d9
      for (; node != NULL; node = node->parent) 
Packit d394d9
	node->result_path = TRUE;
Packit d394d9
    }
Packit d394d9
  }
Packit d394d9
  free_mem( &line );
Packit d394d9
  if (tree_nodes == NULL) 
Packit d394d9
    complain( "Missing root node in tree." );
Packit d394d9
Packit d394d9
  plus = new_pos_string( "+" );
Packit d394d9
  comma = new_pos_string( "," );
Packit d394d9
Packit d394d9
  if (tree_canvas == NULL) 
Packit d394d9
  {
Packit d394d9
    tree_canvas = create_canvas( 
Packit d394d9
      "Malaga Tree", "tree.eps", &tree_geometry, configure_tree, expose_tree, 
Packit d394d9
      close_tree, mouse_event, FALSE, tree_items, ARRAY_LENGTH( tree_items ) );
Packit d394d9
    set_popup_menu( tree_canvas, popup_items, ARRAY_LENGTH( popup_items ) );
Packit d394d9
    tree_show_state_indexes = show_state_indexes;
Packit d394d9
    if (tree_show_state_indexes )
Packit d394d9
      activate_menu_item( tree_canvas, "/Tree/Show State Indexes" );
Packit d394d9
  }
Packit d394d9
  else
Packit d394d9
  {
Packit d394d9
    configure_canvas( tree_canvas );
Packit d394d9
    show_canvas( tree_canvas );
Packit d394d9
  }
Packit d394d9
}
Packit d394d9
Packit d394d9
/* End of file. =============================================================*/