/* Copyright (C) 2002 Bjoern Beutel. */ /* Description. =============================================================*/ /* This is a GTK program that displays Malaga values. */ /* Includes. ================================================================*/ #define _POSIX_SOURCE #include #include #include #include #include #include #include #include #include "basic.h" #include "input.h" #include "scanner.h" #include "files.h" #include "canvas.h" #include "allomorphs.h" #include "expressions.h" #include "result.h" #include "tree.h" #include "variables.h" #ifdef POSIX #include #endif /* Variables. ===============================================================*/ #ifdef WIN32 static bool_t input_consumed; /* Set by consumer, reset by pipe thread. */ static GCond *input_consumed_cond; /* Signals that "input_consumed" is set. */ static GMutex *input_consumed_mutex; #endif /* Functions. ===============================================================*/ static void parse_font_size( string_t input, int_t *font_size ) { int_t size; size = parse_cardinal( &input ); parse_end( &input ); if (size != 8 && size != 10 && size != 12 && size != 14 && size != 18 && size != 24) { complain( "Illegal font size, valid sizes are 8, 10, 12, 14, 18, 24." ); } *font_size = size; } /*---------------------------------------------------------------------------*/ static int_t my_parse_int( string_t *input_p ) /* Parse an integer number in *INPUT_P, adjust *INPUT_P. * Parsing stops when the first non-digit is encountered. */ { int_t number; if (**input_p < '0' || **input_p > '9') complain( "Number expected." ); number = 0; while (**input_p >= '0' && **input_p <= '9') number = 10 * number + (*(*input_p)++ - '0'); return number; } /*---------------------------------------------------------------------------*/ static void parse_geometry( string_t input, rectangle_t *geometry ) { static char_t malformed[] = "Malformed geometry."; string_t arg, arg_p; arg_p = arg = parse_word( &input ); parse_end( &input ); if ((*arg_p < '0' || *arg_p > '9') && *arg_p != '+') complain( malformed ); if (*arg_p >= '0' && *arg_p <= '9') { /* Parse size. */ geometry->width = my_parse_int( &arg_p ); if (*arg_p != 'x') complain( malformed ); arg_p++; geometry->height = my_parse_int( &arg_p ); } if (*arg_p == '+') { /* Parse position. */ arg_p++; geometry->x = my_parse_int( &arg_p ); if (*arg_p != '+') complain( malformed ); arg_p++; geometry->y = my_parse_int( &arg_p ); } if (*arg_p != EOS) complain( malformed ); free_mem( &arg ); } /*---------------------------------------------------------------------------*/ static void read_profile( string_t file_name ) { FILE *stream; string_t line_p, argument, value; char_t *line; volatile int_t line_count; /* Initialise positions to be ignored. */ allomorphs_geometry.x = allomorphs_geometry.y = -1; expressions_geometry.x = expressions_geometry.y = -1; path_geometry.x = path_geometry.y = -1; result_geometry.x = result_geometry.y = -1; tree_geometry.x = tree_geometry.y = -1; variables_geometry.x = variables_geometry.y = -1; stream = open_stream( file_name, "r" ); line_count = 0; while (TRUE) { line = read_line( stream ); if (line == NULL) break; line_count++; cut_comment( line ); line_p = line; if (*line_p != EOS) { argument = NULL; TRY { argument = parse_word( &line_p ); if (strcmp_no_case( argument, "allomorphs_geometry:" ) == 0) parse_geometry( line_p, &allomorphs_geometry ); else if (strcmp_no_case( argument, "expressions_geometry:" ) == 0) parse_geometry( line_p, &expressions_geometry ); else if (strcmp_no_case( argument, "path_geometry:" ) == 0) parse_geometry( line_p, &path_geometry ); else if (strcmp_no_case( argument, "result_geometry:" ) == 0) parse_geometry( line_p, &result_geometry ); else if (strcmp_no_case( argument, "tree_geometry:" ) == 0) parse_geometry( line_p, &tree_geometry ); else if (strcmp_no_case( argument, "variables_geometry:" ) == 0) parse_geometry( line_p, &variables_geometry ); else if (strcmp_no_case( argument, "font_size:" ) == 0) parse_font_size( line_p, &font_size ); else if (strcmp_no_case( argument, "font:" ) == 0) { if (font_family != NULL) complain( "Font family already defined." ); font_family = parse_word( &line_p ); parse_end( &line_p ); } else if (strcmp_no_case( argument, "show_indexes:" ) == 0) { show_state_indexes = parse_yes_no( &line_p ); parse_end( &line_p ); } else if (strcmp_no_case( argument, "hanging_style:" ) == 0) { hanging_style = parse_yes_no( &line_p ); parse_end( &line_p ); } else if (strcmp_no_case( argument, "inline_path:" ) == 0) { inline_path = parse_yes_no( &line_p ); parse_end( &line_p ); } else if (strcmp_no_case( argument, "show_tree:" ) == 0) { value = parse_word( &line_p ); if (strcmp_no_case( value, "full" ) == 0) tree_mode = FULL_TREE; else if (strcmp_no_case( value, "no_dead_ends" ) == 0) tree_mode = NO_DEAD_ENDS; else if (strcmp_no_case( value, "result_paths" ) == 0) tree_mode = RESULT_PATHS; else complain( "\"full\", \"no_dead_ends\" or \"result_paths\" " "expected." ); free_mem( &value ); } } IF_ERROR { print_text( error_text, " (\"%s\", line %d)\n", name_in_path( file_name ), line_count ); } FINALLY free_mem( &argument ); END_TRY; } free_mem( &line ); } close_stream( &stream, file_name ); } /*---------------------------------------------------------------------------*/ static void read_input( string_t input_type ) /* Read and show INPUT_TYPE from STDIN. */ { if (strcmp_no_case( input_type, "allomorph" ) == 0) read_allomorphs(); else if (strcmp_no_case( input_type, "expressions" ) == 0) read_expressions(); else if (strcmp_no_case( input_type, "result" ) == 0) read_result(); else if (strcmp_no_case( input_type, "tree" ) == 0) read_tree(); else if (strcmp_no_case( input_type, "variables" ) == 0) read_variables(); } /*---------------------------------------------------------------------------*/ #ifdef POSIX static void read_on_condition( gpointer data, gint source, GdkInputCondition condition ) /* This is called by GDK whenever there is something to read. * It reads input from malaga and displays the appropriate canvas. */ { string_t input_type; input_type = read_line( stdin ); if (input_type == NULL) gtk_exit(0); read_input( input_type ); free_mem( &input_type ); } #endif /*---------------------------------------------------------------------------*/ #ifdef WIN32 static bool_t read_input_notify( string_t input_type ) /* Read INPUT_TYPE from stdin, display it, and notify waiting thread. */ { if (input_type == NULL) gtk_exit(0); read_input( input_type ); g_mutex_lock( input_consumed_mutex ); input_consumed = TRUE; g_cond_signal( input_consumed_cond ); g_mutex_unlock( input_consumed_mutex ); return FALSE; } #endif /*---------------------------------------------------------------------------*/ #ifdef WIN32 static void * input_thread( void *dummy ) /* Read one line from STDIN, inform main thread when new input has arrived. */ { string_t input_type; while (TRUE) { input_type = read_line( stdin ); g_idle_add( (GSourceFunc) read_input_notify, input_type ); g_mutex_lock( input_consumed_mutex ); while (! input_consumed) g_cond_wait( input_consumed_cond, input_consumed_mutex ); input_consumed = FALSE; g_mutex_unlock( input_consumed_mutex ); free_mem( &input_type ); } return NULL; } #endif /*---------------------------------------------------------------------------*/ int main( int argc, char *argv[] ) { string_t malagarc_path, input_type; init_basic( "malshow" ); init_input(); init_scanner(); if (argc == 2) { if (strcmp_no_case( argv[1], "--version" ) == 0 || strcmp_no_case( argv[1], "-version" ) == 0 || strcmp_no_case( argv[1], "-v" ) == 0) { program_message(); exit(0); } else if (strcmp_no_case( argv[1], "--help" ) == 0 || strcmp_no_case( argv[1], "-help" ) == 0 || strcmp_no_case( argv[1], "-h" ) == 0) { printf( "Display results of a Malaga process in a graphical format.\n\n" "Usage:\n" "malshow -- Display results from malaga.\n" "malshow -v[ersion] -- Print the version number.\n" "malshow -h[elp] -- Print this help.\n\n" "This program is usually started by malaga or mallex.\n" ); exit(0); } } gtk_init( &argc, &argv ); /* Read Malaga profile. */ malagarc_path = NULL; #ifdef POSIX TRY malagarc_path = absolute_path( "~/.malagarc", NULL ); IF_ERROR RESUME; END_TRY; #endif #ifdef WIN32 TRY malagarc_path = absolute_path( "~\\malaga.ini", NULL ); IF_ERROR RESUME; END_TRY; #endif if (malagarc_path != NULL && file_exists( malagarc_path )) read_profile( malagarc_path ); free_mem( &malagarc_path ); /* Determine font name. */ if (font_family == NULL) { #ifdef POSIX font_family = new_string( "Sans", NULL ); #endif #ifdef WIN32 font_family = new_string( "Arial", NULL ); #endif } /* Read first input. */ input_type = read_line( stdin ); read_input( input_type ); free_mem( &input_type ); /* Prepare to read again whenever there is new input. */ #ifdef POSIX gdk_input_add( STDIN_FILENO, GDK_INPUT_READ, read_on_condition, NULL ); #endif #ifdef WIN32 g_thread_init( NULL ); input_consumed_cond = g_cond_new(); input_consumed_mutex = g_mutex_new(); g_thread_create( input_thread, NULL, FALSE, NULL ); #endif gtk_main(); free_mem( &font_family ); terminate_scanner(); terminate_input(); terminate_basic(); return 0; } /* End of file. =============================================================*/