/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by Mike Parker.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

#include "defs.h"
#include "fsm.h"

static I_F current_number;
static int sign;
static int exp_sign;
static int exponent;
static double multiplier;
static float min_float;
static float max_float;
static char *remembered_name;
static int have;
static int len;
FSMarg *_TMPFSM_getarg();

static char *copyofstr();
static KEY *newkey();
static KEY *new_key_on_tree();
static TREE *pop_tree();

_TMP_init_fsmsubs()
{
 FtoI(min_float) = MIN_FLOAT;
 FtoI(max_float) = MAX_FLOAT;
 remembered_name = 0;
}

static char *copyofstr(s)
char *s;
{
 char *cp;

 cp = malloc(strlen(s)+1);
 strcpy(cp,s);
 return(cp);
}

static KEY *newkey()
{
 register KEY *k;

 k = NEW(KEY);
 k->link = 0;
 k->subtree = 0;
 k->number = -12345;
 k->type = 0;
 k->match_routine = 0;
 k->name = 0;
 k->help = 0;
 k->prompt = 0;
 return(k);
}

_TMP_allocate_new_tree(ch)
int ch;
{
 TREE *t;

#ifdef lint
 ch = ch;
#endif
 t = NEW(TREE);
 t->keys = 0;
 t->name = 0;
 _TMP_current_tree = t;
}

int _TMP_get_named_tree(name)
char *name;
{
 TREE *t;

 for (t=_TMP_named_tree_chain;t;t=t->link)
  { if (strcmp(t->name,name) == 0)
     { _TMP_current_tree = t;
       return(1);
     }
  }
 return(0);
}

_TMP_name_tree(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_current_tree->name = copyofstr(remembered_name);
 _TMP_current_tree->link = _TMP_named_tree_chain;
 _TMP_named_tree_chain = _TMP_current_tree;
}

_TMP_unname_tree(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 free_if(_TMP_current_tree->name);
 _TMP_current_tree->name = 0;
}

static KEY *new_key_on_tree()
{
 KEY *k;

 k = newkey();
 k->link = _TMP_current_tree->keys;
 _TMP_current_tree->keys = k;
 k->flags.c = 0;
 k->match_routine = 0;
 return(k);
}

_TMP_new_key(ch)
int ch;
{
 KEY *k;

#ifdef lint
 ch = ch;
#endif
 k = new_key_on_tree();
 k->type = KEY_NORMAL;
 k->number = 0;
 k->name = copyofstr(remembered_name);
}

_TMP_push_current_tree(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_tree_stack[_TMP_trees_stacked++] = _TMP_current_tree;
}

static TREE *pop_tree()
{
 return(_TMP_tree_stack[--_TMP_trees_stacked]);
}

_TMP_no_subtree(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_current_tree->keys->subtree = 0;
}

_TMP_make_tree_subtree(ch)
int ch;
{
 TREE *t = pop_tree();

#ifdef lint
 ch = ch;
#endif
 t->keys->subtree = _TMP_current_tree;
 _TMP_current_tree = t;
}

_TMP_set_key_conditional(n)
int n;
{
 _TMP_current_tree->keys->match_routine = (int (*)()) n;
}

_TMP_import_current_tree(ch)
int ch;
{
 TREE *t;
 KEY *k;
 KEY *K;

#ifdef lint
 ch = ch;
#endif
 t = pop_tree();
 k = _TMP_current_tree->keys;
 for (;k;k=k->link)
  { K = t->keys;

    t->keys = newkey();
    *(t->keys) = *k;
    t->keys->link = K;
  }
 _TMP_current_tree = t;
}

_TMP_set_integer_minimum(ch)
int ch;
{
 KEY *k;

#ifdef lint
 ch = ch;
#endif
 k = _TMP_current_tree->keys;
 k->min.i = current_number.i;
 k->flags.s.min_addr = 0;
}

_TMP_set_integer_min_addr(n)
int n;
{
 KEY *k;

 k = _TMP_current_tree->keys;
 k->min.ip = (int *) n;
 k->flags.s.min_addr = 1;
}

_TMP_set_integer_maximum(ch)
int ch;
{
 KEY *k;

#ifdef lint
 ch = ch;
#endif
 k = _TMP_current_tree->keys;
 k->max.i = current_number.i;
 k->flags.s.max_addr = 0;
}

_TMP_set_integer_max_addr(n)
int n;
{
 KEY *k;

 k = _TMP_current_tree->keys;
 k->max.ip = (int *) n;
 k->flags.s.max_addr = 1;
}

_TMP_init_for_integer(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 current_number.i = 0;
 sign = 1;
}

_TMP_negate_integer(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 sign = - sign;
}

_TMP_integer_value(n)
int n;
{
 current_number.i = sign * n;
}

_TMP_parse_blanks(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMPFSM_getarg()->flags |= FSM_FLAG_PARSE_BLANKS;
}

_TMP_skip_blanks(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMPFSM_getarg()->flags &= ~FSM_FLAG_PARSE_BLANKS;
}

_TMP_set_real_minimum(ch)
int ch;
{
 KEY *k;

#ifdef lint
 ch = ch;
#endif
 k = _TMP_current_tree->keys;
 k->min.f = current_number.f;
 k->flags.s.min_addr = 0;
}

_TMP_set_real_min_addr(n)
int n;
{
 KEY *k;

 k = _TMP_current_tree->keys;
 k->min.fp = (float *) n;
 k->flags.s.min_addr = 1;
}

_TMP_set_real_maximum(ch)
int ch;
{
 KEY *k;

#ifdef lint
 ch = ch;
#endif
 k = _TMP_current_tree->keys;
 k->max.f = current_number.f;
 k->flags.s.max_addr = 0;
}

_TMP_set_real_max_addr(n)
int n;
{
 KEY *k;

 k = _TMP_current_tree->keys;
 k->max.fp = (float *) n;
 k->flags.s.max_addr = 1;
}

_TMP_init_for_real(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 current_number.f = 0;
 sign = 1;
 exp_sign = 1;
 exponent = 0;
 multiplier = 1;
}

_TMP_negate_real(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 sign = - sign;
}

_TMP_negate_exp(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 exp_sign = - exp_sign;
}

_TMP_set_exp(n)
int n;
{
 exponent = n;
}

_TMP_integer_part_real(n)
int n;
{
 current_number.f = n;
}

_TMP_real_fraction_digit(d)
char d;
{
 register int i = d - '0';

 current_number.f += i * (multiplier /= 10);
}

_TMP_finish_real(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 current_number.f *= sign;
 exponent *= exp_sign;
 while (exponent < 0)
  { current_number.f /= 10;
    exponent ++;
  }
 while (exponent > 0)
  { current_number.f *= 10;
    exponent --;
  }
}

_TMP_int_addr_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_I;
 k->number = n;
 k->name = 0;
 k->min.i = MIN_INT;
 k->max.i = MAX_INT;
}

_TMP_hex_addr_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_X;
 k->number = n;
 k->name = 0;
 k->min.i = MIN_INT;
 k->max.i = MAX_INT;
}

_TMP_oct_addr_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_O;
 k->number = n;
 k->name = 0;
 k->min.i = MIN_INT;
 k->max.i = MAX_INT;
}

_TMP_real_addr_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_R;
 k->number = n;
 k->name = 0;
 k->min.f = min_float;
 k->max.f = max_float;
}

_TMP_double_addr_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_D;
 k->number = n;
 k->name = 0;
 k->min.f = min_float;
 k->max.f = max_float;
}

_TMP_str_addr_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_S;
 k->number = n;
 k->name = 0;
}

_TMP_var_key(n)
int n;
{
 KEY *k = new_key_on_tree();

 k->type = KEY_V;
 k->number = n;
 k->name = 0;
}

_TMP_init_literal(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 free_if(remembered_name);
 remembered_name = malloc(have=0);
 len = 0;
 _TMPFSM_getarg()->flags |= FSM_FLAG_PARSE_BLANKS;
}

_TMP_literal_char(c)
char c;
{
 while (len >= have)
  { remembered_name = realloc(remembered_name,have+=16);
  }
 remembered_name[len++] = c;
}

_TMP_finish_literal(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 remembered_name = realloc(remembered_name,len+1);
 remembered_name[len] = '\0';
 _TMPFSM_getarg()->flags &= ~FSM_FLAG_PARSE_BLANKS;
}

_TMP_help_string(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_finish_literal(0);
 _TMP_current_tree->keys->help = copyofstr(remembered_name);
}

_TMP_set_key_prompt(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_current_tree->keys->prompt = copyofstr(remembered_name);
}

_TMP_reverse_keyword_order(ch)
int ch;
{
 KEY *k;
 KEY *K;

#ifdef lint
 ch = ch;
#endif
 k = _TMP_current_tree->keys;
 _TMP_current_tree->keys = 0;
 for (;k;k=K)
  { K = k->link;
    k->link = _TMP_current_tree->keys;
    _TMP_current_tree->keys = k;
  }
}

_TMP_remember_name(s)
char *s;
{
 free_if(remembered_name);
 remembered_name = copyofstr(s);
}

/* VARARGS1 */
_TMP_set_recent(n,ch)
int n;
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_current_tree->n_recent = n;
}

_TMP_increment_recent(ch)
int ch;
{
#ifdef lint
 ch = ch;
#endif
 _TMP_current_tree->n_recent ++;
}

_TMP_check_recent(ch)
int ch;
{
 KEY *k;

#ifdef lint
 ch = ch;
#endif
 if (_TMP_current_tree->n_recent <= 1)
  { return;
  }
 for (k=_TMP_current_tree->keys->link;--_TMP_current_tree->n_recent>0;k=k->link)
  { k->subtree = _TMP_current_tree->keys->subtree;
    k->prompt = _TMP_current_tree->keys->prompt;
  }
}
