/* @(#)dictionary.c	1.8	2/10/93 */
/*******************************************************************************

This code was written and designed by 
Andrew Gene HALL of I.N. Services Pty. Ltd., Scarborough WA, Australia,
for the 
University of Western Australia, Crawley WA, Australia.

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

   dictionary_check() function which complies with
   a STAR Dictionary Definition Language
   proposed by Tony Cook, Orac Ltd. (March 8 1991)

   The following is a description of the DDL data names used in this dictionary.

##############################################################################
#
#                        DDL Data Name Descriptions
#                        --------------------------
#
# _compliance           The dictionary version in which the item is defined.
#
# _definition           The description of the item.
#
# _enumeration          A permissible value for an item. The value 'unknown'
#                       signals that the item can have any value.
#
# _enumeration_default  The default value for an item if it is not specified
#                       explicitly. 'unknown' means default is not known.
#
# _enumeration_detail   The description of a permissible value for an item.
#                       Note that that the code '.' normally signals a null
#                       or 'not applicable' condition.
#
# _enumeration_range    The range of values for a numerical item. The
#                       construction is 'min:max'. If 'max' is omitted then the 
#                       item can have any value greater than or equal to 'min'.
#
# _esd                  Signals if an estimated standard deviation is 
#                       expected to be appended (enclosed within brackets)
#                       to a numerical item. May be 'yes' or 'no'.
#
# _esd_default          The default value for the esd of a numerical item
#                       if a value is not appended.
#
# _example              An example of the item.
#
# _example_detail       A description of the example.
#
# _list                 Signals if an item is expected to occur in a looped
#                       list. Possible values 'yes','no' or 'both'.
#
# _list_identifier      Identifies a data item that MUST appear in the list
#                       containing the currently defined data item.
#
# _name                 The data name of the item defined.
#
# _type                 The data type 'numb' or 'char' (latter includes 'text').
#
# _units_extension      The data name extension code used to specify the units 
#                       of a numerical item.
#
# _units_description    A description of the units.
#
# _units_conversion     The method of converting the item into a value based
#                       on the default units. Each conversion number is 
#                       preceded by an operator code *, /, +, or - which 
#                       indicates how the conversion number is applied.
#
# _update_history       A record of the changes to this file.
#
*******************************************************************************/

#include "utilitys.h"
#include "sf_space.h"
#include "find.h"
#include <string.h>
#include <ctype.h>

/* forward declarations */
extern char *strdup( char *) ; /* CHANGE 9/3 */
extern double	strtod(char *, char **);
Boolean	applicable( Data_Seq *data);
Boolean applicable_LVS( List_Value_Seq  *list);
Boolean	is_value( Data_Seq *data, char *re);
Boolean	is_value_LVS( List_Value_Seq *list, char *re);

typedef
struct {
   Data_Item	*data_name;
   Block_Seq	*defining_block;
} Quick_Ref;

/* externals */
char	*tsearch();
char	*tfind();

/* compare_2_Quick_Ref
 */
int	compare_2_Quick_Ref(
Quick_Ref	*node1,
Quick_Ref	*node2)
{
   if( node1 && node2 ) 
      return( strcmp( node1->data_name->value, node2->data_name->value ) );
   else {
      ERROR_MSG("compare_2_Quick_Ref(): could not compare null pointers.");
      return( 0 );
   }
} /* compare_2_Quick_Ref */

#define ADD_Quick_Ref( root, data_item, block) \
do {\
  Quick_Ref	*q;\
\
  if( (q = (Quick_Ref *)malloc(sizeof(Quick_Ref))) ) {\
    q->data_name = data_item;\
    q->defining_block = block;\
    DEBUG_MSG("Adding data to the Quick Reference tree,");\
    DEBUG_MSG(data_item->value);\
    if( ! tsearch((char *)q, (char **)root, compare_2_Quick_Ref) )\
      { ERROR_MSG("ADD_Quick_Ref(): Not enough memory for Quick_Ref tree.");}\
  } else\
  ERROR_MSG("ADD_Quick_Ref(): Not enough memory for Quick_Ref node.");\
} while(0)

/* LVS_Add_Quick_Ref
 */
void	LVS_Add_Quick_Ref(
Quick_Ref       **root,
List_Value_Seq  *list,
Block_Seq       *block)
{
   for( ; list; list = list->next)
      switch( list->tag ) {
      case DATA_ITEM:
           ADD_Quick_Ref( root, list->element.data_item, block);
           break;
      case SUB_LOOP:
           LVS_Add_Quick_Ref( root, list->element.sub_loop, block);
           break;
      default:
           ERROR_MSG("LVS_Add_Quick_Ref(): Unknown domain in LVS.");
      }
} /* LVS_Add_Quick_Ref */

/* Build_Quick_Ref_tree
 */
void	Build_Quick_Ref_tree(
Quick_Ref	**root,
Data_Seq	*data,
Block_Seq	*block)
{
  char	_name[] = "^_[Nn][Aa][Mm][Ee]$";

  /* scan down the sequence finding the "_name" entry */
  for( ; data; data = data->next)
     if( matches_RE( _name, data->name ) )
        switch( data->tag ) {
        case DATA_ITEM:
             ADD_Quick_Ref( root, data->data.data_item, block);
             break;
        case LOOP:
             LVS_Add_Quick_Ref( root, data->data.loop.values, block);
             break;
        default:
             ERROR_MSG("Build_Quick_Ref_tree(): unknown domain in sequence.");
        }
     else if( data->tag == SAVE_BLOCK )
        Build_Quick_Ref_tree( root, data->data.save_block, block);

   return;
} /* Build_Quick_Ref_tree */


/*******************************************************************************
 * validation functions
 ******************************************************************************/

/* valid_name()
 */
Block_Seq	*valid_name(
Block_Seq       *dict,
char		*name)
{
  Block_Seq	*b = dict;
  Data_Seq	*data = NULL;
  char		*_name = strdup("_[Nn][Aa][Mm][Ee]");

  while( (data = find_Data_Name_in_BS( _name, &b)) )
     if( is_value( data, name) )
        return( b );
     else
        b = b->next;
  return( NULL );
} /* valid_name() */

#define valid_compliance( b, v) TRUE
#define valid_definition( b, v) TRUE

/* valid_enumeration()
 */
Boolean valid_enumeration(
Block_Seq       *block,
char            *value)
{
  char  s[] = "^_[Ee][Nn][Uu][Mm][Ee][Rr][Aa][Tt][Ii][Oo][Nn]$";
  Data_Seq      *defn;
  Block_Seq     *b = block;
  Block_Seq     *next = block->next;

  b->next = NULL;
  defn = find_Data_Name_in_BS( s, &b );
  block->next = next;

  if( applicable( defn ) )
     if( ! is_value( defn, value) ) {
        ERROR_MSG("Value is not a valid ENUMERATION,");
        return( FALSE );
     }
  return( TRUE );
} /* valid_enumeration() */

#define valid_enumeration_default( b, v) TRUE
#define valid_enumeration_detail( b, v) TRUE

Boolean	in_range( Data_Item *, char *);
Boolean	in_LVS_range( List_Value_Seq *, char *);
/* valid_enumeration_range()
 */
Boolean valid_enumeration_range(
Block_Seq       *block,
char            *value)
{
  char  s[] = "^_[Ee][Nn][Uu][Mm][Ee][Rr][Aa][Tt][Ii][Oo][Nn]_[Rr][Aa][Nn][Gg][Ee]$";
  Data_Seq      *defn;
  Block_Seq     *b = block;
  Block_Seq     *next = block->next;

  b->next = NULL;
  defn = find_Data_Name_in_BS( s, &b );
  block->next = next;

  if( applicable( defn ) )
     switch( defn->tag ) {
     case DATA_ITEM:
        if( ! in_range( defn->data.data_item, value ) ) return( FALSE );
        break;

     case LOOP:
        if( ! in_LVS_range( defn->data.loop.values, value ) ) return( FALSE );
        break;

     default:
        ERROR_MSG("valid_enumeration_range(): Inadmissable type of data in Dictionary specification.");
     }
  return( TRUE );
} /* valid_enumeration_range() */


/* valid_esd()
 */
Boolean valid_esd(
Block_Seq       *block,
char		*value)
{
  char  s[] = "^_[Ee][Ss][Dd]$";
  Data_Seq      *defn;
  Block_Seq     *b = block;
  Block_Seq     *next = block->next;

  b->next = NULL;
  defn = find_Data_Name_in_BS( s, &b );
  block->next = next;

  if( applicable( defn ) ) {
     Boolean	may_have_an_ESD = FALSE;
     char    *next_ch = NULL;

     if( is_value( defn, "[Yy][Ee][Ss]") ) 
       may_have_an_ESD = TRUE;
     else if( is_value( defn, "[Nn][Oo]" ) ) 
       may_have_an_ESD = FALSE;
     else
       ERROR_MSG("Inconclusive dictionary specification for this Data's _ESD.");

     (void)strtod( value, &next_ch);
     if( next_ch == value )
        /* could not convert number */
        if( may_have_an_ESD ) {
           ERROR_MSG("Value is not a Number when trying to determine if it has an ESD,");
           return( FALSE );
        } else
           return( TRUE ); 
     else {
        /* search for trailing esd */
        /* skip over leading ' ' and '(' */
        while( isspace( *next_ch ) || ( *next_ch == '(' ) ) next_ch++;
        if( *next_ch ) {
           value = next_ch;
           /* find the esd */
           (void)strtod( value, &next_ch);
           if( value == next_ch )
              /* could not convert esd */
              if( may_have_an_ESD ) {
                 ERROR_MSG("Value does not have a valid ESD,");
                 return( FALSE );
              } else
                 return( TRUE );
           else {
              /* skip over trailing ' ' and ')' */
              while( isspace( *next_ch ) || ( *next_ch == ')' ) ) next_ch++;
              if( *next_ch )
                 if( may_have_an_ESD ) {
                    ERROR_MSG("Trailing garbage after the ESD,");
                    return( FALSE );
                 } else
                    return( TRUE );
              else
                 if( may_have_an_ESD )
                    return( TRUE );
                 else {
                    ERROR_MSG("Value has an ESD when it should not,");
                    return( FALSE );
                 }
           }
        } else
              if( may_have_an_ESD ) {
                 ERROR_MSG("Value does not have an ESD when it should,");
                 return( FALSE );
              } else
                 return( TRUE );
     }
  } else
     return( TRUE );
} /* valid_esd() */

#define valid_esd_default( b, v) TRUE

/* valid_list()
 */
Boolean valid_list(
Block_Seq       *block,
Domain		value)
{
  char	s[] = "^_[Ll][Ii][Ss][Tt]$";
  Data_Seq	*defn;
  Block_Seq	*b = block;
  Block_Seq	*next = block->next;

  b->next = NULL;
  defn = find_Data_Name_in_BS( s, &b );
  block->next = next;

  if( applicable( defn ) ) {
     switch( value ) {
        case DATA_ITEM:
             if( is_value( defn, "[Yy][Ee][Ss]") ) {
                return( FALSE );
             } else if( is_value(defn,"[Nn][Oo]") || 
                      is_value(defn,"[Bb][Oo][Tt][Hh]") )
                return( TRUE );
             break;
        case LOOP:
             if( is_value( defn, "[Yy][Ee][Ss]") ||
                 is_value(defn,"[Bb][Oo][Tt][Hh]") ) 
                return( TRUE );
             else if( is_value(defn,"[Nn][Oo]") ) {
                return( FALSE );
             }
             break;
        default:
             ERROR_MSG("valid_list(): unknown domain in sequence.");
             return( FALSE );
     }
     ERROR_MSG("Inconclusive dictionary specification for this Data's _LIST.");
  } 
  return( TRUE );
} /* valid_list() */

Boolean	in_DNS( Data_Seq *defn, Data_Name_Seq *names);
/* valid_list_identifier()
 */
Boolean valid_list_identifier(
Block_Seq	*block,
Data_Name_Seq	*names)
{
  char  s[] = "^_[Ll][Ii][Ss][Tt]_[Ii][Dd][Ee][Nn][Tt][Ii][Ff][Ii][Ee][Rr]$";
  Data_Seq      *defn;
  Block_Seq     *b = block;
  Block_Seq     *next = block->next;

  b->next = NULL;
  defn = find_Data_Name_in_BS( s, &b );
  block->next = next;

  if( applicable( defn ) ) {
    if( is_value( defn, "_[^ \t\n]") ) {
       if( ! in_DNS( defn, names ) ) return( FALSE );
    } else {
       ERROR_MSG("Data specification in the Dictionary has an invalid _LIST_IDENTIFIER.");
       return( FALSE );
    }
  }
  return( TRUE );
} /* valid_list_identifier() */
 
#define valid_example( b, v) TRUE
#define valid_example_detail( b, v) TRUE

/* valid_type
 */
Boolean	valid_type(
Block_Seq       *block,
char		*value)
{
  char	s[] = "^_[Tt][Yy][Pp][Ee]$";
  Data_Seq	*defn;
  Block_Seq	*b = block;
  Block_Seq	*next = block->next;

  b->next = NULL;
  defn = find_Data_Name_in_BS( s, &b );
  block->next = next;

  if( applicable( defn ) )
     if( is_value(defn,"[Cc][Hh][Aa][Rr]") || is_value(defn,"[Tt][Ee][Xx][Tt]"))
        /* assume text means any text, rather than not a number */
        return( TRUE );
     else if( is_value( defn, "[Nn][Uu][Mm][Bb]" ) ) {
        char	*next_ch = NULL;

        (void)strtod( value, &next_ch);
        if( next_ch == value ) {
           /* could not convert number */
           ERROR_MSG("Value is not a Number when it should be,");
           return( FALSE );
        } else
           return( TRUE );
     } else {
        ERROR_MSG("Inconclusive dictionary specification for this Data Item's _TYPE.");
        return( FALSE );
     }
  else
     return( TRUE );
} /* valid_type */

/* valid_units_conversion()
 */
#define valid_units_conversion( b, v) TRUE
#define valid_units_extension( b, v) TRUE
#define valid_units_description( b, v) TRUE
#define valid_update_history( b, v) TRUE

/* valid_Data_Item
 */
Boolean	valid_Data_Item(
Block_Seq	*block,
Data_Item	*item)
{
  Boolean       valid = TRUE;

  if( ! (strcmp( ".", item->value ) && strcmp( "?", item->value )) )
     /* value is either "." or "?" then assume TRUE */
     return( TRUE );
  if( ! valid_compliance( block, item->value) ) valid = FALSE;
  if( ! valid_definition( block, item->value) ) valid = FALSE;
  if( ! valid_enumeration( block, item->value) ) valid = FALSE;
  if( ! valid_enumeration_default( block, item->value) ) valid = FALSE;
  if( ! valid_enumeration_detail( block, item->value) ) valid = FALSE;
  if( ! valid_enumeration_range( block, item->value) ) valid = FALSE;
  if( ! valid_esd( block, item->value) ) valid = FALSE;
  if( ! valid_esd_default( block, item->value) ) valid = FALSE;
  if( ! valid_example( block, item->value) ) valid = FALSE;
  if( ! valid_example_detail( block, item->value) ) valid = FALSE;
  /* valid_list is called before any of this checking is done */
  /* valid_list_identifier is called before any of this checking is done */
  /* valid_name is called before any of this checking is done */
  if( ! valid_type( block, item->value) ) valid = FALSE;
  if( ! valid_units_extension( block, item->value) ) valid = FALSE;
  if( ! valid_units_description( block, item->value) ) valid = FALSE;
  if( ! valid_units_conversion( block, item->value) ) valid = FALSE;
  if( ! valid_update_history( block, item->value) ) valid = FALSE;

  if( ! valid ) ERROR_MSG(item->value);
  return( valid );
} /* valid_Data_Item */

/* valid_LVS
 */
Boolean	valid_LVS(
Block_Seq	*block,
List_Value_Seq	*list)
{
  Boolean       valid = TRUE;

   for( ; list; list = list->next)
      switch( list->tag ) {
      case DATA_ITEM:
           if( ! valid_Data_Item(block, list->element.data_item) )
             valid = FALSE;
           break;
      case SUB_LOOP:
           if( ! valid_LVS(block, list->element.sub_loop) ) valid = FALSE;
           break;
      default:
           ERROR_MSG("valid_LVS(): Unknown domain in LVS.");
      }
  return( valid );
} /* valid_LVS */

/* vaild_Data_Seq
 */
