which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@976 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			2302 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2302 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* r4relate.c   (c)Copyright Sequiter Software Inc., 1992-1994.  All rights reserved. */
 | 
						|
 | 
						|
#include "d4all.h"
 | 
						|
#ifndef S4UNIX
 | 
						|
#ifdef __TURBOC__
 | 
						|
#pragma hdrstop
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#include <time.h>
 | 
						|
 | 
						|
int S4FUNCTION f4flag_is_set_flip( F4FLAG *flag_ptr, unsigned long r )
 | 
						|
{
 | 
						|
  if ( flag_ptr->flags == 0 )
 | 
						|
    return 1 ;
 | 
						|
 | 
						|
  if ( flag_ptr->is_flip )
 | 
						|
    return ! f4flag_is_set( flag_ptr, r ) ;
 | 
						|
  else
 | 
						|
    return f4flag_is_set( flag_ptr, r ) ;
 | 
						|
}
 | 
						|
 | 
						|
/* returns the position of the next flipped flag in the flag set - start at r */
 | 
						|
unsigned long S4FUNCTION f4flag_get_next_flip( F4FLAG *f4, unsigned long r, char direction )
 | 
						|
{
 | 
						|
  unsigned char c_flag ;
 | 
						|
  unsigned long low_val, on_val ;
 | 
						|
  char i ;
 | 
						|
  unsigned long high_val ;
 | 
						|
 | 
						|
  c_flag = 0 ;
 | 
						|
  on_val = r ;
 | 
						|
  if ( f4->flags == 0 || r > f4->num_flags )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  low_val = (unsigned long)( r & 0x7 ) ;
 | 
						|
  high_val = (unsigned long)( r >> 3 ) ;
 | 
						|
 | 
						|
  if ( (int)direction == -1 )
 | 
						|
  {
 | 
						|
    c_flag = (unsigned char)( f4->flags[high_val] ) ;
 | 
						|
    if ( f4->is_flip )
 | 
						|
      c_flag = (unsigned char) ~c_flag ;
 | 
						|
 | 
						|
    c_flag = (unsigned char)( (unsigned char)( c_flag << ( 7 - low_val ) ) >> ( 7 - low_val )) ;
 | 
						|
 | 
						|
    on_val += ( 7 - low_val ) ;
 | 
						|
 | 
						|
    if ( c_flag == 0 )
 | 
						|
      for( ; c_flag == 0 ; on_val -= 8 )
 | 
						|
      {
 | 
						|
        if ( high_val-- <= 1 )  /* if was zero, or is now zero */
 | 
						|
        {
 | 
						|
          if ( f4->flags[0] == 0 )
 | 
						|
            return r ;
 | 
						|
          c_flag = f4->flags[0] ;
 | 
						|
          if ( f4->is_flip )
 | 
						|
            c_flag = (unsigned char) ~c_flag ;
 | 
						|
          on_val -= 8 ;  /* for sure if high_val == 0, else?? */
 | 
						|
          break ;
 | 
						|
        }
 | 
						|
        c_flag = f4->flags[high_val] ;
 | 
						|
        if ( f4->is_flip )
 | 
						|
          c_flag = (unsigned char) ~c_flag ;
 | 
						|
      }
 | 
						|
 | 
						|
    for( i = 7 ; (int)i >= 0 ; i--, on_val-- )
 | 
						|
      if ( c_flag & ( 0x01 << i ) )
 | 
						|
        break ;
 | 
						|
 | 
						|
    return (r - on_val) ;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    c_flag = (unsigned char)f4->flags[high_val] ;
 | 
						|
    if ( f4->is_flip )
 | 
						|
      c_flag = (unsigned char) ~c_flag ;
 | 
						|
    c_flag = (unsigned char) (c_flag >> low_val) ;
 | 
						|
    if ( c_flag == 0 )
 | 
						|
    {
 | 
						|
      on_val -= low_val ;
 | 
						|
      for( ; c_flag == 0 ; on_val += 8 )
 | 
						|
      {
 | 
						|
        if ( on_val >= f4->num_flags )
 | 
						|
          return (f4->num_flags - r + 1) ;
 | 
						|
        c_flag = f4->flags[++high_val] ;
 | 
						|
        if ( f4->is_flip )
 | 
						|
          c_flag = (unsigned char) ~c_flag ;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    for( i = 0 ; i <= 7 ; i++, on_val++ )
 | 
						|
      if ( c_flag & ( 0x01 << i ) )
 | 
						|
        break ;
 | 
						|
 | 
						|
    return (on_val - r) ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION r4data_list_add( LIST4 *l4, DATA4 *data, RELATE4 *relate )
 | 
						|
{
 | 
						|
  R4DATA_LIST *r4 ;
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  r4 = (R4DATA_LIST *)u4alloc_free( data->code_base, sizeof( R4DATA_LIST ) ) ;
 | 
						|
  if ( r4 == 0 )
 | 
						|
    return -1 ;
 | 
						|
  r4->data = data ;
 | 
						|
  r4->relate = relate ;
 | 
						|
  l4add( l4, r4 ) ;
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION r4data_list_find( LIST4 *l4, RELATE4 *r4 )
 | 
						|
{
 | 
						|
  R4DATA_LIST *link ;
 | 
						|
 | 
						|
  for ( link = 0 ;; )
 | 
						|
  {
 | 
						|
    link = (R4DATA_LIST *)l4next( l4, link ) ;
 | 
						|
    if ( link == 0 )
 | 
						|
      return 0 ;
 | 
						|
    if ( link->relate == r4 )
 | 
						|
      return 1 ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void S4FUNCTION r4data_list_free( LIST4 *l4 )
 | 
						|
{
 | 
						|
  R4DATA_LIST *r4data, *r4data2 ;
 | 
						|
 | 
						|
  for ( r4data = (R4DATA_LIST *)l4first( l4 ) ; r4data ; )
 | 
						|
  {
 | 
						|
    r4data->relate->sort_type = 0 ;
 | 
						|
    r4data2 = (R4DATA_LIST *)l4next( l4, r4data ) ;
 | 
						|
    l4remove( l4, r4data ) ;
 | 
						|
    u4free( r4data ) ;
 | 
						|
    r4data = r4data2 ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* this function takes a completed sort list, and adds data members in the
 | 
						|
   following case:
 | 
						|
 | 
						|
   If (r)elate must be added, r's siblings must also be added
 | 
						|
 | 
						|
   Or, interpreted differently, if r is a relation, and any of it's children
 | 
						|
   must be added, then all of its children must be added.
 | 
						|
   */
 | 
						|
static int r4data_list_massage( LIST4 *l4 )
 | 
						|
{
 | 
						|
  RELATE4 *relate_child ;
 | 
						|
  R4DATA_LIST *r4data ;
 | 
						|
  int add_children, relate_added ;
 | 
						|
 | 
						|
  if ( l4->n_link == 0 )  /* no work required */
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  r4data = 0 ;
 | 
						|
 | 
						|
  for( ;; )
 | 
						|
  {
 | 
						|
    r4data = (R4DATA_LIST *)l4next( l4, r4data ) ;
 | 
						|
    if ( r4data == 0 )
 | 
						|
      break ;
 | 
						|
 | 
						|
    relate_child = 0 ;
 | 
						|
    add_children = 0 ;
 | 
						|
    for( ;; )
 | 
						|
    {
 | 
						|
      relate_child = (RELATE4 *)l4next( &r4data->relate->slaves, relate_child ) ;
 | 
						|
      if ( relate_child == 0 )
 | 
						|
        break ;
 | 
						|
      if ( r4data_list_find( l4, relate_child ) )
 | 
						|
      {
 | 
						|
        add_children = 1 ;
 | 
						|
        break ;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( add_children == 1 )
 | 
						|
    {
 | 
						|
      relate_added = 0 ;
 | 
						|
      relate_child = 0 ;
 | 
						|
      for( ;; )
 | 
						|
      {
 | 
						|
        relate_child = (RELATE4 *)l4next( &r4data->relate->slaves, relate_child ) ;
 | 
						|
        if ( relate_child == 0 )
 | 
						|
          break ;
 | 
						|
        if ( r4data_list_find( l4, relate_child ) == 0 )
 | 
						|
        {
 | 
						|
          r4data_list_add( l4, relate_child->data, relate_child ) ;
 | 
						|
          relate_child->sort_type = relate4exact ;
 | 
						|
          relate_added = 1 ;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if ( relate_added == 1 )
 | 
						|
        r4data = 0 ;   /* start at list top again to be sure none missed */
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
/* 1 - database added, 0 - database not added, -1 - error */
 | 
						|
/* check_type gives the caller's status in terms of whether we should be included */
 | 
						|
int S4FUNCTION r4data_list_build( LIST4 *l4, RELATE4 *relate, EXPR4 *expr, int check_type )
 | 
						|
{
 | 
						|
  int i ;
 | 
						|
  char must_add ;
 | 
						|
  E4INFO *info ;
 | 
						|
  RELATE4 *slave_on ;
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  must_add = 0 ;
 | 
						|
 | 
						|
  /* 1st check if we must belong */
 | 
						|
  for( i = 0 ; i < expr->info_n ; i++ )
 | 
						|
  {
 | 
						|
    info = expr->info + i ;
 | 
						|
    if ( info->field_ptr )
 | 
						|
    {
 | 
						|
      if ( info->field_ptr->data == relate->data )
 | 
						|
      {
 | 
						|
        must_add = 1 ;
 | 
						|
        break ;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  relate->sort_type = relate4exact ;
 | 
						|
 | 
						|
  if ( must_add )
 | 
						|
    check_type = relate4exact ;
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( relate->relation_type == relate4scan )
 | 
						|
      check_type = relate4scan ;
 | 
						|
    else
 | 
						|
      if ( check_type != relate4scan )   /* non-scan parent must be added, so we add ourselves too, in order to save work later */
 | 
						|
        must_add = 1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  /* if a child must be added, we must be too: */
 | 
						|
  for ( slave_on = 0 ;; )
 | 
						|
  {
 | 
						|
    slave_on = (RELATE4 *)l4next( &relate->slaves, slave_on ) ;
 | 
						|
    if ( slave_on == 0 )
 | 
						|
      break ;
 | 
						|
    if ( r4data_list_build( l4, slave_on, expr, check_type ) == 1 )
 | 
						|
      must_add = 1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( must_add )
 | 
						|
    r4data_list_add( l4, relate->data, relate ) ;
 | 
						|
  else
 | 
						|
    if ( relate->relation_type == relate4scan )
 | 
						|
      relate->sort_type = relate4sort_skip ;
 | 
						|
 | 
						|
  return must_add ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4blank_set( RELATE4 *relate, char direction )
 | 
						|
{
 | 
						|
  RELATE4 *slave ;
 | 
						|
  int rc ;
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relate->is_read = 1 ;
 | 
						|
  if ( direction == 1 )
 | 
						|
  {
 | 
						|
    if ( d4go_eof( relate->data ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    rc = d4top( relate->data ) ;
 | 
						|
    if ( rc )
 | 
						|
      return rc ;
 | 
						|
    rc = d4skip( relate->data, -1L ) ;
 | 
						|
    relate->data->rec_num = -1 ;
 | 
						|
    d4blank( relate->data ) ;
 | 
						|
    relate->data->record_changed = 0 ;
 | 
						|
    if ( relate->code_base->error_code < 0 )
 | 
						|
      return -1 ;
 | 
						|
#ifndef S4SINGLE
 | 
						|
    if ( rc == r4locked || rc < 0 )
 | 
						|
      return rc ;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
  for( slave = 0 ;; )
 | 
						|
  {
 | 
						|
    slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
 | 
						|
    if ( slave == 0 )
 | 
						|
      return 0 ;
 | 
						|
    rc = relate4blank_set( slave, direction ) ;
 | 
						|
    if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4bottom( RELATE4 *relate )
 | 
						|
{
 | 
						|
  RELATION4 *relation ;
 | 
						|
  int rc, rc2 ;
 | 
						|
  long rec ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4BOTTOM ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4BOTTOM ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relation = relate->relation ;
 | 
						|
  relate = &relation->relate ;
 | 
						|
 | 
						|
  if ( relation->skip_backwards == 0 )
 | 
						|
  {
 | 
						|
    relate4sort_free( relation, 0 ) ;
 | 
						|
    relate4skip_enable( relate, 1 ) ;
 | 
						|
  }
 | 
						|
 | 
						|
  rc = relate4top( relate ) ;
 | 
						|
  if ( rc )
 | 
						|
    return rc ;
 | 
						|
 | 
						|
  relate4set_not_read( relate ) ;
 | 
						|
 | 
						|
  if ( relation->in_sort == relate4sort_done )
 | 
						|
  {
 | 
						|
    if ( relate4sort_get_record( relation, relation->sort_rec_count ) == r4eof )
 | 
						|
      return r4eof ;
 | 
						|
    relation->sort_rec_on = relation->sort_rec_count ;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    if ( d4bottom( relate->data ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
    if ( relation->expr_source )
 | 
						|
    {
 | 
						|
      rec = d4recno( relate->data ) ;
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
      if ( relate->data_tag )
 | 
						|
        while ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
 | 
						|
        {
 | 
						|
#ifdef S4HAS_DESCENDING
 | 
						|
          rc = (int)t4dskip( relate->data_tag, -1L ) ;
 | 
						|
#else
 | 
						|
          rc = (int)t4skip( relate->data_tag, -1L ) ;
 | 
						|
#endif
 | 
						|
          if ( rc != -1 )
 | 
						|
          {
 | 
						|
            if ( rc == 0 )
 | 
						|
              return r4bof ;
 | 
						|
            return rc ;
 | 
						|
          }
 | 
						|
          rec = t4recno( relate->data_tag ) ;
 | 
						|
        }
 | 
						|
      else
 | 
						|
      {
 | 
						|
#endif
 | 
						|
 | 
						|
        if ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
 | 
						|
        {
 | 
						|
          rec = d4recno( relate->data ) - f4flag_get_next_flip( &relate->set, d4recno( relate->data), -1 ) ;
 | 
						|
          if ( rec == 0 )
 | 
						|
            return r4bof ;
 | 
						|
        }
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
      }
 | 
						|
#endif
 | 
						|
      d4go( relate->data, rec ) ;
 | 
						|
    }
 | 
						|
    relate4set_not_read( relate ) ;
 | 
						|
  }
 | 
						|
 | 
						|
  rc = relate4read_rest( relate, -1 ) ;
 | 
						|
  if ( rc == relate4filter_record )
 | 
						|
    rc = relate4skip( relate, -1L ) ;
 | 
						|
 | 
						|
  if ( rc < 0 || rc == r4terminate )
 | 
						|
    return rc ;
 | 
						|
 | 
						|
  if ( relation->expr_source )
 | 
						|
  {
 | 
						|
    rc2 = log4true( &relation->log ) ;
 | 
						|
    if ( rc2 == r4terminate )
 | 
						|
      return r4terminate ;
 | 
						|
    if ( rc2 == 0 )
 | 
						|
    {
 | 
						|
      if ( relation->in_sort == relate4sort_skip )  /* must temporarily disable in order to get a matching scan if available */
 | 
						|
      {
 | 
						|
        relation->in_sort = 0 ;
 | 
						|
        rc = relate4skip( relate, -1L ) ;
 | 
						|
        relation->in_sort = relate4sort_skip ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        rc = relate4skip( relate, -1L ) ;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4build_scan_list( RELATE4 *relate, RELATION4 *relation )
 | 
						|
{
 | 
						|
  RELATE4 *relate_on ;
 | 
						|
  RELATE4LIST *ptr ;
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  for( relate_on = 0 ;; )
 | 
						|
  {
 | 
						|
    relate_on = (RELATE4 *)l4next(&relate->slaves,relate_on) ;
 | 
						|
    if ( relate_on  == 0 )
 | 
						|
      break ;
 | 
						|
    if ( relate4build_scan_list( relate_on, relation ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( relate->relation_type == relate4scan || relate == &relation->relate )
 | 
						|
  {
 | 
						|
    ptr = (RELATE4LIST *)mem4create_alloc( relate->code_base, &relation->relate_list_memory, 5, sizeof(RELATE4LIST), 5, 0 ) ;
 | 
						|
    if ( ptr == 0 )
 | 
						|
      return -1 ;
 | 
						|
    ptr->ptr = relate ;
 | 
						|
    l4add( &relation->relate_list, ptr ) ;
 | 
						|
  }
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
void S4FUNCTION relate4changed( RELATE4 *relate )
 | 
						|
{
 | 
						|
  RELATION4 *relation ;
 | 
						|
  int j ;
 | 
						|
  void *ptr ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4CHANGED ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return ;
 | 
						|
 | 
						|
  u4free( relate->scan_value ) ;
 | 
						|
  relate->scan_value = 0 ;
 | 
						|
  relation = relate->relation ;
 | 
						|
  relation->is_initialized = 0 ;
 | 
						|
  relate4sort_free( relation, 0 ) ;
 | 
						|
 | 
						|
  for( ptr = 0 ;; )
 | 
						|
  {
 | 
						|
    ptr = l4last( &relation->relate_list) ;
 | 
						|
    if ( ptr == 0 )
 | 
						|
      break ;
 | 
						|
    l4remove( &relation->relate_list, ptr ) ;
 | 
						|
    mem4free( relation->relate_list_memory, ptr ) ;
 | 
						|
  }
 | 
						|
 | 
						|
  u4free( relation->relate.set.flags ) ;
 | 
						|
  memset( (void *)&relation->relate.set, 0, sizeof( F4FLAG ) ) ;
 | 
						|
 | 
						|
  if ( relation->log.expr != 0 )
 | 
						|
  {
 | 
						|
    for( j = relation->log.expr->info_n; --j >= 0; )
 | 
						|
    {
 | 
						|
      E4INFO_REPORT *info_ptr = relation->log.info_report + j ;
 | 
						|
      if ( info_ptr->data_list != 0 )
 | 
						|
      {
 | 
						|
        u4free( (void *)info_ptr->data_list->pointers ) ;
 | 
						|
#ifdef S4DEBUG
 | 
						|
        info_ptr->data_list->pointers = 0 ;
 | 
						|
#endif
 | 
						|
        mem4free( relation->data_list_memory, info_ptr->data_list ) ;
 | 
						|
#ifdef S4DEBUG
 | 
						|
        info_ptr->data_list = 0 ;
 | 
						|
#endif
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    expr4free( relation->log.expr ) ;
 | 
						|
    relation->log.expr = 0 ;
 | 
						|
    u4free( relation->log.info_report ) ;
 | 
						|
    relation->log.info_report = 0 ;
 | 
						|
  }
 | 
						|
  relation->in_sort = 0 ;
 | 
						|
}
 | 
						|
 | 
						|
RELATE4 *S4FUNCTION relate4create_slave( RELATE4 *master, DATA4 *slave_data, char *master_expr, TAG4 *slave_tag )
 | 
						|
{
 | 
						|
  RELATION4 *relation ;
 | 
						|
  RELATE4 *slave ;
 | 
						|
  char t1, t2 ;
 | 
						|
  int failed ;
 | 
						|
 | 
						|
  if ( master == 0 )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( master->code_base, 1, E4_R4CREATE_SLAVE ) )
 | 
						|
    return (RELATE4 *) 0 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( master->code_base->error_code < 0 )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  relation = master->relation ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( slave_data == 0 || master_expr == 0 )
 | 
						|
    e4severe( e4parm, E4_R4CREATE_SLAVE ) ;
 | 
						|
 | 
						|
  /* check that the d4 doesn't belong to any existing relation */
 | 
						|
  if ( relate4lookup_relate( &relation->relate, slave_data ) != 0 )
 | 
						|
  {
 | 
						|
    e4( master->code_base, e4parm, E4_PARM_REL ) ;
 | 
						|
    return 0 ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  relate4changed( master ) ;
 | 
						|
 | 
						|
  slave = (RELATE4 *)mem4create_alloc( master->code_base, &relation->relate_memory, 5, sizeof(RELATE4), 5, 0 ) ;
 | 
						|
  if ( slave == 0 )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  relate4init_relate( slave, master->relation, slave_data, master->code_base ) ;
 | 
						|
 | 
						|
  slave->master_expr = expr4parse( master->data, master_expr ) ;
 | 
						|
  if ( slave->master_expr == 0 )
 | 
						|
  {
 | 
						|
    mem4free( relation->relate_memory, slave ) ;
 | 
						|
    return 0 ;
 | 
						|
  }
 | 
						|
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  if ( slave_tag != 0 )
 | 
						|
  {
 | 
						|
    t1 = t4type( slave_tag ) ;
 | 
						|
    t2 = expr4type( slave->master_expr ) ;
 | 
						|
    if ( t1 != t2 )   /* check if types are compatible... */
 | 
						|
    {
 | 
						|
      failed = 1 ;
 | 
						|
 | 
						|
      if ( t1 == r4date && t2 == r4date_doub )
 | 
						|
        failed = 0 ;
 | 
						|
      else
 | 
						|
      {
 | 
						|
        if ( t1 == r4date_doub && t2 == r4date )
 | 
						|
          failed = 0 ;
 | 
						|
        else
 | 
						|
        {
 | 
						|
          if ( t1 == r4num && t2 == r4num_doub )
 | 
						|
            failed = 0 ;
 | 
						|
          else
 | 
						|
            if ( t1 == r4num_doub && t2 == r4num )
 | 
						|
              failed = 0 ;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if ( failed == 1 )
 | 
						|
      {
 | 
						|
        if ( master->code_base->relate_error )
 | 
						|
          e4( master->code_base, e4relate, E4_RELATE_RCS ) ;
 | 
						|
        mem4free( relation->relate_memory, slave ) ;
 | 
						|
        return 0 ;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  slave->data_tag = slave_tag ;
 | 
						|
  slave->master = master ;
 | 
						|
 | 
						|
  l4add( &master->slaves, slave ) ;
 | 
						|
  relate4match_len( slave, -1 ) ; /* Set to maximum */
 | 
						|
 | 
						|
  return slave ;
 | 
						|
}
 | 
						|
 | 
						|
/* checks if the given dbf belongs to one of the relations in relation */
 | 
						|
int S4FUNCTION relate4dbf_in_relation( RELATE4 *relate, DATA4 *dbf )
 | 
						|
{
 | 
						|
  RELATE4 *relate_on ;
 | 
						|
 | 
						|
  relate_on = &relate->relation->relate ;
 | 
						|
  while( relate_on->master )
 | 
						|
    relate_on = relate_on->master ;
 | 
						|
 | 
						|
  do
 | 
						|
  {
 | 
						|
    if ( relate_on->data == dbf )
 | 
						|
      return 1 ;
 | 
						|
  } while( relate4next( &relate_on ) != 2 ) ;
 | 
						|
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4do( RELATE4 *relate )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4DO ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4DO ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relate4set_not_read( relate ) ;
 | 
						|
  rc = relate4read_rest( relate, 0 ) ;
 | 
						|
  if ( rc == relate4filter_record )  /* no match is an error */
 | 
						|
  {
 | 
						|
    if ( relate->code_base->relate_error )
 | 
						|
      return e4( relate->code_base, e4lookup_err, relate->data->alias ) ;
 | 
						|
    return r4terminate ;
 | 
						|
  }
 | 
						|
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4do_one( RELATE4 *relate )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4DO_ONE ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4DO_ONE ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( relate->master == 0 )   /* no master, so we must be read */
 | 
						|
    return 0 ;
 | 
						|
  relate4set_not_read( relate ) ;
 | 
						|
  rc = relate4lookup( relate, 0 ) ;
 | 
						|
  relate->is_read = relate->master->is_read ;  /* we are read if master is read */
 | 
						|
  if ( rc == relate4filter_record )  /* no match is an error */
 | 
						|
  {
 | 
						|
    if ( relate->code_base->relate_error )
 | 
						|
      return e4( relate->code_base, e4lookup_err, relate->data->alias ) ;
 | 
						|
    return r4terminate ;
 | 
						|
  }
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4eof( RELATE4 *relate )
 | 
						|
{
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4EOF ) ;
 | 
						|
 | 
						|
  if ( relate->relation->is_initialized == 0 )
 | 
						|
  {
 | 
						|
    e4( relate->code_base, e4info, E4_INFO_REL ) ;
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->relation->in_sort == relate4sort_done )
 | 
						|
    return relate->relation->sort_eof_flag ;
 | 
						|
  else
 | 
						|
    return d4eof( relate->relation->relate.data ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4error_action( RELATE4 *relate, int code )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( code != relate4blank && code != relate4skip_rec && code != relate4terminate )
 | 
						|
    e4severe( e4parm, E4_INFO_IVE ) ;
 | 
						|
#endif
 | 
						|
  rc = relate->error_action ;
 | 
						|
  relate->error_action = code ;
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4free( RELATE4 *relate, int close_files )
 | 
						|
{
 | 
						|
  int rc = 0 ;
 | 
						|
  RELATION4 *relation ;
 | 
						|
  RELATE4 *relate_on ;
 | 
						|
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4FREE ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef S4SINGLE
 | 
						|
  relate4unlock( relate ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  relate4changed( relate ) ;
 | 
						|
  relation = relate->relation ;
 | 
						|
  relate = &relation->relate ;
 | 
						|
 | 
						|
  if( close_files )
 | 
						|
    if( d4close( relate->data ) < 0 )
 | 
						|
      rc = -1 ;
 | 
						|
 | 
						|
  for( relate_on = 0 ;; )
 | 
						|
  {
 | 
						|
    relate_on = (RELATE4 *)l4last( &relate->slaves ) ;
 | 
						|
    if ( relate_on == 0 )
 | 
						|
      break ;
 | 
						|
    if( relate4free_relate( relate_on, close_files ) < 0 )
 | 
						|
      rc = -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  mem4release( relation->relate_memory ) ;
 | 
						|
  mem4release( relation->relate_list_memory ) ;
 | 
						|
  mem4release( relation->data_list_memory ) ;
 | 
						|
 | 
						|
  relate4sort_free( relation, 1 ) ;
 | 
						|
  u4free( relation->expr_source ) ;
 | 
						|
  u4free( relation ) ;
 | 
						|
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4free_relate( RELATE4 *relate, int close_files )
 | 
						|
{
 | 
						|
  int rc = 0 ;
 | 
						|
  RELATE4 *relate_on ;
 | 
						|
  if ( relate->master == 0 )
 | 
						|
    return relate4free( relate, close_files ) ;
 | 
						|
 | 
						|
  relate4changed( relate ) ;
 | 
						|
 | 
						|
  if( close_files )
 | 
						|
    if( d4close( relate->data ) < 0 )
 | 
						|
      rc = -1 ;
 | 
						|
 | 
						|
  for( ;; )
 | 
						|
  {
 | 
						|
    relate_on = (RELATE4 *)l4last( &relate->slaves) ;
 | 
						|
    if ( relate_on == 0 )
 | 
						|
      break ;
 | 
						|
    if( relate4free_relate( relate_on, close_files ) < 0 )
 | 
						|
      rc = -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  expr4free( relate->master_expr ) ;
 | 
						|
  u4free( relate->scan_value ) ;
 | 
						|
  relate->scan_value = 0 ;
 | 
						|
  u4free( relate->set.flags ) ;
 | 
						|
  relate->set.flags = 0 ;
 | 
						|
 | 
						|
  l4remove( &relate->master->slaves, relate ) ;
 | 
						|
  mem4free( relate->relation->relate_memory, relate ) ;
 | 
						|
  relate = 0 ;
 | 
						|
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
RELATE4 *S4FUNCTION relate4init( DATA4 *master )
 | 
						|
{
 | 
						|
  RELATION4 *relation ;
 | 
						|
  CODE4 *code_base ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( master->code_base, 1, E4_R4INIT ) )
 | 
						|
    return (RELATE4 *) 0 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( master == 0 )
 | 
						|
    e4severe( e4parm, E4_R4INIT ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  code_base = master->code_base ;
 | 
						|
  if ( code_base->error_code < 0 )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  relation = (RELATION4 *)u4alloc_er( code_base, sizeof( RELATION4 ) ) ;
 | 
						|
  if ( relation == 0 )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  relate4init_relate( &relation->relate, relation, master, code_base ) ;
 | 
						|
  relation->log.relation = relation ;
 | 
						|
  relation->log.code_base = code_base ;
 | 
						|
  relation->sort.file.hand = -1 ;
 | 
						|
  relation->sorted_file.hand = -1 ;
 | 
						|
 | 
						|
  return &relation->relate ;
 | 
						|
}
 | 
						|
 | 
						|
void S4FUNCTION relate4init_relate( RELATE4 *relate, RELATION4 *relation, DATA4 *data, CODE4 *code_ptr )
 | 
						|
{
 | 
						|
  relate->code_base = code_ptr ;
 | 
						|
  relate->relation_type = relate4exact ;
 | 
						|
  relate->data = data ;
 | 
						|
  relate->error_action  = relate4blank ;
 | 
						|
  relate->relation = relation ;
 | 
						|
  relate->data->count = d4reccount( relate->data ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4lock( RELATE4 *relate )
 | 
						|
{
 | 
						|
#ifdef S4SINGLE
 | 
						|
  return 0 ;
 | 
						|
#else
 | 
						|
  CODE4 *code_base ;
 | 
						|
  int rc, old_attempts, count ;
 | 
						|
  DATA4 *data_on ;
 | 
						|
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4LOCK ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  code_base = relate->code_base ;
 | 
						|
  if ( code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relate->relation->locked = 1 ;
 | 
						|
 | 
						|
  count = old_attempts = code_base->lock_attempts ;  /* take care of wait here */
 | 
						|
  code_base->lock_attempts = 1 ;
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  {
 | 
						|
    rc = 0 ;
 | 
						|
    for ( data_on = (DATA4 *)l4first( &code_base->data_list) ; data_on ; data_on = (DATA4 *)l4next( &code_base->data_list, data_on ) )
 | 
						|
      if ( relate4dbf_in_relation( relate, data_on ) )
 | 
						|
      {
 | 
						|
        rc = d4lock_all( data_on ) ;
 | 
						|
        if ( rc != 0 )
 | 
						|
          break ;
 | 
						|
      }
 | 
						|
 | 
						|
    if ( rc != r4locked )
 | 
						|
      break ;
 | 
						|
 | 
						|
    relate4unlock( relate ) ;
 | 
						|
    if ( count == 0 )
 | 
						|
      break ;
 | 
						|
 | 
						|
    if ( count > 0 )
 | 
						|
      count-- ;
 | 
						|
 | 
						|
#ifdef S4TEMP
 | 
						|
    if ( d4display_quit( &display ) )
 | 
						|
      e4severe( e4result, E4_RESULT_EXI ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
    u4delay_sec() ;   /* wait a second */
 | 
						|
  }
 | 
						|
 | 
						|
  code_base->lock_attempts = old_attempts ;
 | 
						|
  if ( code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  return rc ;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/* direction : -1 = look backwards, 0 = lookup only, 1 = look forwards */
 | 
						|
int S4FUNCTION relate4lookup( RELATE4 *relate, char direction )
 | 
						|
{
 | 
						|
  int rc, len ;
 | 
						|
  long recno ;
 | 
						|
  char *ptr ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4LOOKUP ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( direction != 0 && relate->relation->is_initialized == 0 )
 | 
						|
  {
 | 
						|
#ifdef S4DEBUG
 | 
						|
    e4( relate->code_base, e4info, E4_INFO_REL ) ;
 | 
						|
#endif
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  relate->is_read = 1 ;
 | 
						|
  if ( relate->master == 0 )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  d4tag_select( relate->data, relate->data_tag ) ;
 | 
						|
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  if ( relate->data_tag == 0 )
 | 
						|
  {
 | 
						|
#endif
 | 
						|
    recno = (long)expr4double( relate->master_expr ) ;
 | 
						|
    if ( relate->code_base->error_code < 0 )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
    if ( direction != 0 )
 | 
						|
      if ( f4flag_is_set_flip( &relate->set, recno ) == 0 )
 | 
						|
        return relate4filter_record ;
 | 
						|
 | 
						|
    rc = d4go( relate->data, recno ) ;
 | 
						|
    if ( rc < 0 )
 | 
						|
      return -1 ;
 | 
						|
    if ( rc != r4entry )  /* if not error, then return */
 | 
						|
      return 0 ;
 | 
						|
    if ( relate->relation_type == relate4approx )
 | 
						|
    {
 | 
						|
      d4go_eof( relate->data ) ;
 | 
						|
      return 0 ;
 | 
						|
    }
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    len = expr4key( relate->master_expr, &ptr ) ;
 | 
						|
    if ( len < 0 )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
    len = (len < relate->match_len) ? len : relate->match_len ;   /* min of len and match len */
 | 
						|
 | 
						|
    if ( relate->relation_type == relate4scan )
 | 
						|
    {
 | 
						|
#ifdef S4DEBUG
 | 
						|
      if ( relate->master == 0 )
 | 
						|
        e4severe( e4info, E4_RELATE_MEN ) ;
 | 
						|
#endif
 | 
						|
      if ( relate->master->scan_value == 0 )
 | 
						|
      {
 | 
						|
        relate->master->scan_value_len = len ;
 | 
						|
        relate->master->scan_value = (char *)u4alloc_er( relate->code_base, len ) ;
 | 
						|
        if ( relate->master->scan_value == 0 )
 | 
						|
          return -1 ;
 | 
						|
      }
 | 
						|
      memcpy( relate->master->scan_value, ptr, len ) ;
 | 
						|
    }
 | 
						|
 | 
						|
    rc = t4seek( relate->data_tag, ptr, len ) ;
 | 
						|
    if ( rc < 0 )
 | 
						|
      return -1 ;
 | 
						|
    if ( relate->relation_type == relate4approx || rc == 0 )
 | 
						|
    {
 | 
						|
      if ( t4eof( relate->data_tag) )
 | 
						|
      {
 | 
						|
        d4go_eof( relate->data ) ;
 | 
						|
        return 0 ;
 | 
						|
      }
 | 
						|
 | 
						|
      if ( (int)direction < 0 && rc == 0 && relate->relation_type == relate4scan )  /* look for last one */
 | 
						|
        for( ;; )
 | 
						|
        {
 | 
						|
#ifdef S4HAS_DESCENDING
 | 
						|
          if ( !t4dskip( relate->data_tag, 1L ) )
 | 
						|
#else
 | 
						|
            if ( !t4skip( relate->data_tag, 1L ) )
 | 
						|
#endif
 | 
						|
              break ;
 | 
						|
          if ( u4memcmp( t4key_data( relate->data_tag )->value, ptr, len ) )
 | 
						|
          {
 | 
						|
#ifdef S4HAS_DESCENDING
 | 
						|
            t4dskip( relate->data_tag, -1L ) ;
 | 
						|
#else
 | 
						|
            t4skip( relate->data_tag, -1L ) ;
 | 
						|
#endif
 | 
						|
            break ;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
      recno = t4key_data( relate->data_tag )->num ;
 | 
						|
      if ( direction != 0 )
 | 
						|
        if ( f4flag_is_set_flip( &relate->set, recno ) == 0 )
 | 
						|
          return relate4filter_record ;
 | 
						|
      if ( d4go( relate->data, recno ) < 0 )
 | 
						|
        return -1 ;
 | 
						|
      return 0 ;
 | 
						|
    }
 | 
						|
    else
 | 
						|
      recno = t4key_data( relate->data_tag )->num ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4CHANGE_BACK
 | 
						|
  if ( relate->relation_type == relate4scan )  /* no matching records, so filter */
 | 
						|
    return relate4filter_record ;
 | 
						|
#endif
 | 
						|
 | 
						|
  switch( relate->error_action )  /* if got here, must be error condition */
 | 
						|
  {
 | 
						|
  case relate4blank:
 | 
						|
    if ( d4go_eof( relate->data ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
    if ( direction != 0 )
 | 
						|
      if ( f4flag_is_set_flip( &relate->set, recno ) == 0 )
 | 
						|
        return relate4filter_record ;
 | 
						|
    return 0 ;
 | 
						|
  case relate4skip_rec:
 | 
						|
    return relate4filter_record ;
 | 
						|
  case relate4terminate:
 | 
						|
    if ( relate->code_base->relate_error )
 | 
						|
      return e4( relate->code_base, e4lookup_err, relate->data->alias ) ;
 | 
						|
    return r4terminate ;
 | 
						|
  default:
 | 
						|
#ifdef S4DEBUG
 | 
						|
    /* should never get this far */
 | 
						|
    e4severe( e4info, E4_RELATE_EAI ) ;
 | 
						|
#endif
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
RELATE4 *S4FUNCTION relate4lookup_relate( RELATE4 *relate, DATA4 *d4 )
 | 
						|
{
 | 
						|
  RELATE4 *relate_return, *relate_on ;
 | 
						|
 | 
						|
  if ( relate->data == d4 )
 | 
						|
    return relate ;
 | 
						|
  for( relate_on = 0 ;; )
 | 
						|
  {
 | 
						|
    relate_on = (RELATE4 *)l4next( &relate->slaves, relate_on) ;
 | 
						|
    if ( relate_on == 0 )
 | 
						|
      return 0 ;
 | 
						|
    relate_return = relate4lookup_relate( relate_on, d4 ) ;
 | 
						|
    if ( relate_return )
 | 
						|
      return relate_return ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int S4FUNCTION relate4match_len( RELATE4 *relate, int match_len )
 | 
						|
{
 | 
						|
  int len ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4MATCH_LEN ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  len = expr4key_len( relate->master_expr ) ;
 | 
						|
 | 
						|
#ifdef S4CLIPPER
 | 
						|
  if ( match_len <= 0 )
 | 
						|
    match_len = len ;
 | 
						|
#else
 | 
						|
  if ( match_len <= 0 )
 | 
						|
  {
 | 
						|
    relate->match_len = len ;
 | 
						|
    return match_len ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
#ifndef S4CLIPPER
 | 
						|
  if ( relate->data_tag )
 | 
						|
    if( expr4type(  relate->data_tag->expr ) != r4str)  /* make sure r4str only */
 | 
						|
    {
 | 
						|
#ifdef S4DEBUG
 | 
						|
      e4( relate->code_base, e4relate, E4_RELATE_REL ) ;
 | 
						|
#endif
 | 
						|
      return -1 ;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( match_len >= len )
 | 
						|
    match_len = len ;
 | 
						|
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  if ( relate->data_tag )
 | 
						|
  {
 | 
						|
    len = expr4key_len( relate->data_tag->expr ) ;
 | 
						|
    if ( match_len >= len )
 | 
						|
      match_len = len ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  relate->match_len = match_len ;
 | 
						|
  relate4changed( relate ) ;
 | 
						|
  return match_len ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4next( RELATE4 **ptr_ptr )
 | 
						|
{
 | 
						|
  RELATE4 *cur ;
 | 
						|
  void *next_link ;
 | 
						|
  int rc ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( ptr_ptr == 0 )
 | 
						|
    e4severe( e4parm, E4_R4NEXT ) ;
 | 
						|
  if ( *ptr_ptr == 0 )
 | 
						|
    e4severe( e4parm, E4_R4NEXT ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  cur = *ptr_ptr ;
 | 
						|
  rc = 1 ;
 | 
						|
 | 
						|
  if ( cur->slaves.n_link > 0 )
 | 
						|
  {
 | 
						|
    *ptr_ptr = (RELATE4 *)l4first( &cur->slaves ) ;
 | 
						|
    return 1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  for(;;)
 | 
						|
  {
 | 
						|
    rc -- ;
 | 
						|
    if ( cur->master == 0 )
 | 
						|
    {
 | 
						|
      *ptr_ptr = 0 ;
 | 
						|
      return 2 ;
 | 
						|
    }
 | 
						|
 | 
						|
    next_link = l4next( &cur->master->slaves, cur ) ;
 | 
						|
    if ( next_link )
 | 
						|
    {
 | 
						|
      *ptr_ptr = (RELATE4 *)next_link ;
 | 
						|
      return rc ;
 | 
						|
    }
 | 
						|
 | 
						|
    cur = cur->master ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4next_record_in_scan( RELATE4 *relate )
 | 
						|
{
 | 
						|
  long next_rec ;
 | 
						|
  int  rc, save_code, len ;
 | 
						|
  B4KEY_DATA *key ;
 | 
						|
  char *ptr ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4NEXT_RIS ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( relate->relation->is_initialized == 0 )
 | 
						|
  {
 | 
						|
#ifdef S4DEBUG
 | 
						|
    e4( relate->code_base, e4info, E4_INFO_REL ) ;
 | 
						|
#endif
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( relate->relation->in_sort == relate4sort_skip && relate->sort_type == relate4sort_skip )
 | 
						|
    return r4eof ;
 | 
						|
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  if ( relate->data_tag == 0 )
 | 
						|
  {
 | 
						|
#endif
 | 
						|
    if ( d4bof( relate->data ) )
 | 
						|
      next_rec = 1 ;
 | 
						|
    else
 | 
						|
      next_rec = d4recno( relate->data ) + 1 ;
 | 
						|
    next_rec += f4flag_get_next_flip( &relate->set, next_rec, 1 ) ;
 | 
						|
    if ( next_rec > relate->data->count )
 | 
						|
    {
 | 
						|
      relate->data->count = d4reccount( relate->data ) ;
 | 
						|
      if ( next_rec > relate->data->count )
 | 
						|
        return r4eof ;
 | 
						|
    }
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  }
 | 
						|
  else
 | 
						|
    for(;;)
 | 
						|
    {
 | 
						|
      if ( d4bof( relate->data ) )
 | 
						|
      {
 | 
						|
        if ( relate->data->num_recs == 0 )
 | 
						|
          return r4eof ;
 | 
						|
        len = expr4key( relate->master_expr, &ptr ) ;
 | 
						|
        if ( len < 0 )
 | 
						|
          return -1 ;
 | 
						|
 | 
						|
        len = (len < relate->match_len) ? len : relate->match_len ;   /* min of len and match len */
 | 
						|
 | 
						|
        rc = (int)t4seek( relate->data_tag, relate->master->scan_value, len ) ;
 | 
						|
        if ( rc < 0 )
 | 
						|
          return -1 ;
 | 
						|
        if ( rc == 0 )
 | 
						|
          rc = 1 ;
 | 
						|
        else
 | 
						|
          rc = 0 ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
#ifdef S4HAS_DESCENDING
 | 
						|
        rc = (int)t4dskip( relate->data_tag, 1 ) ;
 | 
						|
#else
 | 
						|
      rc = (int)t4skip( relate->data_tag, 1 ) ;
 | 
						|
#endif
 | 
						|
      if ( rc < 0 )
 | 
						|
        return -1 ;
 | 
						|
      if ( rc != 1 )
 | 
						|
        return r4eof ;
 | 
						|
 | 
						|
      key = t4key_data( relate->data_tag) ;
 | 
						|
      next_rec = key->num ;
 | 
						|
 | 
						|
      if ( relate->master )
 | 
						|
        if ( u4memcmp( key->value, relate->master->scan_value, relate->master->scan_value_len ) != 0 )
 | 
						|
          return r4eof ;
 | 
						|
 | 
						|
      if ( f4flag_is_set_flip( &relate->set, next_rec ) )
 | 
						|
        break ;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
  save_code = relate->code_base->go_error ;
 | 
						|
  relate->code_base->go_error = 0 ;
 | 
						|
  rc = d4go( relate->data, next_rec ) ;
 | 
						|
  relate->code_base->go_error = save_code ;
 | 
						|
  if ( rc < 0 )
 | 
						|
    return -1 ;
 | 
						|
  if ( rc == r4entry )
 | 
						|
    return r4eof ;
 | 
						|
  relate->is_read = 1 ;   /* we have updated this one */
 | 
						|
  return relate4skipped ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4next_scan_record( RELATION4 *relation )
 | 
						|
{
 | 
						|
  RELATE4 *relate ;
 | 
						|
  int rc, rc2 ;
 | 
						|
 | 
						|
  if ( relation->relate.code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relation->relate_list.selected = (void *)l4first( &relation->relate_list ) ;
 | 
						|
  for(;;)
 | 
						|
  {
 | 
						|
    relate = ((RELATE4LIST *)relation->relate_list.selected)->ptr ;
 | 
						|
    relate4set_not_read( relate ) ;  /* This data file & its slaves */
 | 
						|
    if ( relation->in_sort == relate4sort_done )
 | 
						|
      if ( r4data_list_find( &relation->sort_data_list, relate ) )
 | 
						|
        return relate4sort_next_record( relation ) ;
 | 
						|
 | 
						|
    rc = relate4next_record_in_scan( relate ) ;
 | 
						|
    if ( rc == relate4skipped )
 | 
						|
      return 0 ;
 | 
						|
    if ( rc < 0 )
 | 
						|
      return -1 ;
 | 
						|
    rc2 = relate4blank_set( relate, (char)1 ) ;
 | 
						|
    if ( rc2 == r4locked || rc2 < 0 )  /* error or locked */
 | 
						|
      return rc2 ;
 | 
						|
    if ( relate->master == 0 )
 | 
						|
      if ( d4eof( relate->data ) )
 | 
						|
        return r4eof ;
 | 
						|
    relation->relate_list.selected = l4next( &relation->relate_list, relation->relate_list.selected);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4prev_record_in_scan( RELATE4 *relate )
 | 
						|
{
 | 
						|
  long next_rec ;
 | 
						|
  int  rc, save_code ;
 | 
						|
  B4KEY_DATA *key ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4PREV_RIS ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->relation->is_initialized == 0 )
 | 
						|
  {
 | 
						|
#ifdef S4DEBUG
 | 
						|
    e4( relate->code_base, e4info, E4_INFO_REL ) ;
 | 
						|
#endif
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  if ( relate->data_tag == 0 )
 | 
						|
  {
 | 
						|
#endif
 | 
						|
    next_rec = d4recno( relate->data ) - 1 ;
 | 
						|
    next_rec -= f4flag_get_next_flip( &relate->set, next_rec, -1 ) ;
 | 
						|
    if ( next_rec <= 0 )
 | 
						|
      return r4bof ;
 | 
						|
    if ( next_rec > relate->data->count )
 | 
						|
    {
 | 
						|
      relate->data->count = d4reccount( relate->data ) ;
 | 
						|
      if ( next_rec > relate->data->count )
 | 
						|
        return r4eof ;
 | 
						|
    }
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
  }
 | 
						|
  else
 | 
						|
    for(;;)
 | 
						|
    {
 | 
						|
      if ( relate4eof( relate ) )   /* if eof in relate, just leave on last tag entry */
 | 
						|
        rc = t4eof( relate->data_tag ) ? 0 : -1 ;
 | 
						|
      else
 | 
						|
      {
 | 
						|
        if ( d4eof( relate->data ) == 1 )
 | 
						|
        {
 | 
						|
          if ( relate->data->num_recs == 0 )
 | 
						|
            return r4bof ;
 | 
						|
          rc = (int)t4bottom( relate->data_tag ) ;
 | 
						|
          if ( rc < 0 )
 | 
						|
            return -1 ;
 | 
						|
          if ( rc == 0 )
 | 
						|
            rc = -1 ;
 | 
						|
          else
 | 
						|
            rc = 0 ;
 | 
						|
        }
 | 
						|
        else
 | 
						|
#ifdef S4HAS_DESCENDING
 | 
						|
          rc = (int)t4dskip( relate->data_tag, -1L ) ;
 | 
						|
#else
 | 
						|
        rc = (int)t4skip( relate->data_tag, -1L ) ;
 | 
						|
#endif
 | 
						|
      }
 | 
						|
      if ( rc > 0 )
 | 
						|
        return -1 ;
 | 
						|
      if ( rc != -1L )
 | 
						|
        return r4bof ;
 | 
						|
 | 
						|
      key = t4key_data( relate->data_tag) ;
 | 
						|
      next_rec = key->num ;
 | 
						|
 | 
						|
      if ( relate->master )
 | 
						|
        if ( u4memcmp( key->value, relate->master->scan_value, relate->master->scan_value_len ) != 0 )
 | 
						|
          return r4bof ;
 | 
						|
 | 
						|
      if ( f4flag_is_set_flip( &relate->set, next_rec ) )
 | 
						|
        break ;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
  save_code = relate->code_base->go_error ;
 | 
						|
  relate->code_base->go_error = 0 ;
 | 
						|
  rc = d4go( relate->data, next_rec ) ;
 | 
						|
  relate->code_base->go_error = save_code ;
 | 
						|
  if ( rc < 0 )
 | 
						|
    return -1 ;
 | 
						|
  if ( rc == r4entry )
 | 
						|
    return r4eof ;
 | 
						|
  relate->is_read = 1 ;   /* we have updated this one */
 | 
						|
  return relate4skipped ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4prev_scan_record( RELATION4 *relation )
 | 
						|
{
 | 
						|
  RELATE4 *relate ;
 | 
						|
  int rc, rc2 ;
 | 
						|
 | 
						|
  if ( relation->relate.code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relate = ((RELATE4LIST *)l4last( &relation->relate_list ))->ptr ;
 | 
						|
  if ( relate4eof( relate ) )  /* at eof means we must read this record */
 | 
						|
    if ( relation->in_sort != relate4sort_done )
 | 
						|
    {
 | 
						|
      rc2 = relate->code_base->read_lock ;  /* suspend the potential lock call... */
 | 
						|
      relate->code_base->read_lock = 0 ;
 | 
						|
      rc = relate4bottom( relate ) ;
 | 
						|
      relate->code_base->read_lock = rc2 ;
 | 
						|
      if ( rc == r4eof )   /* no records, so can't skip back */
 | 
						|
        return r4bof ;
 | 
						|
else
 | 
						|
  return rc ;
 | 
						|
    }
 | 
						|
 | 
						|
  relation->relate_list.selected = (void *)l4first( &relation->relate_list ) ;
 | 
						|
  for(;;)
 | 
						|
  {
 | 
						|
    relate = ((RELATE4LIST *)relation->relate_list.selected)->ptr ;
 | 
						|
    relate4set_not_read( relate ) ;  /* This data file & its slaves */
 | 
						|
    if ( relation->in_sort == relate4sort_done )
 | 
						|
      if ( r4data_list_find( &relation->sort_data_list, relate ) )
 | 
						|
        return relate4sort_prev_record( relation ) ;
 | 
						|
 | 
						|
    rc = relate4prev_record_in_scan(relate) ;
 | 
						|
    if ( rc == relate4skipped )
 | 
						|
    {
 | 
						|
      if ( relate4eof( relate ) )
 | 
						|
      {
 | 
						|
        if ( relate->relation->in_sort == relate4sort_done && relate->relation->sort_eof_flag == 1 )
 | 
						|
        {
 | 
						|
          relation->sort_rec_on-- ;  /* move off eof on sort part */
 | 
						|
          relate->relation->sort_eof_flag = 0 ;
 | 
						|
        }
 | 
						|
        else
 | 
						|
          d4go( relate->relation->relate.data, d4reccount( relate->relation->relate.data ) ) ;
 | 
						|
      }
 | 
						|
      return 0 ;
 | 
						|
    }
 | 
						|
    if ( rc < 0 )
 | 
						|
      return -1 ;
 | 
						|
    rc2 = relate4blank_set( relate, (char)-1 ) ;
 | 
						|
    if ( rc2 == r4locked || rc2 < 0  )  /* error or locked */
 | 
						|
      return rc2 ;
 | 
						|
    if ( relate->master == 0 )
 | 
						|
    {
 | 
						|
      if ( d4bof(relate->data) )
 | 
						|
        return r4bof ;
 | 
						|
      if ( d4eof(relate->data) )
 | 
						|
        return r4eof ;
 | 
						|
    }
 | 
						|
    relation->relate_list.selected = l4next( &relation->relate_list, relation->relate_list.selected);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4query_set( RELATE4 *relate, char *expr )
 | 
						|
{
 | 
						|
  int len ;
 | 
						|
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4QUERY_SET ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relate4changed( relate ) ;
 | 
						|
  u4free( relate->relation->expr_source ) ;
 | 
						|
  relate->relation->expr_source = 0 ;
 | 
						|
  if ( expr == 0 )
 | 
						|
    return 0 ;
 | 
						|
  if ( expr[0] == 0 )
 | 
						|
    return 0 ;
 | 
						|
  len = strlen( expr ) + 1 ;
 | 
						|
  relate->relation->expr_source = (char *)u4alloc_er( relate->code_base, len ) ;
 | 
						|
  if ( relate->relation->expr_source == 0 )
 | 
						|
    return -1 ;
 | 
						|
  memcpy( relate->relation->expr_source, expr, len ) ;
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4read_in( RELATE4 *relate )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
  if ( relate->is_read )
 | 
						|
    return 0 ;
 | 
						|
  if ( relate->master )
 | 
						|
    if ( relate->master->is_read == 0 )
 | 
						|
    {
 | 
						|
      rc = relate4read_in( relate->master ) ;
 | 
						|
      if ( rc == relate4filter_record || rc == r4terminate )
 | 
						|
        return rc ;
 | 
						|
    }
 | 
						|
 | 
						|
  return relate4lookup( relate, 1 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4read_rest( RELATE4 *relate, char direction )
 | 
						|
{
 | 
						|
  RELATE4 *slave ;
 | 
						|
  int rc ;
 | 
						|
  int scan_done ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4READ_REST ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1;
 | 
						|
 | 
						|
  if ( relate->is_read == 0 )
 | 
						|
  {
 | 
						|
    rc = relate4lookup( relate, direction );
 | 
						|
    if ( rc < 0 || rc == relate4filter_record || rc == r4terminate )
 | 
						|
      return rc ;
 | 
						|
  }
 | 
						|
 | 
						|
  scan_done = 0 ;
 | 
						|
  for( slave = 0 ;; )
 | 
						|
  {
 | 
						|
    slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
 | 
						|
    if ( slave == 0 )
 | 
						|
      return 0 ;
 | 
						|
    if ( slave->relation_type == relate4scan && scan_done == 1 )
 | 
						|
    {
 | 
						|
      relate4blank_set( slave, (char)(1 - direction) ) ;
 | 
						|
      slave->is_read = 1 ;
 | 
						|
      rc = relate4read_rest( slave, direction ) ;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      rc = relate4read_rest( slave, direction ) ;
 | 
						|
      if ( slave->relation_type == relate4scan && rc == 0 )
 | 
						|
        if ( !d4eof( slave->data ) )
 | 
						|
          scan_done = 1 ;
 | 
						|
    }
 | 
						|
    if ( rc < 0 || rc == relate4filter_record || rc == r4terminate )
 | 
						|
      return rc ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void S4FUNCTION relate4set_not_read( RELATE4 *relate )
 | 
						|
{
 | 
						|
  RELATE4 *slave_on ;
 | 
						|
  if ( relate->is_read )
 | 
						|
  {
 | 
						|
    relate->is_read = 0 ;
 | 
						|
    for( slave_on = 0 ;; )
 | 
						|
    {
 | 
						|
      slave_on = (RELATE4 *)l4next(&relate->slaves,slave_on) ;
 | 
						|
      if ( slave_on == 0 )
 | 
						|
        return ;
 | 
						|
      relate4set_not_read( slave_on ) ;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4skip( RELATE4 *relate, long num_skip )
 | 
						|
{
 | 
						|
  int rc, sort_status, rc2 ;
 | 
						|
#ifdef S4UNIX
 | 
						|
  int sign ;
 | 
						|
#else
 | 
						|
  signed char sign ;
 | 
						|
#endif
 | 
						|
  RELATION4 *relation ;
 | 
						|
#ifdef S4REPORT
 | 
						|
#ifdef S4WINDOWS
 | 
						|
  char countstring[22];
 | 
						|
  static long int scanreccount = 0, selectreccount = 0, sortreccount = 0;
 | 
						|
  HWND statwin;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4SKIP ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4SKIP ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( relate->relation->is_initialized == 0 )
 | 
						|
  {
 | 
						|
#ifdef S4DEBUG
 | 
						|
    e4( relate->code_base, e4info, E4_INFO_REL ) ;
 | 
						|
#endif
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  relation = relate->relation ;
 | 
						|
  relate = &relation->relate ;
 | 
						|
 | 
						|
  if ( num_skip < 0 )
 | 
						|
  {
 | 
						|
    if ( relation->skip_backwards == 0 )
 | 
						|
    {
 | 
						|
#ifdef S4DEBUG
 | 
						|
      e4describe( relate->code_base, e4info, E4_R4SKIP, E4_INFO_BAC, (char *)0 ) ;
 | 
						|
#endif
 | 
						|
      return -1 ;
 | 
						|
    }
 | 
						|
    sign = -1 ;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    sign = 1 ;
 | 
						|
 | 
						|
  sort_status = 0 ;
 | 
						|
  rc = 0 ;
 | 
						|
  for( ; num_skip ; )
 | 
						|
  {
 | 
						|
 | 
						|
#ifdef S4REPORT
 | 
						|
#ifdef S4WINDOWS
 | 
						|
    if(GetWindowWord(relate->code_base->hWnd,8) == 666)
 | 
						|
      statwin = relate->code_base->hWnd;
 | 
						|
 | 
						|
    if( statwin )
 | 
						|
    {
 | 
						|
      if(GetWindowWord(statwin,6)==0)
 | 
						|
      {
 | 
						|
        SetWindowWord(statwin,6,1);
 | 
						|
        scanreccount = sortreccount = selectreccount = 0;
 | 
						|
      }
 | 
						|
 | 
						|
      scanreccount++;
 | 
						|
      if( scanreccount < 20 || (scanreccount % 20) == 0 )
 | 
						|
      {
 | 
						|
        c4ltoa45(scanreccount,countstring,sizeof(countstring)-1);
 | 
						|
        countstring[21] = 0;
 | 
						|
        SendMessage((HWND)GetWindowWord(statwin,0),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
 | 
						|
      }
 | 
						|
    }
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
    if ( sign > 0 )
 | 
						|
    {
 | 
						|
      rc = relate4next_scan_record( relation ) ;
 | 
						|
      if ( rc == r4eof )
 | 
						|
        break ;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      rc = relate4prev_scan_record( relation ) ;
 | 
						|
      if ( rc == r4bof )
 | 
						|
        break ;
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef S4SINGLE
 | 
						|
    if ( rc < 0 )
 | 
						|
#else
 | 
						|
      if ( rc < 0 || rc == r4locked )
 | 
						|
#endif
 | 
						|
        break ;
 | 
						|
 | 
						|
    rc = relate4read_rest( relate, sign ) ;
 | 
						|
    if ( rc == relate4filter_record )
 | 
						|
      continue ;
 | 
						|
 | 
						|
    if ( rc < 0 || rc == r4terminate )
 | 
						|
      break ;
 | 
						|
 | 
						|
    if ( relation->expr_source )
 | 
						|
    {
 | 
						|
      rc2 = log4true(&relation->log ) ;
 | 
						|
      if ( rc2 == r4terminate )
 | 
						|
      {
 | 
						|
        rc = r4terminate ;
 | 
						|
        break ;
 | 
						|
      }
 | 
						|
      if ( rc2 == 0 )
 | 
						|
      {
 | 
						|
        if ( relation->in_sort == relate4sort_skip )  /* must temporarily disable in order to get a matching scan if available */
 | 
						|
        {
 | 
						|
          sort_status = 1 ;
 | 
						|
          relation->in_sort = 0 ;
 | 
						|
        }
 | 
						|
        continue ;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    num_skip -= sign ;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef S4WINDOWS
 | 
						|
#ifdef S4REPORT
 | 
						|
  if(GetWindowWord(relate->code_base->hWnd,8) == 666)
 | 
						|
    statwin = relate->code_base->hWnd;
 | 
						|
 | 
						|
  if( statwin )
 | 
						|
  {
 | 
						|
    selectreccount++;
 | 
						|
    if(selectreccount < 20 || (selectreccount % 20) == 0)
 | 
						|
    {
 | 
						|
      c4ltoa45(selectreccount,countstring,sizeof(countstring)-1);
 | 
						|
      countstring[21] = 0;
 | 
						|
      SendMessage((HWND)GetWindowWord(statwin,2),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
 | 
						|
    }
 | 
						|
    if(relate->relation->in_sort)
 | 
						|
    {
 | 
						|
      sortreccount++;
 | 
						|
      if( sortreccount < 20 || (sortreccount % 20) == 0)
 | 
						|
      {
 | 
						|
        c4ltoa45(sortreccount,countstring,sizeof(countstring)-1);
 | 
						|
        countstring[21] = 0;
 | 
						|
        SendMessage((HWND)GetWindowWord(statwin,4),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( sort_status == 1 )
 | 
						|
    relation->in_sort = relate4sort_skip ;
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4skip_enable( RELATE4 *relate, int do_enable )
 | 
						|
{
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( relate->relation->skip_backwards != (char) do_enable )
 | 
						|
  {
 | 
						|
    relate->relation->skip_backwards = (char) do_enable ;
 | 
						|
    relate4changed( relate ) ;
 | 
						|
  }
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4sort( RELATE4 *relate )
 | 
						|
{
 | 
						|
  EXPR4 *sort_expr ;
 | 
						|
  int rc, i, len ;
 | 
						|
  long j, zero = 0L ;
 | 
						|
  char n_dbf, *sort_key ;
 | 
						|
  R4DATA_LIST *r4data ;
 | 
						|
  RELATION4 *relation ;
 | 
						|
  CODE4 *code_base ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4SORT ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  code_base = relate->code_base ;
 | 
						|
  if ( code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relation = relate->relation ;
 | 
						|
  relate = &relation->relate ;
 | 
						|
  rc = 0 ;
 | 
						|
  sort_expr = expr4parse( relate->data, relation->sort_source ) ;
 | 
						|
 | 
						|
  relation->in_sort = relate4sort_skip ;
 | 
						|
  relation->sort_done_flag = 0 ;
 | 
						|
 | 
						|
  rc = relate4top( relate ) ;
 | 
						|
  if ( rc )   /* no records satisfy the relate, or error */
 | 
						|
  {
 | 
						|
    expr4free( sort_expr ) ;
 | 
						|
    return rc ;
 | 
						|
  }
 | 
						|
 | 
						|
  len = expr4key( sort_expr, &sort_key ) ;
 | 
						|
  if ( len <= 0 )
 | 
						|
  {
 | 
						|
    expr4free( sort_expr ) ;
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relation->sort_data_list.n_link != 0 )
 | 
						|
    e4severe( e4parm, E4_PARM_NFD ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( r4data_list_build( &relation->sort_data_list, relate, sort_expr, relate4exact ) < 0 )
 | 
						|
  {
 | 
						|
    expr4free( sort_expr ) ;
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( r4data_list_massage( &relation->sort_data_list ) < 0 )
 | 
						|
  {
 | 
						|
    expr4free( sort_expr ) ;
 | 
						|
    return -1 ;
 | 
						|
  }
 | 
						|
 | 
						|
  n_dbf = (char) relation->sort_data_list.n_link ;
 | 
						|
 | 
						|
  relation->sort_other_len = (unsigned)n_dbf * sizeof( long ) ;
 | 
						|
  relation->other_data = (char *)u4alloc( relation->sort_other_len ) ;
 | 
						|
  if ( relation->other_data == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  rc = sort4init_free( &relation->sort, code_base, len, relation->sort_other_len, relate ) ;
 | 
						|
  if ( rc )
 | 
						|
  {
 | 
						|
    expr4free( sort_expr ) ;
 | 
						|
    return rc ;
 | 
						|
  }
 | 
						|
 | 
						|
#ifndef S4FOX
 | 
						|
#ifndef S4CLIPPER
 | 
						|
  switch( expr4type( sort_expr ) )
 | 
						|
  {
 | 
						|
#ifdef S4NDX
 | 
						|
  case r4num:
 | 
						|
  case r4num_doub:
 | 
						|
  case r4date:
 | 
						|
  case r4date_doub:
 | 
						|
    relation->sort.cmp = t4cmp_doub ;
 | 
						|
    break ;
 | 
						|
#endif
 | 
						|
#ifdef S4MDX
 | 
						|
  case r4num:
 | 
						|
    /*               if ( is_desc )                 */
 | 
						|
    /*                  relation->sort.cmp = t4desc_bcd_cmp ;  */
 | 
						|
    /*               else                           */
 | 
						|
    relation->sort.cmp = c4bcd_cmp ;
 | 
						|
    break ;
 | 
						|
  case r4date:
 | 
						|
    /*               if ( is_desc )                 */
 | 
						|
    /*                  relation->sort.cmp = t4desc_cmp_doub ; */
 | 
						|
    /*               else                           */
 | 
						|
    relation->sort.cmp = t4cmp_doub ;
 | 
						|
    break ;
 | 
						|
    /*            case r4str:                       */
 | 
						|
    /*               if ( is_desc )                 */
 | 
						|
    /*                  relation->sort.cmp = t4desc_memcmp ;   */
 | 
						|
    /*               else                           */
 | 
						|
    /*                  relation->sort.cmp = u4memcmp ;        */
 | 
						|
 | 
						|
#endif
 | 
						|
  default:
 | 
						|
    break ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
  /* call relate4top() again in case free-ups occurred */
 | 
						|
  rc = relate4top( relate ) ;
 | 
						|
  if ( rc )   /* no records satisfy the relate, or error */
 | 
						|
  {
 | 
						|
    expr4free( sort_expr ) ;
 | 
						|
    return rc ;
 | 
						|
  }
 | 
						|
 | 
						|
  for ( j = 0L, rc = 0 ; !rc ; j++, rc = relate4skip( relate, 1L ) )
 | 
						|
  {
 | 
						|
    for ( i = 0, r4data = 0 ;; i++ )
 | 
						|
    {
 | 
						|
      r4data = (R4DATA_LIST *)l4next( &relation->sort_data_list, r4data ) ;
 | 
						|
      if ( r4data == 0 )
 | 
						|
        break ;
 | 
						|
      if ( d4eof( r4data->data ) || d4bof( r4data->data ) )   /* relate4blank case */
 | 
						|
        memcpy( relation->other_data + i * sizeof(long), (void *)&zero, sizeof( long ) ) ;
 | 
						|
      else
 | 
						|
        memcpy( relation->other_data + i * sizeof(long), (void *)&r4data->data->rec_num, sizeof( long ) ) ;
 | 
						|
    }
 | 
						|
    if ( expr4key( sort_expr, &sort_key ) < 0 )
 | 
						|
    {
 | 
						|
      expr4free( sort_expr ) ;
 | 
						|
      u4free( relation->other_data ) ;
 | 
						|
      relation->other_data = 0 ;
 | 
						|
      return -1 ;
 | 
						|
    }
 | 
						|
    if ( sort4put( &relation->sort, j, sort_key, relation->other_data ) < 0 )
 | 
						|
    {
 | 
						|
      expr4free( sort_expr ) ;
 | 
						|
      u4free( relation->other_data ) ;
 | 
						|
      relation->other_data = 0 ;
 | 
						|
      return -1 ;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  expr4free( sort_expr ) ;
 | 
						|
 | 
						|
  if ( rc < 0 || rc == r4terminate )
 | 
						|
  {
 | 
						|
    u4free( relation->other_data ) ;
 | 
						|
    relation->other_data = 0 ;
 | 
						|
    return rc ;
 | 
						|
  }
 | 
						|
 | 
						|
  relation->sort_rec_count = j ;
 | 
						|
  relation->in_sort = relate4sort_done ;
 | 
						|
 | 
						|
  if ( relation->skip_backwards )
 | 
						|
    if ( file4temp( &relation->sorted_file, code_base, relation->sorted_file_name, 1 ) < 0 )
 | 
						|
    {
 | 
						|
      u4free( relation->other_data ) ;
 | 
						|
      relation->other_data = 0 ;
 | 
						|
      return -1 ;
 | 
						|
    }
 | 
						|
 | 
						|
  if ( sort4get_init_free( &relation->sort, relate ) < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relation->sort_rec_on = relation->sort_file_pos = relation->sort_rec_to = 0L ;
 | 
						|
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
void S4FUNCTION relate4sort_free( RELATION4 *relation, int delete_sort )
 | 
						|
{
 | 
						|
  if ( relation == 0 )
 | 
						|
    return ;
 | 
						|
 | 
						|
  sort4free( &relation->sort ) ;
 | 
						|
  u4free( relation->other_data ) ;
 | 
						|
  relation->other_data = 0 ;
 | 
						|
  if ( relation->sorted_file.hand >= 0 )
 | 
						|
    file4close( &relation->sorted_file ) ;
 | 
						|
  r4data_list_free( &relation->sort_data_list ) ;
 | 
						|
  relation->in_sort = 0 ;
 | 
						|
  if ( delete_sort )
 | 
						|
  {
 | 
						|
    u4free( relation->sort_source ) ;
 | 
						|
    relation->sort_source = 0 ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4sort_get_record( RELATION4 *relation, long num )
 | 
						|
{
 | 
						|
  int len, i, rc ;
 | 
						|
  char *other, *key ;
 | 
						|
  R4DATA_LIST *link_on ;
 | 
						|
  long j, num_left ;
 | 
						|
#ifdef S4UNIX
 | 
						|
  long long_ptr ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relation->relate.code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  if ( num <= 0 )
 | 
						|
    return r4bof ;
 | 
						|
 | 
						|
  relation->sort_eof_flag = 0 ;
 | 
						|
  num_left = num - relation->sort_rec_to ;
 | 
						|
 | 
						|
  if ( num_left <= 0 )  /* already read, so just return from file */
 | 
						|
  {
 | 
						|
    if ( relation->skip_backwards == 0 )
 | 
						|
      return -1 ;
 | 
						|
    len = file4read( &relation->sorted_file, ( num - 1 ) * relation->sort_other_len, relation->other_data, relation->sort_other_len ) ;
 | 
						|
    if ( len != relation->sort_other_len )  /* free up and exit */
 | 
						|
      return -1 ;
 | 
						|
    other = relation->other_data ;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    while ( num_left-- )
 | 
						|
    {
 | 
						|
      if ( relation->sort_done_flag == 1 )  /* sort is finished, therefore must be eof */
 | 
						|
        return r4eof ;
 | 
						|
 | 
						|
      rc = sort4get( &relation->sort, &j, (void **)&key, (void **)&other ) ;
 | 
						|
      if ( rc )  /* no more items, or error */
 | 
						|
      {
 | 
						|
        sort4free( &relation->sort ) ;
 | 
						|
        if ( rc == 1 )
 | 
						|
        {
 | 
						|
          relation->sort_eof_flag = 1 ;
 | 
						|
          relation->sort_done_flag = 1 ;
 | 
						|
          return r4eof ;
 | 
						|
        }
 | 
						|
        else
 | 
						|
          return rc ;
 | 
						|
      }
 | 
						|
      relation->sort_rec_to++ ;
 | 
						|
      if ( relation->skip_backwards )
 | 
						|
      {
 | 
						|
        file4write( &relation->sorted_file, relation->sort_file_pos, other, relation->sort_other_len ) ;
 | 
						|
        relation->sort_file_pos += relation->sort_other_len ;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  /* now read the database records in */
 | 
						|
  for ( i = 0, link_on = 0 ;; i++ )
 | 
						|
  {
 | 
						|
    link_on = (R4DATA_LIST *)l4next( &relation->sort_data_list, link_on ) ;
 | 
						|
    if ( link_on == 0 )
 | 
						|
      return 0 ;
 | 
						|
#ifdef S4UNIX
 | 
						|
    memcpy( &long_ptr, (long *)other + i, sizeof(long_ptr) ) ;
 | 
						|
    if ( long_ptr == 0 )  /* relate4blank case */
 | 
						|
      d4go_eof( link_on->data ) ;
 | 
						|
    else
 | 
						|
      d4go( link_on->data, long_ptr ) ;
 | 
						|
#else
 | 
						|
    if ( *((long *)other + i ) == 0 )  /* relate4blank case */
 | 
						|
      d4go_eof( link_on->data ) ;
 | 
						|
    else
 | 
						|
      d4go( link_on->data, *((long *)other + i ) ) ;
 | 
						|
#endif
 | 
						|
    link_on->relate->is_read = 1 ;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4sort_next_record( RELATION4 *relation )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
 | 
						|
  if ( relation->relate.code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  rc = relate4sort_get_record( relation, relation->sort_rec_on + 1 ) ;
 | 
						|
  if ( rc == 0 )
 | 
						|
    relation->sort_rec_on++ ;
 | 
						|
  if ( rc == r4eof )
 | 
						|
    relation->sort_rec_on = relation->sort_rec_count + 1 ;
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4sort_prev_record( RELATION4 *relation )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
 | 
						|
  if ( relation->relate.code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  rc = relate4sort_get_record( relation, relation->sort_rec_on - 1 ) ;
 | 
						|
  if ( rc == 0 )
 | 
						|
    relation->sort_rec_on-- ;
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4sort_set( RELATE4 *relate, char *expr )
 | 
						|
{
 | 
						|
  RELATION4 *relation ;
 | 
						|
  int len ;
 | 
						|
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4SORT_SET ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( relate->code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relation = relate->relation ;
 | 
						|
  relate = &relation->relate ;
 | 
						|
  relate4changed( relate ) ;
 | 
						|
  u4free( relate->relation->sort_source ) ;
 | 
						|
  relate->relation->sort_source = 0 ;
 | 
						|
  if ( expr )
 | 
						|
    if ( expr[0] )
 | 
						|
    {
 | 
						|
      len = strlen( expr ) ;
 | 
						|
      relation->sort_source = (char *)u4alloc_er( relate->code_base, len + 1 ) ;
 | 
						|
      if ( relation->sort_source == 0 )
 | 
						|
        return -1 ;
 | 
						|
      memcpy( relation->sort_source, expr, len ) ;
 | 
						|
    }
 | 
						|
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4top( RELATE4 *relate )
 | 
						|
{
 | 
						|
  RELATION4 *relation ;
 | 
						|
  int rc, rc2 ;
 | 
						|
  long rec ;
 | 
						|
  CODE4 *code_base ;
 | 
						|
#ifndef S4OPTIMIZE_OFF
 | 
						|
  char has_opt ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( relate->code_base, 1, E4_R4TOP ) )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4TOP ) ;
 | 
						|
#else
 | 
						|
  if( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  code_base = relate->code_base ;
 | 
						|
  if ( code_base->error_code < 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
  relation = relate->relation ;
 | 
						|
  relate = &relation->relate ;
 | 
						|
 | 
						|
  rc = 0 ;
 | 
						|
 | 
						|
  if ( relation->in_sort == relate4sort_done )
 | 
						|
    if ( relation->skip_backwards == 0 )
 | 
						|
      relate4changed( relate ) ;
 | 
						|
 | 
						|
  relate->data_tag = d4tag_selected( relate->data ) ;
 | 
						|
  if ( relation->is_initialized == 0 )
 | 
						|
  {
 | 
						|
 | 
						|
#ifndef S4SINGLE
 | 
						|
    if ( code_base->read_lock )
 | 
						|
      rc = relate4lock( relate ) ;
 | 
						|
#endif
 | 
						|
#ifndef S4OPTIMIZE_OFF
 | 
						|
    has_opt = (char)code_base->has_opt ;
 | 
						|
#endif
 | 
						|
    if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
    relate->relation->bitmaps_freed = 0 ;
 | 
						|
    if ( relation->expr_source )
 | 
						|
    {
 | 
						|
      relation->log.expr = expr4parse( relate->data, relation->expr_source ) ;
 | 
						|
      if ( relation->log.expr == 0 )
 | 
						|
        return -1 ;
 | 
						|
 | 
						|
      if ( log4bitmap_do( &relation->log ) < 0 )
 | 
						|
        relate->relation->bitmaps_freed = 1 ;
 | 
						|
      log4determine_evaluation_order( &relation->log ) ;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( relate4build_scan_list( relate, relation ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
    relation->relate_list.selected = (void *)l4first( &relation->relate_list) ;
 | 
						|
 | 
						|
    relation->is_initialized = 1 ;
 | 
						|
 | 
						|
    if ( relation->sort_source )
 | 
						|
    {
 | 
						|
      rc = relate4sort( relate ) ;
 | 
						|
      if ( rc < 0 || rc == r4terminate )
 | 
						|
        return rc ;
 | 
						|
    }
 | 
						|
 | 
						|
#ifndef S4OPTIMIZE_OFF
 | 
						|
    if ( has_opt )
 | 
						|
      d4opt_restart( code_base ) ;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
  relate4set_not_read( relate ) ;
 | 
						|
 | 
						|
  if ( relation->in_sort == relate4sort_done )
 | 
						|
  {
 | 
						|
    relation->sort_rec_on = 0 ;
 | 
						|
    rc = relate4sort_next_record( relation ) ;
 | 
						|
  }
 | 
						|
  else
 | 
						|
    rc = d4top( relate->data ) ;
 | 
						|
 | 
						|
  if ( rc )    /* eof or error */
 | 
						|
    return rc ;
 | 
						|
 | 
						|
  if ( relation->expr_source )
 | 
						|
  {
 | 
						|
    rec = d4recno( relate->data ) ;
 | 
						|
    if ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
 | 
						|
    {
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
      if ( relate->data_tag )
 | 
						|
        while ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
 | 
						|
        {
 | 
						|
#ifdef S4HAS_DESCENDING
 | 
						|
          rc = (int)t4dskip( relate->data_tag, 1L ) ;
 | 
						|
#else
 | 
						|
          rc = (int)t4skip( relate->data_tag, 1L ) ;
 | 
						|
#endif
 | 
						|
          if ( rc != 1 )
 | 
						|
          {
 | 
						|
            if ( rc == 0 )
 | 
						|
            {
 | 
						|
              d4go_eof( relate->data ) ;
 | 
						|
              return r4eof ;
 | 
						|
            }
 | 
						|
            return rc ;
 | 
						|
          }
 | 
						|
          rec = t4recno( relate->data_tag ) ;
 | 
						|
        }
 | 
						|
      else
 | 
						|
      {
 | 
						|
#endif
 | 
						|
        rec = f4flag_get_next_flip( &relate->set, 1L, 1 ) + 1L ;
 | 
						|
        if ( rec > relate->data->count )
 | 
						|
        {
 | 
						|
          relate->data->count = d4reccount( relate->data ) ;
 | 
						|
          if ( rec > relate->data->count )
 | 
						|
          {
 | 
						|
            d4go_eof( relate->data ) ;
 | 
						|
            return r4eof ;
 | 
						|
          }
 | 
						|
        }
 | 
						|
#ifndef S4INDEX_OFF
 | 
						|
      }
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    d4go( relate->data, rec ) ;
 | 
						|
  }
 | 
						|
 | 
						|
  rc = relate4read_rest( relate, 1 ) ;
 | 
						|
  if ( rc == relate4filter_record )
 | 
						|
    return relate4skip( relate, 1L ) ;
 | 
						|
 | 
						|
  if ( rc < 0 || rc == r4terminate )
 | 
						|
    return rc ;
 | 
						|
 | 
						|
  if ( relation->expr_source )
 | 
						|
  {
 | 
						|
    rc2 = log4true( &relation->log ) ;
 | 
						|
    if ( rc2 == r4terminate )
 | 
						|
      return r4terminate ;
 | 
						|
    if ( rc2 == 0 )
 | 
						|
    {
 | 
						|
      if ( relation->in_sort == relate4sort_skip )  /* must temporarily disable in order to get a matching scan if available */
 | 
						|
      {
 | 
						|
        relation->in_sort = 0 ;
 | 
						|
        rc = relate4skip( relate, 1L ) ;
 | 
						|
        relation->in_sort = relate4sort_skip ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
        rc = relate4skip( relate, 1L ) ;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4type( RELATE4 *relate, int relate_type )
 | 
						|
{
 | 
						|
  int rc ;
 | 
						|
 | 
						|
  if ( relate == 0 )
 | 
						|
    return -1 ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate_type != relate4exact && relate_type != relate4scan && relate_type != relate4approx )
 | 
						|
    e4severe( e4parm, E4_INFO_IVT ) ;
 | 
						|
#endif
 | 
						|
  rc = relate->relation_type ;
 | 
						|
  if ( rc != relate_type )
 | 
						|
  {
 | 
						|
    relate->relation_type = relate_type ;
 | 
						|
    relate4changed( relate ) ;
 | 
						|
  }
 | 
						|
  return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4unlock( RELATE4 *relate )
 | 
						|
{
 | 
						|
#ifndef S4SINGLE
 | 
						|
  DATA4 *data_on ;
 | 
						|
 | 
						|
#ifdef S4DEBUG
 | 
						|
  if ( relate == 0 )
 | 
						|
    e4severe( e4parm, E4_R4UNLOCK ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
  if ( !relate->relation->locked )
 | 
						|
    return 0 ;
 | 
						|
 | 
						|
  for ( data_on = (DATA4 *)l4first( &relate->code_base->data_list) ; data_on ; data_on = (DATA4 *)l4next( &relate->code_base->data_list, data_on ) )
 | 
						|
    if ( relate4dbf_in_relation( relate, data_on ) )
 | 
						|
      d4unlock( data_on ) ;
 | 
						|
 | 
						|
  relate->relation->locked = 0 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef S4VB_DOS
 | 
						|
 | 
						|
RELATE4 *S4FUNCTION relate4create_slave_v( RELATE4 *master, DATA4 *slave, char *master_expr, TAG4 *slave_tag)
 | 
						|
{
 | 
						|
  return relate4create_slave(master, slave, c4str(master_expr), slave_tag) ;
 | 
						|
}
 | 
						|
 | 
						|
char * relate4master_expr_v( RELATE4 *r4 )
 | 
						|
{
 | 
						|
#ifdef S4VBASIC
 | 
						|
  if ( c4parm_check( r4->code_base, 1, "relate4masterExpr():" ) ) return 0 ;
 | 
						|
#endif
 | 
						|
 | 
						|
  return v4str(r4->master_expr->source) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4query_set_v ( RELATE4 *relate, char *expr )
 | 
						|
{
 | 
						|
  return relate4query_set( relate, c4str(expr) ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION relate4sort_set_v ( RELATE4 *relate, char *expr )
 | 
						|
{
 | 
						|
  return relate4sort_set( relate, c4str(expr) ) ;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |