/* c4const.c (c)Copyright Sequiter Software Inc., 1990-1994. All rights reserved. */ #include "d4all.h" #ifndef S4UNIX #ifdef __TURBOC__ #pragma hdrstop #endif #endif #ifndef S4INDEX_OFF /* This function creates a branch out of the input constant, and combines it with the input map */ static void bitmap4constant_combine( BITMAP4 *parent, BITMAP4 *old_and_map, CONST4 *con, int con_type ) { BITMAP4 *temp_leaf, *and_map, *new_branch ; CONST4 *temp ; if ( con->len == 0 || parent->log->code_base->error_code == e4memory ) return ; new_branch = bitmap4create( parent->log, parent->relate, 1, 1 ) ; if ( new_branch == 0 ) return ; and_map = bitmap4create( parent->log, parent->relate, 0, 0 ) ; if ( and_map == 0 ) return ; bitmap4copy( and_map, old_and_map ) ; l4add( &new_branch->children, and_map ) ; temp_leaf = bitmap4create( parent->log, parent->relate, 1, 0 ) ; if ( temp_leaf == 0 ) return ; temp_leaf->type = and_map->type ; temp_leaf->tag = and_map->tag ; l4add( &new_branch->children, temp_leaf ) ; switch( con_type ) { case 1: memcpy( (void *)&temp_leaf->lt, (void *)con, sizeof( CONST4 ) ) ; break ; case 2: memcpy( (void *)&temp_leaf->le, (void *)con, sizeof( CONST4 ) ) ; break ; case 3: memcpy( (void *)&temp_leaf->gt, (void *)con, sizeof( CONST4 ) ) ; break ; case 4: memcpy( (void *)&temp_leaf->ge, (void *)con, sizeof( CONST4 ) ) ; break ; case 5: memcpy( (void *)&temp_leaf->eq, (void *)con, sizeof( CONST4 ) ) ; break ; case 6: temp = (CONST4 *)u4alloc( sizeof( CONST4 ) ) ; if ( temp == 0 ) return ; memcpy( (void *)temp, (void *)con, sizeof( CONST4 ) ) ; l4add( &temp_leaf->ne, temp ) ; break ; default: #ifdef S4DEBUG e4severe( e4info, E4_BM4CON_COMBINE ) ; #endif return ; } memset( (void *)con, 0 ,sizeof( CONST4 ) ) ; new_branch = bitmap4redistribute( 0, new_branch, 0 ) ; if ( new_branch->children.n_link == 0 ) bitmap4destroy( new_branch ) ; else l4add( &parent->children, new_branch ) ; } /* this function redistributes (splits and combines) and/and, or/or block sequences */ BITMAP4 * S4FUNCTION bitmap4redistribute( BITMAP4 *parent, BITMAP4 *map, char do_shrink ) { BITMAP4 *child_map, *child_on, *parent2map ; char split ; if ( map->branch == 0 ) return map ; /* first combine all the children of this map */ child_on = child_map = (BITMAP4 *)l4first( &map->children ) ; for( ;; ) { if ( child_on == 0 ) break ; child_on = bitmap4redistribute( map, child_on, 0 ) ; child_on = (BITMAP4 *)l4next( &map->children, child_on ) ; } /* now combine all leaf children where possible */ if ( parent != 0 ) if ( parent->and_or != map->and_or ) /* case where no combos possible */ return map ; parent2map = 0 ; child_on = child_map = (BITMAP4 *)l4first( &map->children ) ; for( ; child_map != 0 ; ) { child_on = (BITMAP4 *)l4next( &map->children, child_map ) ; if ( child_on == 0 ) break ; split = 0 ; if ( child_on->tag != child_map->tag || child_on->and_or != child_map->and_or ) split = 1 ; else { if ( map != 0 ) if ( map->and_or != child_on->and_or ) split = 1 ; } if ( split == 1 ) { if ( parent2map == 0 ) { parent2map = bitmap4create( map->log, map->relate, map->and_or, 1 ) ; if ( parent2map == 0 ) /* must handle by freeing... */ return 0 ; if ( parent == 0 ) { parent = bitmap4create( map->log, map->relate, map->and_or, 1 ) ; if ( parent == 0 ) /* must handle by freeing... */ return 0 ; l4add( &parent->children, map ) ; } l4add( &parent->children, parent2map ) ; } l4remove( &map->children, child_on ) ; l4add( &parent2map->children, child_on ) ; } else child_map = bitmap4combine_leafs( map, child_map, child_on ) ; } if ( parent2map != 0 ) { #ifdef S4DEBUG if ( parent == 0 ) e4severe( e4info, E4_BM4REDIST ) ; #endif bitmap4redistribute( parent, parent2map, 1 ) ; } if ( do_shrink ) { if ( map->children.n_link == 1 ) /* just a child, so remove myself */ { child_map = (BITMAP4 *)l4first( &map->children ) ; l4remove( &map->children, child_map ) ; if ( parent != 0 ) { #ifdef S4DEBUG if ( child_map->tag == 0 && child_map->children.n_link == 0 ) e4severe( e4info, E4_BM4REDIST ) ; #endif if ( parent->tag == 0 && child_map->tag != 0 ) parent->tag = child_map->tag ; l4add_after( &parent->children, map, child_map ) ; l4remove( &parent->children, map ) ; } bitmap4destroy( map ) ; map = child_map ; } } if ( parent2map != 0 && parent != 0 ) return parent ; return map ; } /* this function redistributes the input maps by breaking the one up into constants and creating maps for each */ BITMAP4 * S4FUNCTION bitmap4redistribute_leaf( BITMAP4 *parent, BITMAP4 *map1, BITMAP4 *map2 ) { BITMAP4 *new_branch, *or_map, *place, *and_map, *temp ; CONST4 *c_on ; new_branch = bitmap4create( parent->log, parent->relate, 1, 1 ) ; if ( new_branch == 0 ) return 0 ; place = bitmap4create( parent->log, parent->relate, 0, 0 ) ; if ( place == 0 ) return 0 ; l4add_after( &parent->children, map1, place ) ; l4remove( &parent->children, map1 ) ; l4remove( &parent->children, map2 ) ; if ( map1->and_or == 1 ) { and_map = map1 ; or_map = map2 ; } else { and_map = map2 ; or_map = map1 ; } bitmap4constant_combine( new_branch, and_map, &or_map->lt, 1 ) ; bitmap4constant_combine( new_branch, and_map, &or_map->le, 2 ) ; bitmap4constant_combine( new_branch, and_map, &or_map->gt, 3 ) ; bitmap4constant_combine( new_branch, and_map, &or_map->ge, 4 ) ; bitmap4constant_combine( new_branch, and_map, &or_map->eq, 5 ) ; for( ;; ) { c_on = (CONST4 *)l4first( &or_map->ne ) ; if ( c_on == 0 ) break ; bitmap4constant_combine( new_branch, and_map, c_on, 6 ) ; } if ( parent->log->code_base->error_code == e4memory ) return 0 ; if ( new_branch->children.n_link == 0 ) /* collapsed */ { if ( parent->tag == 0 && and_map->tag != 0 ) parent->tag = and_map->tag ; bitmap4destroy( new_branch ) ; new_branch = 0 ; } else { while( new_branch->branch == 1 && new_branch->children.n_link == 1 ) { temp = (BITMAP4 *)l4first( &new_branch->children ) ; bitmap4destroy( new_branch ) ; new_branch = temp ; } l4add_after( &parent->children, place, new_branch ) ; } l4remove( &parent->children, place ) ; bitmap4destroy( place ) ; bitmap4destroy( or_map ) ; bitmap4destroy( and_map ) ; return new_branch ; } /* this function splits and combines and/or, or/and block sequences */ /* all bitmaps must be in standard bitmap4redistribute format prior to call */ BITMAP4 * S4FUNCTION bitmap4redistribute_branch( BITMAP4 *parent, BITMAP4 *map ) { BITMAP4 *child_on2, *child_on, *child_next2 ; if ( map->branch == 0 ) return map ; child_on = (BITMAP4 *)l4first( &map->children ) ; for( ;; ) { if ( child_on == 0 ) break ; if ( child_on->branch ) { child_on = bitmap4redistribute_branch( map, child_on ) ; if ( child_on == 0 && parent->log->code_base->error_code == e4memory ) return 0 ; } if ( child_on->branch == 0 ) { child_on2 = (BITMAP4 *)l4next( &map->children, child_on ) ; while( child_on2 != 0 ) { if ( child_on2->branch ) { child_on2 = bitmap4redistribute_branch( map, child_on2 ) ; if ( child_on2 == 0 && parent->log->code_base->error_code == e4memory ) return 0 ; } child_next2 = (BITMAP4 *)l4next( &map->children, child_on2 ) ; if ( child_on->branch == 0 && map->and_or == 1 && child_on->tag == child_on2->tag && child_on->and_or != child_on2->and_or ) { child_on = bitmap4redistribute_leaf( map, child_on, child_on2 ) ; if ( child_on == 0 && parent->log->code_base->error_code == e4memory ) return 0 ; } child_on2 = child_next2 ; } } child_on = (BITMAP4 *)l4next( &map->children, child_on ) ; } if ( map->branch == 1 ) { if ( map->children.n_link == 0 ) /* mark ourselves as a leaf with no match */ { map->branch = 0 ; map->no_match = 1 ; } else if ( map->children.n_link == 1 ) /* just a child, so remove myself */ { child_on = (BITMAP4 *)l4first( &map->children ) ; l4remove( &map->children, child_on ) ; if ( parent != 0 ) { l4add_after( &parent->children, map, child_on ) ; l4remove( &parent->children, map ) ; } bitmap4destroy( map ) ; map = child_on ; } } return map ; } /* location = 0 if seek_before, 1 if seek 1st, 2 if seek last, 3 if seek_after, */ /* add 10 if it is to be an approximate seek */ /* returns record number */ #ifdef S4HAS_DESCENDING long S4FUNCTION bitmap4seek( BITMAP4 *map, CONST4 *con, char location, long check, int do_check ) { int len, rc ; TAG4 *tag ; char *result ; #ifdef S4CLIPPER int old_dec ; char hold_result[20] ; /* enough space for a numerical key */ #endif tag = map->tag ; result = (char *)const4return( map->log, con ) ; if ( map->type != r4str ) /* must convert to a proper key */ { #ifdef S4CLIPPER { old_dec = tag->code_base->decimals ; tag->code_base->decimals = tag->header.key_dec ; memcpy( hold_result, result, con->len ) ; result = hold_result ; #endif #ifdef S4DEBUG if ( expr4len( tag->expr ) == -1 ) e4severe( e4info, E4_BM4_IEL ) ; #endif len = expr4key_convert( tag->expr, (char **)&result, con->len, map->type ) ; #ifdef S4CLIPPER tag->code_base->decimals = old_dec ; } #endif } else len = con->len ; if ( location > 1 ) t4descending( tag, 1 ) ; else t4descending( tag, 0 ) ; t4seek( tag, result, len ) ; t4descending( tag, 0 ) ; if ( !t4eof( tag ) ) if ( do_check == 1 ) if ( check == t4recno( tag ) ) return -1 ; switch ( location ) { case 0: if ( t4skip( tag, -1L ) != -1L ) /* at top already */ return -1 ; break ; case 1: if ( t4eof( tag ) ) return -1 ; break ; case 2: #ifdef S4FOX if( u4memcmp( t4key_data(tag)->value, result, len ) != 0 ) /* last one is too far, go back one for a closure */ #else if( (*tag->cmp)( t4key_data(tag)->value, result, len ) != 0 ) /* last one is too far, go back one for a closure */ #endif { if ( !t4eof( tag ) ) if ( do_check == 1 ) if ( check == t4recno( tag ) ) /* case where none belong, so break now */ return -1 ; } break ; case 3: rc = (int)t4skip( tag, 1L ) ; if ( rc == 0L ) return -1 ; break ; default: #ifdef S4DEBUG e4severe( e4info, E4_BM4SEEK ) ; #endif return 0 ; } return t4recno( tag ) ; } #endif #ifdef S4NDX long S4FUNCTION bitmap4seek( BITMAP4 *map, CONST4 *con, char location, long check, int do_check ) { int len, rc ; TAG4 *tag ; char *result ; char did_skip ; int seek_rc ; tag = map->tag ; result = (char *)const4return( map->log, con ) ; if ( map->type != r4str ) /* must convert to a proper key */ { #ifdef S4DEBUG if ( expr4len( tag->expr ) == -1 ) e4severe( e4info, E4_BM4_IEL ) ; #endif len = expr4key_convert( tag->expr, (char **)&result, con->len, map->type ) ; } else len = con->len ; seek_rc = t4seek( tag, result, len ) ; if ( !t4eof( tag ) ) if ( do_check ) if ( check == t4recno( tag ) ) return -1 ; switch ( location ) { case 0: if ( t4skip( tag, -1L ) != -1L ) /* at top already */ return -1 ; break ; case 1: if ( t4eof( tag ) ) return -1 ; break ; case 2: if( (*tag->cmp)( t4key_data(tag)->value, result, len ) != 0 ) /* last one is too far, go back one for a closure */ { if ( !t4eof( tag ) ) if ( check == t4recno( tag ) ) /* case where none belong, so break now */ return -1 ; if ( t4skip( tag, -1L ) != -1L ) return -1 ; } case 3: did_skip = 0 ; for(; (*tag->cmp)( t4key_data(tag)->value, result, len ) == 0; ) { rc = (int)t4skip( tag, 1L ) ; if ( rc < 0 ) return -1 ; if ( rc != 1 ) { if ( location == 2 ) /* on last record, but it still belongs, so don't skip back */ did_skip = 0 ; if ( location == 3 ) /* on last record not far enough, so none match */ return -1 ; break ; } did_skip = 1 ; } if ( location == 3 ) { if ( did_skip == 0 && seek_rc != 2 ) if ( t4skip( tag, 1L ) != 1L ) return -1 ; } else if ( did_skip == 1 ) if ( t4skip( tag, -1L ) != -1L ) return -1 ; break ; default: #ifdef S4DEBUG e4severe( e4info, E4_BM4SEEK ) ; #endif return 0 ; } return t4recno( tag ) ; } #endif #ifdef S4MDX long S4FUNCTION bitmap4seek( BITMAP4 *map, CONST4 *con, char location, long check, int do_check ) { int len, rc, seek_rc, is_desc ; TAG4 *tag ; char *result ; char did_skip ; tag = map->tag ; result = (char *)const4return( map->log, con ) ; is_desc = ( tag->header.type_code & 8 ) ? 1 : 0 ; if ( map->type != r4str ) /* must convert to a proper key */ { #ifdef S4DEBUG if ( expr4len( tag->expr ) == -1 ) e4severe( e4info, E4_BM4_IEL ) ; #endif len = expr4key_convert( tag->expr, (char **)&result, con->len, map->type ) ; } else len = con->len ; seek_rc = t4seek( tag, result, len ) ; if ( !t4eof( tag ) ) if ( do_check ) if ( check == t4recno( tag ) ) return -1 ; switch ( location ) { case 0: if ( is_desc ) { if ( t4eof( tag ) ) return -1 ; for(; (*tag->cmp)( t4key_data(tag)->value, result, len ) == 0; ) { rc = (int)t4skip( tag, 1L ) ; if ( rc < 0 ) return -1 ; if ( rc != 1 ) { if ( rc == 0 ) return -1 ; break ; } } } else if ( t4skip( tag, -1L ) != -1L ) /* at top already */ return -1 ; break ; case 1: if ( is_desc ) { if ( seek_rc == 2 ) { if ( !t4eof( tag ) ) if ( check == t4recno( tag ) ) /* case where none belong, so break now */ return -1 ; if ( t4skip( tag, -1L ) != -1L ) return -1 ; } else { rc = -1 ; for(; (*tag->cmp)( t4key_data(tag)->value, result, len ) == 0; ) { rc = (int)t4skip( tag, 1L ) ; if ( rc < 0 ) return -1 ; if ( rc != 1 ) break ; } if ( rc == 0 ) t4bottom( tag ) ; else t4skip( tag, -1L ) ; } } else { if ( t4eof( tag ) ) return -1 ; } break ; case 2: if ( is_desc ) { if ( t4eof( tag ) ) return -1 ; if ( seek_rc == 2 ) if ( check == t4recno( tag ) ) /* case where none belong, so break now */ return -1 ; break ; } else { if( (*tag->cmp)( t4key_data(tag)->value, result, len ) != 0 ) /* last one is too far, go back one for a closure */ { if ( !t4eof( tag ) ) if ( check == t4recno( tag ) ) /* case where none belong, so break now */ return -1 ; if ( t4skip( tag, -1L ) != -1L ) return -1 ; } } case 3: if ( is_desc ) { if ( t4skip( tag, -1L ) != -1L ) /* at top already */ return -1 ; } else { did_skip = 0 ; for(; (*tag->cmp)( t4key_data(tag)->value, result, len ) == 0; ) { rc = (int)t4skip( tag, 1L ) ; if ( rc < 0 ) return -1 ; if ( rc != 1 ) { if ( location == 2 ) /* on last record, but it still belongs, so don't skip back */ did_skip = 0 ; if ( location == 3 ) /* on last record not far enough, so none match */ return -1 ; break ; } did_skip = 1 ; } if ( location == 3 ) { if ( did_skip == 0 && seek_rc != 2 ) if ( t4skip( tag, 1L ) != 1L ) return -1 ; } else if ( did_skip == 1 ) if ( t4skip( tag, -1L ) != -1L ) return -1 ; } break ; default: #ifdef S4DEBUG e4severe( e4info, E4_BM4SEEK ) ; #endif return 0 ; } return t4recno( tag ) ; } #endif /* returns a pointer to the constant value */ void *S4FUNCTION const4return( L4LOGICAL *log, CONST4 *c1 ) { return (void *)( log->buf + c1->offset ) ; } /* updates the log's constant memory buffer, re-allocating memory if required */ int S4FUNCTION const4mem_alloc( L4LOGICAL *log, unsigned len ) { if ( ( log->buf_pos + len ) > log->buf_len ) { #ifdef S4DEBUG if ( (long)len + (long)log->buf_len != (long)(len + log->buf_len) ) e4severe( e4memory, E4_MEMORY_OOR ) ; #endif if ( u4alloc_again( log->code_base, &log->buf, &log->buf_len, log->buf_pos + len ) != 0 ) return -1 ; } log->buf_pos += len ; return 0 ; } /* duplicate an existing constant */ int S4FUNCTION const4duplicate( CONST4 *to, CONST4 *from, L4LOGICAL *log ) { unsigned len ; len = from->len ; if ( len == 0 ) memset( (void *)to, 0, sizeof( CONST4 ) ) ; else { if ( const4mem_alloc( log, len ) < 0 ) return -1 ; memcpy( log->buf + log->buf_pos - len, const4return( log, from ), len ) ; to->offset = log->buf_len - len ; to->len = len ; } return 0 ; } /* get a constant from an expr. info structure */ int S4FUNCTION const4get( CONST4 *con, BITMAP4 *map, L4LOGICAL *log, int pos ) { unsigned len ; char *result ; if ( expr4execute( log->expr, pos, (void **)&result ) < 0 ) return -1 ; len = log->expr->info[pos].len ; #ifdef S4DEBUG if ( map->type != 0 && map->type != v4functions[log->expr->info[pos].function_i].return_type ) e4severe( e4info, E4_CONST_EIN ) ; #endif if ( const4mem_alloc( log, len ) < 0 ) return -1 ; memcpy( log->buf + log->buf_pos - len, result, len ) ; map->type = v4functions[log->expr->info[pos].function_i].return_type ; con->offset = log->buf_len - len ; con->len = len ; return 0 ; } int S4FUNCTION const4less( CONST4 *p1, CONST4 *p2, BITMAP4 *map ) { switch( map->type ) { case r4num_doub: case r4date_doub: #ifdef S4DEBUG if ( p1->len != p2->len ) e4severe( e4info, E4_CONST4LESS ) ; #endif if ( *(double *)const4return( map->log, p1 ) < *(double *)const4return( map->log, p2 ) ) return 1 ; break ; case r4num: case r4str: if ( p1->len < p2->len ) { if ( memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), p1->len ) <= 0 ) return 1 ; } else if ( memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), p2->len ) < 0 ) return 1 ; break ; default: e4severe( e4info, E4_CONST4LESS ) ; } return 0 ; } int S4FUNCTION const4eq( CONST4 *p1, CONST4 *p2, BITMAP4 *map ) { if ( p1->len < p2->len ) { #ifdef S4DEBUG if ( map->type == r4num_doub || map->type == r4date_doub ) e4severe( e4info, E4_CONST4EQ ) ; #endif return 0 ; } #ifdef S4DEBUG switch( map->type ) { case r4num_doub: case r4date_doub: case r4num: case r4str: case r4log: break ; default: e4severe( e4info, E4_CONST4EQ ) ; } #endif if ( memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), p1->len ) == 0 ) return 1 ; return 0 ; } int S4FUNCTION const4less_eq( CONST4 *p1, CONST4 *p2, BITMAP4 *map ) { switch( map->type ) { case r4num_doub: case r4date_doub: #ifdef S4DEBUG if ( p1->len != p2->len ) e4severe( e4info, E4_CONST4LESS_EQ ) ; #endif if ( *(double *)const4return( map->log, p1 ) <= *(double *)const4return( map->log, p2 ) ) return 1 ; break ; case r4num: case r4str: if ( p1->len <= p2->len ) { if ( memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), p1->len ) <= 0 ) return 1 ; } else if ( memcmp( const4return( map->log, p1 ), const4return( map->log, p2 ), p2->len ) < 0 ) return 1 ; break ; default: e4severe( e4info, E4_CONST4LESS_EQ ) ; } return 0 ; } void S4FUNCTION const4add_ne( BITMAP4 *map, CONST4 *con ) { CONST4 *c_on ; c_on = (CONST4 *)l4first( &map->ne ) ; while ( c_on != 0 ) { if ( const4eq( con, c_on, map ) ) /* ne already exists, so ignore */ return ; c_on = (CONST4 *)l4next( &map->ne, c_on ) ; } c_on = (CONST4 *) u4alloc( sizeof( CONST4 ) ) ; if ( c_on == 0 ) return ; memcpy( (void *)c_on, (void *)con, sizeof( CONST4 ) ) ; l4add( &map->ne, c_on ) ; memset( (void *)con, 0, sizeof( CONST4 ) ) ; } void S4FUNCTION const4delete_ne( LIST4 *list, CONST4 *con ) { l4remove( list, con ) ; u4free( con ) ; } #endif /* S4INDEX_OFF */