Boolean	valid_Data_Seq(
Block_Seq	*dict,
Data_Seq	*data)
{
  Boolean       valid = TRUE;
  Block_Seq	*entry;

  /* scan thru the sequence checking each piece of data */
  for( ; data; data = data->next)
     if( (entry = valid_name( dict, data->name )) )
        switch( data->tag ) {
        case DATA_ITEM:
             if( ! valid_list( entry, DATA_ITEM) ) {
                valid = FALSE;
                ERROR_MSG("Data is a single Data Item, when it should be in a Loop,");
                ERROR_MSG(data->name);
             }
             if( ! valid_Data_Item(entry, data->data.data_item)){
                valid = FALSE;
                ERROR_MSG("Data has an invalid Data Item,");
                ERROR_MSG(data->name);
             }
             break;

        case LOOP:
             if( ! valid_list( entry, LOOP) ) {
                valid = FALSE;
                ERROR_MSG("Data is in a loop, when it should not be,");
                ERROR_MSG(data->name);
             }
             if( ! valid_list_identifier( entry,data->data.loop.packet_members)){
                valid = FALSE;
                ERROR_MSG("Data does not share a loop with a given _LIST_IDENTIFIER,");
                ERROR_MSG(data->name);
             }
             if( ! valid_LVS(entry, data->data.loop.values ) ){
                valid = FALSE;
                ERROR_MSG("Data has an invalid Data Item,");
                ERROR_MSG(data->name);
             }
             break;
        default:
             ERROR_MSG("valid_Data_Seq(): unknown domain in sequence.");
        }
     else if( data->tag == SAVE_BLOCK ) {
          if( ! valid_Data_Seq( dict, data->data.save_block) ) {
              valid = FALSE;
              ERROR_MSG("Save Block contains invalid data,");
              ERROR_MSG(data->name);
          }
     } else {
        valid = FALSE;
        ERROR_MSG("Data is not defined in the dictionary,");
        ERROR_MSG(data->name);
     }
  return( valid );
} /* valid_Data_Seq */

Boolean	dictionary_check(
Block_Seq	*dictionary,
Block_Seq	*input)
{
  Boolean	valid = TRUE;

  /* forall blocks in the input */
  for( ; input; input = input->next )
     switch( input->tag ) {
     case DATA_BLOCK:
          if( ! valid_Data_Seq( dictionary, 
                                input->block.data_block.actual_data) ) {
              valid = FALSE;
              ERROR_MSG("Data Block contains invalid data,");
              ERROR_MSG(input->name);
          }
          break;

     case GLOBAL_BLOCK:
          if( ! valid_Data_Seq( dictionary, input->block.global_block) ) {
              valid = FALSE;
              ERROR_MSG("Data Block contains invalid data,");
              ERROR_MSG(input->name);
          }
          break;

     default:
         ERROR_MSG("dictionary_check(): Unknown block in Block Sequence.");
     } /* end case switch */

  return( valid );
} /* dictionary_check */

/* applicable()
 * Determine if a piece of data has ANY applicable data in it.
 */
Boolean	applicable(
Data_Seq	*data)
{
  if( data )
     switch( data->tag ) {
     case DATA_ITEM:
          if( ! (strcmp( ".", data->data.data_item->value) && 
                 strcmp( "?", data->data.data_item->value)) )
             /* value is "." or "?" */
             return( FALSE );
          else
             return( TRUE );
          break;

     case LOOP:
          return( applicable_LVS( data->data.loop.values) );
          break;

     case SAVE_BLOCK: {
          Data_Seq      *d;

          for( d = data->data.save_block; d; d = d->next )
             if( applicable( d) ) return( TRUE );
          return( FALSE );
          } break;

     default:
          ERROR_MSG("applicable(): unknown domain in data sequence.");
     }
  return( FALSE );
} /* applicable() */

/* applicable_LVS
 */
Boolean applicable_LVS(
List_Value_Seq  *list)
{
   for( ; list; list = list->next)
     switch( list->tag ) {
     case DATA_ITEM:
          if( (strcmp( ".", list->element.data_item->value) && 
               strcmp( "?", list->element.data_item->value)) )
             /* value is not ".", and not "?" */
             return( TRUE );
          break;
     case SUB_LOOP:
          if( applicable_LVS( list->element.sub_loop) ) return( TRUE );
          break;
     default:
          ERROR_MSG("applicable_LVS(): Unknown domain in LVS.");
     }
   return( FALSE );
} /* applicable_LVS() */

/* is_value()
 * Given a piece of data,
   does it have ANY value matching the RE given.
 */
Boolean	is_value(
Data_Seq	*data,
char		*re)
{
  if( data )
     switch( data->tag ) {
     case DATA_ITEM:
          return( matches_RE( re, data->data.data_item->value) );
          break;

     case LOOP:
          return( is_value_LVS( data->data.loop.values, re) );
          break;

     case SAVE_BLOCK: {
          Data_Seq	*d;

          for( d = data->data.save_block; d; d = d->next )
             if( is_value( d, re) ) return( TRUE );
          } break;

     default:
          ERROR_MSG("is_value(): unknown domain in data sequence.");
     }
  return( FALSE );
} /* is_value() */

/* is_value_LVS()
 */
Boolean	is_value_LVS(
List_Value_Seq	*list,
char		*re)
{
   for( ; list; list = list->next)
      switch( list->tag ) {
      case DATA_ITEM:
           if( matches_RE( re, list->element.data_item->value) ) return( TRUE );
           break;
      case SUB_LOOP:
           if( is_value_LVS( list->element.sub_loop, re) ) return( TRUE );
           break;
      default:
           ERROR_MSG("is_value_LVS(): Unknown domain in LVS.");
      }
   return( FALSE );
} /* is_value_LVS() */

/* in_DNS()
 */
Boolean	in_DNS(
Data_Seq	*defn, 
Data_Name_Seq	*names)
{
  for( ; names; names = names->next)
     switch( names->tag ) {
     case NAME:
        if( is_value( defn, names->node.name) ) return( TRUE );
        break;
     case SUB_LOOP:
        if( in_DNS( defn, names->node.sub_loop) ) return( TRUE );
        break;
     default:
        ERROR_MSG("in_DNS(): Unknown domain in Data Name Sequence.");
     }
  return( FALSE );
} /* in_DNS() */

/* in_range()
 */
Boolean	in_range(
Data_Item	*item,
char            *value)
{
  if( item ) {
     char	*s = item->value;
     char	*next_ch = s;
     double	x1,x2,v;
     double	*min = NULL; /* => -infinity */
     double	*max = NULL; /* => +infinity */

     /* calculate minimum */
     /* skip over ' ' */
     while( isspace( *next_ch ) ) next_ch++;
     if( *next_ch != ':' ) {
        s = next_ch;
        x1 = strtod( s, &next_ch);
        if( s == next_ch ) {
           /* not a number */
           ERROR_MSG("Could not determine the minimum in the Dictionary specification,");
           return( FALSE );
        } else
           min = &x1;
     }
     /* else there is no lower limit */

     /* calculate maximum */
     /* skip over ' ' */
     while( isspace( *next_ch ) ) next_ch++;
     if( *next_ch == ':' ) {
        /* step over ':' */
        next_ch++;
        while( isspace( *next_ch ) ) next_ch++;
        if( *next_ch ) {
           s = next_ch;
           x2 = strtod( s, &next_ch);
           if( s == next_ch ) {
              /* not a number */
              ERROR_MSG("Could not determine the maximum in the Dictionary specification,");
              return( FALSE );
           } else
              max = &x2;
        } /* else just trailing spaces */
     } else {
           ERROR_MSG("Garbage trailing the minimum in the Dictionary specification,");
           return( FALSE );
     }

     /* calculate value */
     v = strtod( value, &next_ch);
     if( value == next_ch ) {
        ERROR_MSG("Value was not number so could not test the range,");
        return( FALSE );
     }

     /* test if its in range */
     if( min ) if( v < *min ) {
        ERROR_MSG("Value was below the lower limit,");
        return( FALSE );
     }
     if( max ) if( v > *max ) {
        ERROR_MSG("Value was beyond the upper limit,");
        return( FALSE );
     }
  }
  return( TRUE );
} /* in_range() */

/* in_LVS_range ()
 */
Boolean	in_LVS_range(
List_Value_Seq  *list,
char		*value)
{
   for( ; list; list = list->next)
      switch( list->tag ) {
      case DATA_ITEM:
           if( in_range( list->element.data_item, value) ) return( TRUE );
           break;
      case SUB_LOOP:
           if( in_LVS_range( list->element.sub_loop, value) ) return( TRUE );
           break;
      default:
           ERROR_MSG("in_LVS_range(): Unknown domain in LVS.");
      }
   return( FALSE );

} /* in_LVS_range() */
