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
1099 lines
32 KiB
C
Executable File
1099 lines
32 KiB
C
Executable File
/* r4save_2.c (c)Copyright Sequiter Software Inc., 1991-1994. All rights reserved. */
|
|
#include "d4all.h"
|
|
|
|
extern int file_version;
|
|
extern LIST4 name_list;
|
|
|
|
int save4long( FILE4SEQ_WRITE *seq, long *lval );
|
|
int save4short( FILE4SEQ_WRITE *seq, short *sval );
|
|
int ret4long( FILE4SEQ_READ *seq, long *lval );
|
|
int ret4short( FILE4SEQ_READ *seq, short *sval );
|
|
|
|
/************************************************************
|
|
*
|
|
* Function:
|
|
*
|
|
* PARAMETERS:
|
|
* DATA4* data - data file
|
|
* char* index_name - name of the index file to be checked for
|
|
* char* index_lookup - buffer used in the function
|
|
* char* current - buffer used in the function
|
|
*
|
|
* DESCRIPTION:this function performs the same operation as d4index(), but
|
|
* checks for an index file both with and without path names
|
|
*
|
|
* RETURNS: 1 - on finding a matching index file, 0 - on failure
|
|
*
|
|
* By: Raymond Cypher
|
|
*
|
|
* HISTORY:
|
|
*
|
|
*/
|
|
|
|
/* this function performs the same operation as d4index(), but checks for an
|
|
index file both with and without path names
|
|
*/
|
|
int S4FUNCTION r4index_lookup_foo( DATA4 *data, char *index_name,
|
|
char *index_lookup, char *current )
|
|
{
|
|
INDEX4 *index_on ;
|
|
int ttype;
|
|
|
|
|
|
if ( data == 0 || index_name == 0 )
|
|
#ifdef S4DEBUG
|
|
e4severe( e4parm, E4_D4INDEX ) ;
|
|
#else
|
|
return 0 ;
|
|
#endif
|
|
|
|
ttype = report4index_type();
|
|
u4name_piece( index_lookup, 257, index_name, 1, 0 ) ;
|
|
#ifndef S4UNIX
|
|
c4upper( index_lookup ) ;
|
|
#endif
|
|
|
|
if( r4cli == ttype || r4ndx == ttype )
|
|
{
|
|
if( d4tag( data, index_lookup ) )
|
|
return 1;
|
|
u4name_piece( index_lookup, 257, index_name, 0, 0 ) ;
|
|
if( d4tag( data, index_lookup ) )
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
index_on = (INDEX4 *)l4first( &data->indexes );
|
|
while( index_on )
|
|
{
|
|
u4name_piece( current, 257, index_on->file.name, 1, 0 ) ;
|
|
#ifndef S4UNIX
|
|
c4upper( current ) ;
|
|
#endif
|
|
if ( !strcmp( current, index_lookup ) ) /* check out data->alias? */
|
|
return 1;
|
|
index_on = (INDEX4 *) l4next( &data->indexes, index_on) ;
|
|
}
|
|
|
|
u4name_piece( index_lookup, 257, index_name, 0, 0 ) ;
|
|
#ifndef S4UNIX
|
|
c4upper( index_lookup ) ;
|
|
#endif
|
|
|
|
index_on = (INDEX4 *)l4first( &data->indexes );
|
|
while( index_on )
|
|
{
|
|
u4name_piece( current, 257, index_on->file.name, 0, 0 ) ;
|
|
#ifndef S4UNIX
|
|
c4upper( current ) ;
|
|
#endif
|
|
if ( !strcmp( current, index_lookup ) ) /* check out data->alias? */
|
|
return 1;
|
|
index_on = (INDEX4 *) l4next( &data->indexes, index_on) ;
|
|
}
|
|
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* wrapper for above function */
|
|
int S4FUNCTION r4index_lookup( DATA4 *data, char *index_name )
|
|
{
|
|
char *index_lookup, *current;
|
|
int retvalue;
|
|
|
|
index_lookup = (char *)u4alloc_free( data->code_base, 258 );
|
|
if( !index_lookup )
|
|
return 0;
|
|
|
|
current = (char*)u4alloc_free( data->code_base, 258 );
|
|
if( !current )
|
|
{
|
|
u4free( index_lookup );
|
|
return 0;
|
|
}
|
|
|
|
retvalue = r4index_lookup_foo( data, index_name, index_lookup, current );
|
|
|
|
u4free( index_lookup );
|
|
u4free( current );
|
|
return retvalue;
|
|
}
|
|
|
|
/************************************************************
|
|
*
|
|
* Function: r4open_data_foo()
|
|
*
|
|
* PARAMETERS:
|
|
* char* file_name - full name of the file, potentially including path
|
|
* char* alias - alias to set for the data file
|
|
* RELATE4* relate - the relate associated with the current report
|
|
* CODE4* code_base - CODE4 structure for the app
|
|
* char* fnbuf - a buffer used by the function
|
|
*
|
|
* DESCRIPTION: opens a data file, if the file is already open in the relate
|
|
* appropriate aliasing is performed to open the file a second time
|
|
*
|
|
* RETURNS: a DATA4 pointer on success, NULL on failure
|
|
*
|
|
* By: Raymond Cypher
|
|
*
|
|
* HISTORY:
|
|
*
|
|
*/
|
|
DATA4 *r4open_data_foo( char *file_name, char *alias, RELATE4 *relate, CODE4 *code_base, char *fnbuf )
|
|
{
|
|
DATA4 *old, *nnew;
|
|
RELATE4 *relate_on;
|
|
char abuf[11];
|
|
|
|
if( !file_name || !alias )
|
|
return NULL;
|
|
|
|
nnew = old = NULL;
|
|
/* if no alias or no relate do a simple d4open() */
|
|
if( alias[0] == '\0' || !relate )
|
|
{
|
|
nnew = d4open( code_base, file_name );
|
|
return nnew;
|
|
}
|
|
|
|
#ifndef S4UNIX
|
|
c4upper( file_name );
|
|
c4upper( alias );
|
|
#endif
|
|
|
|
/* check to see if the file is already open */
|
|
relate_on = relate;
|
|
while( relate_on )
|
|
{
|
|
strcpy( fnbuf, relate_on->data->file.name );
|
|
#ifndef S4UNIX
|
|
c4upper( fnbuf );
|
|
#endif
|
|
strcpy( abuf, d4alias( relate_on->data ) );
|
|
#ifndef S4UNIX
|
|
c4upper( abuf );
|
|
#endif
|
|
if( strcmp( fnbuf, file_name ) == 0 && strcmp(abuf, alias) == 0 )
|
|
old = relate_on->data;
|
|
|
|
relate4next( &relate_on );
|
|
}
|
|
|
|
/* if the file is not already open do a d4open() and set the alias */
|
|
if( old == NULL )
|
|
{
|
|
nnew = d4open( code_base, file_name );
|
|
if( nnew && alias[0] != '\0' )
|
|
d4alias_set( nnew, alias );
|
|
return nnew;
|
|
}
|
|
|
|
/* save the existing files alias, reset it to xxxxxxx open the new file,
|
|
set the new files alias, then restore the old files alias */
|
|
strcpy( abuf, d4alias(old) );
|
|
d4alias_set( old, "XXXXXXXXXX" );
|
|
nnew = d4open( code_base, file_name );
|
|
if( nnew )
|
|
d4alias_set( nnew, alias );
|
|
d4alias_set( old, abuf );
|
|
|
|
return nnew;
|
|
|
|
}
|
|
|
|
/* wrapper for above function */
|
|
DATA4 *r4open_data( char *file_name, char *alias, RELATE4 *relate, CODE4 *code_base )
|
|
{
|
|
DATA4 *retvalue;
|
|
char *fnbuf;
|
|
|
|
fnbuf = (char *)u4alloc_free( code_base, 256 );
|
|
if( !fnbuf )
|
|
return NULL;
|
|
|
|
retvalue = r4open_data_foo( file_name, alias, relate, code_base, fnbuf );
|
|
|
|
u4free( fnbuf );
|
|
return retvalue;
|
|
}
|
|
|
|
|
|
/* frees the list of N4CHANGE structures */
|
|
void report4free_name_list()
|
|
{
|
|
PN4CHANGE nchange;
|
|
|
|
while( (nchange = (PN4CHANGE)l4pop( &name_list )) != NULL )
|
|
{
|
|
if( nchange->old_name )
|
|
u4free( nchange->old_name );
|
|
|
|
if( nchange->new_name )
|
|
u4free( nchange->new_name );
|
|
|
|
u4free( nchange );
|
|
}
|
|
}
|
|
|
|
/* simple memcompare function that first capitalizes the buffers being compared */
|
|
int r4memicmp_foo( char *str1, char *str2, int len, char *buffer )
|
|
{
|
|
memset( buffer, 0, len + 1 );
|
|
memcpy( buffer, str1, len );
|
|
#ifndef S4UNIX
|
|
c4upper( buffer );
|
|
c4upper( str2 );
|
|
#endif
|
|
return memcmp( str1, str2, len );
|
|
}
|
|
|
|
/* wrapper for above function */
|
|
int r4memicmp( char *str1, char *str2, int len )
|
|
{
|
|
char *buffer;
|
|
int retvalue;
|
|
|
|
buffer = (char *)u4alloc( len+2 );
|
|
if( !buffer )
|
|
return 1;
|
|
|
|
retvalue = r4memicmp_foo( str1, str2, len, buffer );
|
|
u4free( buffer );
|
|
return retvalue;
|
|
}
|
|
|
|
/************************************************************
|
|
*
|
|
* Function: report4nchange()
|
|
*
|
|
* PARAMETERS:
|
|
* CODE4* c4 - apps code4 struct
|
|
* char** psrc - pointer to a pointer to the source string
|
|
* int can_alloc - flag specifying whether or not to allocate additional
|
|
* memory as needed
|
|
* int s_size - size of the source string
|
|
*
|
|
* DESCRIPTION: in CR when opening a report file, if a data or index file
|
|
* cannot be found the user is prompted to enter a new path and/or name.
|
|
* If the name of a data file has changed the name must also be changed in
|
|
* all the expressions within the report. To do this a list of N4CHANGE
|
|
* structures is maintained. N4CHANGE simply contains the old and new names
|
|
* for a data file. This function is passed an expression source and is
|
|
* responsible for swapping the names.
|
|
*
|
|
* RETURNS: none
|
|
*
|
|
* By: Raymond Cypher
|
|
*
|
|
* HISTORY:
|
|
*
|
|
*/
|
|
void report4nchange( CODE4 *c4, char **psrc, int can_alloc, int s_size )
|
|
{
|
|
char *orig = NULL, *src = *psrc;
|
|
PN4CHANGE nchange;
|
|
int pos, src_pos, orig_len;
|
|
int old_name_len, new_name_len;
|
|
unsigned src_size = s_size;
|
|
|
|
if( strlen(src) == 0 )
|
|
return;
|
|
|
|
/* for ever N4CHANGE struct in the name list */
|
|
nchange = (PN4CHANGE)l4first( &name_list );
|
|
while( nchange )
|
|
{
|
|
/* if no names continue */
|
|
if( !nchange->new_name || !nchange->old_name )
|
|
continue;
|
|
|
|
old_name_len = strlen(nchange->old_name);
|
|
|
|
/* create a buffer to duplicate the expression source */
|
|
orig = (char *)u4alloc_free( c4, strlen(src) + 1 );
|
|
if( !orig )
|
|
return;
|
|
|
|
/* copy the expression source */
|
|
src_pos = 0;
|
|
strcpy( orig, src );
|
|
orig_len = strlen(orig);
|
|
|
|
/* run through the copy of the expression source */
|
|
for( pos = 0; orig[pos]; pos++ )
|
|
{
|
|
/* we are copying the duplicated expression source back into the
|
|
original buffer, with appropriate insertions */
|
|
src[src_pos++] = orig[pos];
|
|
|
|
/* if the expression source buffer is too small due to changes
|
|
do a re-allocation */
|
|
if( src_pos == (int)src_size )
|
|
{
|
|
if( !can_alloc )
|
|
{
|
|
u4free( orig );
|
|
return;
|
|
}
|
|
u4alloc_again( c4, &src, &src_size, src_size+50 );
|
|
if( !src )
|
|
return;
|
|
}
|
|
|
|
/* if we're at the end of the expression source, continue */
|
|
if( (orig_len - pos) < old_name_len )
|
|
continue;
|
|
|
|
/* is this piece of the expression the current old name */
|
|
if( r4memicmp( orig+pos, nchange->old_name, old_name_len ) != 0 )
|
|
continue;
|
|
|
|
if( u4name_char( orig[pos+old_name_len] ) )
|
|
continue;
|
|
|
|
if( pos > 0 )
|
|
if( u4name_char( orig[pos-1]) )
|
|
continue;
|
|
|
|
/* insert the new name into the expression source, re-allocating space
|
|
if necessary */
|
|
new_name_len = strlen( nchange->new_name );
|
|
if( (int)src_size <= (pos+new_name_len) )
|
|
{
|
|
if( !can_alloc )
|
|
{
|
|
u4free( orig );
|
|
return;
|
|
}
|
|
|
|
u4alloc_again( c4, &src, &src_size, src_size + 50 );
|
|
if( !src )
|
|
{
|
|
u4free( orig );
|
|
return;
|
|
}
|
|
}
|
|
memcpy( src+(--src_pos), nchange->new_name, new_name_len );
|
|
src_pos += new_name_len;
|
|
pos += (old_name_len - 1);
|
|
} /* end of loop through copy of expression source */
|
|
|
|
/* end the string */
|
|
src[src_pos++] = '\0';
|
|
|
|
/* next change name */
|
|
nchange = (PN4CHANGE)l4next( &name_list, nchange );
|
|
/* free the source duplicate buffer */
|
|
if( orig )
|
|
{
|
|
u4free( orig );
|
|
orig = NULL;
|
|
}
|
|
}
|
|
|
|
if( orig )
|
|
{
|
|
u4free( orig );
|
|
orig = NULL;
|
|
}
|
|
|
|
/* set the pointer to the new source buffer */
|
|
*psrc = src;
|
|
}
|
|
|
|
|
|
|
|
/************************************************************
|
|
*
|
|
* Function: relate4retrieve_relate_foo()
|
|
*
|
|
* PARAMETERS:
|
|
* FILE4SEQ_READ* seq - sequential read struture for the file i/o
|
|
* int open_files - should the data files for the relate be opened
|
|
* char* spath - path to look for the data files
|
|
* the rest of the parameters are simply character buffers used in the fctn
|
|
*
|
|
* DESCRIPTION: retrieves a relation from a file. Note: this file and the
|
|
* r4save.c source file are compiled directly into the CR executable, as well
|
|
* as into the CodeBase DLL. As a result certain sections of this code
|
|
* are specific the the executable and call functions in the executable
|
|
*
|
|
* RETURNS: a RELATE4 pointer on success, NULL on failure
|
|
*
|
|
* By: Raymond Cypher
|
|
*
|
|
* HISTORY:
|
|
*
|
|
*/
|
|
RELATE4 * S4FUNCTION relate4retrieve_relate_foo( FILE4SEQ_READ *seq, int open_files, char *spath,
|
|
char *dname_buf, char *iname_buf, char *tname_buf,
|
|
char *str_buf, char *master_expr_buf,
|
|
char *slave_expr_buf, char *tempname_buf )
|
|
{
|
|
RELATE4 *relate = NULL, *master = NULL;
|
|
DATA4 *data;
|
|
TAG4 *tag;
|
|
INDEX4 *index;
|
|
LIST4 indexes;
|
|
CODE4 *c4;
|
|
INAME4 *iname, *nname;
|
|
EXPR4 *expr;
|
|
char alias_buf[11], *cptr;
|
|
short match_len, relation_type, sort_type, error_action, n_links, code;
|
|
int i, err_code, err_flag, repeat_flag, error_code = 0, iindex, tname_err;
|
|
long lExt;
|
|
#ifdef S4CR2
|
|
PN4CHANGE nchange;
|
|
int rc;
|
|
#endif
|
|
|
|
/* reset the changed name list */
|
|
memset( &name_list, 0, sizeof(name_list) );
|
|
|
|
c4 = seq->file->code_base;
|
|
|
|
/* reset the index name list */
|
|
memset( &indexes, 0, sizeof(indexes) );
|
|
err_code = err_flag = 0;
|
|
|
|
while( 1 )
|
|
{
|
|
/* get the data file name */
|
|
if( retrieve4string( seq, dname_buf, 256 ) < 0 )
|
|
{
|
|
/* the error codes are used to allow the continued retrieval of
|
|
the relation tree, even if a part of it is not retrievable due
|
|
to a missing data or index file */
|
|
error_code = 1;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/* get the files alias */
|
|
memset( alias_buf, 0, sizeof(alias_buf) );
|
|
if( file_version >= 0x24 )
|
|
{
|
|
if( retrieve4string( seq, alias_buf, sizeof(alias_buf) ) < 0 )
|
|
{
|
|
error_code = 1;
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
/* retrieve the internal flags of the RELATE4 */
|
|
ret4short( seq, &match_len );
|
|
ret4short( seq, &relation_type );
|
|
ret4short( seq, &sort_type );
|
|
ret4short( seq, &error_action );
|
|
|
|
/* retrieve the names of the index files and place them in the index list
|
|
*/
|
|
ret4short( seq, &n_links );
|
|
for( i = 0; i < n_links; i++ )
|
|
{
|
|
iname = (INAME4 *)u4alloc_free( c4, sizeof(INAME4) );
|
|
if( retrieve4string( seq, iname_buf, 256 ) < 0 )
|
|
{
|
|
error_code = 1;
|
|
goto CLEANUP;
|
|
}
|
|
iname->index_name = (char *)u4alloc_free( c4, strlen(iname_buf) + 1 );
|
|
iname->name_length = strlen(iname_buf) + 1;
|
|
#ifdef S4WINDOWS
|
|
lstrcpy( iname->index_name, iname_buf );
|
|
#else
|
|
strcpy( iname->index_name, iname_buf );
|
|
#endif
|
|
l4add( &indexes, iname );
|
|
}
|
|
|
|
/* get the tag name */
|
|
if( retrieve4string( seq, tname_buf, 256 ) < 0 )
|
|
{
|
|
error_code = 1;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/* retrieve the source for the master expression */
|
|
if( retrieve4string( seq, master_expr_buf, 1024 ) < 0 )
|
|
{
|
|
error_code = 1;
|
|
goto CLEANUP;
|
|
}
|
|
|
|
/* check for changed names */
|
|
cptr = master_expr_buf;
|
|
report4nchange( c4, &cptr, 0, 1024 );
|
|
|
|
/* the code indicates where the new relate should fall in the tree with
|
|
respect to the last relate. The code used is the same as the return
|
|
values from relate4next() */
|
|
ret4short( seq, &code );
|
|
|
|
if( !err_flag && !err_code )
|
|
{
|
|
repeat_flag = 1;
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
/* see if data file is already open */
|
|
data = 0;
|
|
u4name_piece( str_buf, 256, dname_buf, 0, 0 );
|
|
data = d4data( c4, alias_buf );
|
|
/* if not already open try to open */
|
|
if( !data )
|
|
{
|
|
/* if not allowed to open, error */
|
|
if( !open_files )
|
|
{
|
|
e4describe( c4, e4result, E4_RESULT_LCF, dname_buf, (char *)0 );
|
|
err_flag = 1;
|
|
}
|
|
|
|
/* check for an alternate path */
|
|
if( spath && spath[0] != '\0' )
|
|
{
|
|
u4name_piece( str_buf, 256, dname_buf, 0, 1 );
|
|
strcpy( tempname_buf, spath );
|
|
strcat( tempname_buf, "\\" );
|
|
strcat( tempname_buf, str_buf );
|
|
/* open the data file */
|
|
data = r4open_data( tempname_buf, alias_buf, master, c4 );
|
|
}
|
|
else
|
|
{
|
|
/* open the data file */
|
|
data = r4open_data( dname_buf, alias_buf, master, c4 );
|
|
}
|
|
|
|
/* if the open failed */
|
|
if( !data )
|
|
{
|
|
/* if this is for the CR executable interactively get an
|
|
alternate file name */
|
|
#ifdef S4CR2
|
|
nchange = (PN4CHANGE)u4alloc_free( c4, sizeof(N4CHANGE) );
|
|
if( nchange )
|
|
{
|
|
u4name_piece( str_buf, 256, dname_buf, 0, 0 );
|
|
nchange->old_name = (char *)u4alloc_free( c4, strlen(str_buf)+1 );
|
|
if( nchange->old_name )
|
|
{
|
|
strcpy( nchange->old_name, str_buf );
|
|
rc = AlternateDataFile( dname_buf, 256 );
|
|
if( rc == 0 )
|
|
{
|
|
u4name_piece( str_buf, 256, dname_buf, 0, 0 );
|
|
nchange->new_name = (char *)u4alloc_free(c4,strlen(str_buf)+1 );
|
|
if( nchange->new_name )
|
|
{
|
|
strcpy( nchange->new_name, str_buf );
|
|
l4add( &name_list, nchange );
|
|
repeat_flag = 1;
|
|
}
|
|
else
|
|
{
|
|
u4free( nchange->old_name );
|
|
u4free( nchange );
|
|
err_flag = 1;
|
|
}
|
|
}
|
|
else
|
|
err_flag = 1;
|
|
}
|
|
else
|
|
{
|
|
u4free( nchange );
|
|
err_flag = 1;
|
|
}
|
|
}
|
|
else
|
|
err_flag = 1;
|
|
#else
|
|
/* if not in the executable report an error */
|
|
if( spath && spath[0] != '\0' )
|
|
e4describe( c4, e4report, E4_REP_DFILE, tempname_buf, (char *)0 );
|
|
else
|
|
e4describe( c4, e4report, E4_REP_DFILE, dname_buf, (char *)0 );
|
|
err_flag = 1;
|
|
#endif
|
|
}
|
|
e4set( c4, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !err_flag && !err_code )
|
|
{
|
|
/* loop through index file names */
|
|
iname = (INAME4 *)l4first( &indexes );
|
|
while( iname )
|
|
{
|
|
repeat_flag = 1;
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
index = NULL;
|
|
iindex = 0;
|
|
|
|
u4name_piece( str_buf, 256, iname->index_name, 0, 0 );
|
|
tname_err = c4->tag_name_error;
|
|
c4->tag_name_error = 0;
|
|
|
|
/* check to see if the index is already open */
|
|
iindex = r4index_lookup( data, str_buf );
|
|
c4->tag_name_error = tname_err;
|
|
e4set( c4, 0 );
|
|
|
|
/* if not already open */
|
|
if( !iindex )
|
|
{
|
|
/* if not allowed to open files report an error */
|
|
if( !open_files )
|
|
{
|
|
e4describe( c4, e4result, E4_RESULT_LCF, iname_buf, (char *)0 );
|
|
err_flag = 1;
|
|
}
|
|
|
|
/* by default this compile switch is defined in r4report.h
|
|
it forces the index file name to have the default extension
|
|
for the compile flag, regardless of the extension saved in
|
|
the report. IF the user is using a different extension
|
|
he should undefine this switch */
|
|
#ifdef S4DEFAULT_INDEX
|
|
lExt = u4switch();
|
|
if( lExt & 1 )
|
|
u4name_ext( iname->index_name, strlen(iname->index_name)+1, "cdx", 1 );
|
|
else
|
|
if( lExt & 2 )
|
|
u4name_ext( iname->index_name, strlen(iname->index_name)+1, "ntx", 1 );
|
|
else
|
|
if( lExt & 4 )
|
|
u4name_ext( iname->index_name, strlen(iname->index_name)+1, "mdx", 1 );
|
|
else
|
|
if( lExt & 8 )
|
|
u4name_ext( iname->index_name, strlen(iname->index_name)+1, "ndx", 1 );
|
|
#endif
|
|
|
|
/* attempt to open the index file */
|
|
if( spath && spath[0] != '\0' )
|
|
{
|
|
u4name_piece( str_buf, 256, iname->index_name, 0, 1 );
|
|
strcpy( tempname_buf, spath );
|
|
strcat( tempname_buf, "\\" );
|
|
strcat( tempname_buf, str_buf );
|
|
index = i4open( data, tempname_buf );
|
|
}
|
|
else
|
|
index = i4open( data, iname->index_name );
|
|
|
|
/* if open fails */
|
|
if( !index )
|
|
{
|
|
/* if in CR executable prompt for alternate */
|
|
#ifdef S4CR2
|
|
lstrcpy( str_buf, iname->index_name );
|
|
rc = AlternateIndexFile( str_buf, 256 );
|
|
if( rc == 0 )
|
|
{
|
|
repeat_flag = 1;
|
|
u4free( iname->index_name );
|
|
iname->index_name = NULL;
|
|
iname->index_name = (char *)u4alloc( lstrlen(str_buf)+1 );
|
|
if( iname->index_name )
|
|
lstrcpy( iname->index_name, str_buf );
|
|
}
|
|
else
|
|
err_flag = 1;
|
|
#else
|
|
/* report an error */
|
|
if( spath && spath[0] != '\0' )
|
|
e4describe( c4, e4report, E4_REP_IFILE, tempname_buf, (char *)0 );
|
|
else
|
|
e4describe( c4, e4report, E4_REP_IFILE, iname_buf, (char *)0 );
|
|
err_flag = 1;
|
|
#endif
|
|
}
|
|
e4set( c4, 0 );
|
|
}
|
|
}
|
|
iname = (INAME4 *)l4next( &indexes, iname );
|
|
}
|
|
}
|
|
|
|
if( !err_flag && !err_code )
|
|
{
|
|
tag = NULL;
|
|
|
|
/* if this is the first relate do a relate4init() */
|
|
if( !relate )
|
|
{
|
|
master = relate = relate4init( data );
|
|
if( !relate )
|
|
goto CLEANUP;
|
|
|
|
/* set the internal flags */
|
|
relate->match_len = match_len;
|
|
relate->sort_type = sort_type;
|
|
relate->relation_type = relation_type;
|
|
relate->error_action = error_action;
|
|
|
|
/* if a tag was specified set it */
|
|
if( strlen(tname_buf) )
|
|
{
|
|
repeat_flag = 1;
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
tag = NULL;
|
|
tag = d4tag( data, tname_buf );
|
|
if( tag )
|
|
{
|
|
relate->data_tag = tag;
|
|
d4tag_select( data, tag );
|
|
}
|
|
#ifdef S4CR2
|
|
else
|
|
{
|
|
/* if the specified tag is not available and this is the
|
|
.exe prompt for an alternate */
|
|
e4set( c4, 0 );
|
|
rc = AlternateTagName( tname_buf, 256 );
|
|
if( rc == 0 )
|
|
repeat_flag = 1;
|
|
}
|
|
#else
|
|
else
|
|
e4set( c4, 0 );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* if not the first relate do a create slave */
|
|
/* start by getting a tag pointer from the tag name */
|
|
if( strlen(tname_buf) )
|
|
{
|
|
repeat_flag = 1;
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
tag = NULL;
|
|
tag = d4tag( data, tname_buf );
|
|
if( !tag )
|
|
#ifdef S4CR2
|
|
{
|
|
e4set( c4, 0 );
|
|
rc = AlternateTagName( tname_buf, 256 );
|
|
if( rc == 0 )
|
|
repeat_flag = 1;
|
|
else
|
|
{
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
#else
|
|
{
|
|
e4describe( c4, e4report, E4_REP_NOTAG, (char *)tname_buf, 0 );
|
|
e4set( c4, 0 );
|
|
goto CLEANUP;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* try to create the slave */
|
|
repeat_flag = 1;
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
expr = expr4parse( master->data, master_expr_buf );
|
|
if( expr )
|
|
{
|
|
expr4free( expr );
|
|
relate = relate4create_slave( master, data, master_expr_buf, tag );
|
|
}
|
|
#ifdef S4CR2
|
|
else
|
|
{
|
|
/* if create slave fales prompt for a different master expr */
|
|
e4set( c4, 0 );
|
|
rc = AlternateMasterExpression( master_expr_buf, master, 1024 );
|
|
if( rc == 0 )
|
|
repeat_flag = 1;
|
|
else
|
|
relate = NULL;
|
|
}
|
|
#else
|
|
else
|
|
{
|
|
/* report an error */
|
|
e4describe( c4, e4report, E4_REP_NOMEXPR, 0, 0 );
|
|
e4set( c4, 0 );
|
|
relate = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if( !relate )
|
|
goto CLEANUP;
|
|
relate->match_len = match_len;
|
|
relate->sort_type = sort_type;
|
|
relate->relation_type = relation_type;
|
|
relate->error_action = error_action;
|
|
}
|
|
}
|
|
|
|
/* free the index name list */
|
|
iname = (INAME4 *)l4first( &indexes );
|
|
while( iname )
|
|
{
|
|
nname = (INAME4 *)l4next( &indexes, iname );
|
|
l4remove( &indexes, iname );
|
|
u4free( iname->index_name );
|
|
u4free( iname );
|
|
iname = nname;
|
|
}
|
|
|
|
/* if end of relates leave the loop */
|
|
if( code == 2 )
|
|
break;
|
|
|
|
if( err_flag == 0 && err_code > 0 )
|
|
{
|
|
err_code += code;
|
|
if( err_code <= 0 )
|
|
{
|
|
err_code = 0;
|
|
code = 1;
|
|
}
|
|
}
|
|
|
|
if( err_flag == 1 )
|
|
{
|
|
err_flag = 0;
|
|
err_code = 1;
|
|
}
|
|
|
|
if( err_code <= 0 )
|
|
{
|
|
master = relate;
|
|
while( code++ <= 0 )
|
|
master = master->master;
|
|
}
|
|
}
|
|
|
|
/* deal with the sort and query expressions */
|
|
memset( master_expr_buf, 0, 1024 );
|
|
memset( slave_expr_buf, 0, 1024 );
|
|
retrieve4string( seq, master_expr_buf, 1024 );
|
|
cptr = master_expr_buf;
|
|
report4nchange( c4, &cptr, 0, 1024 );
|
|
retrieve4string( seq, slave_expr_buf, 1024 );
|
|
cptr = slave_expr_buf;
|
|
report4nchange( c4, &cptr, 0, 1024 );
|
|
if( master )
|
|
{
|
|
repeat_flag = 1;
|
|
if( strlen( slave_expr_buf) > 0 )
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
expr = expr4parse( master->data, slave_expr_buf );
|
|
if( expr )
|
|
{
|
|
expr4free( expr );
|
|
relate4sort_set( master, slave_expr_buf );
|
|
}
|
|
#ifdef S4CR2
|
|
else
|
|
{
|
|
e4set( c4, 0 );
|
|
rc = AlternateSortExpression( slave_expr_buf, master, 1024 );
|
|
if( rc == 0 )
|
|
repeat_flag = 1;
|
|
}
|
|
#else
|
|
else
|
|
{
|
|
e4describe( c4, e4report, E4_REP_NOSORT, 0, 0 );
|
|
e4set( c4, 0 );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
repeat_flag = 1;
|
|
if( strlen( master_expr_buf ) > 0 )
|
|
while( repeat_flag )
|
|
{
|
|
repeat_flag = 0;
|
|
expr = expr4parse( master->data, master_expr_buf );
|
|
if( expr )
|
|
{
|
|
expr4free( expr );
|
|
relate4query_set( master, master_expr_buf );
|
|
}
|
|
#ifdef S4CR2
|
|
else
|
|
{
|
|
e4set( c4, 0 );
|
|
rc = AlternateQueryExpression( master_expr_buf, master, 1024 );
|
|
if( rc == 0 )
|
|
repeat_flag = 1;
|
|
}
|
|
#else
|
|
else
|
|
{
|
|
e4describe( c4, e4report, E4_REP_NOQUERY, 0, 0 );
|
|
e4set( c4, 0 );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if( relate )
|
|
return( &relate->relation->relate );
|
|
else
|
|
return NULL;
|
|
|
|
CLEANUP:
|
|
iname = (INAME4 *)l4first( &indexes );
|
|
while( iname )
|
|
{
|
|
nname = (INAME4 *)l4next( &indexes, iname );
|
|
l4remove( &indexes, iname );
|
|
u4free( iname->index_name );
|
|
u4free( iname );
|
|
iname = nname;
|
|
}
|
|
|
|
if( master )
|
|
{
|
|
relate4free( master, open_files );
|
|
}
|
|
else
|
|
{
|
|
if( relate )
|
|
relate4free( relate, open_files );
|
|
}
|
|
|
|
if( error_code )
|
|
{
|
|
e4describe( c4, e4report, E4_REP_RELERR, 0, 0 );
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* wrapper for above function */
|
|
RELATE4 * S4FUNCTION relate4retrieve_relate( FILE4SEQ_READ *seq, int open_files, char *spath )
|
|
{
|
|
char *dname_buf = NULL, *iname_buf = NULL, *tname_buf = NULL, *str_buf = NULL;
|
|
char *master_expr_buf = NULL, *slave_expr_buf = NULL, *tempname_buf = NULL;
|
|
RELATE4 *retvalue = NULL;
|
|
|
|
dname_buf = (char *)u4alloc_free( seq->file->code_base, 256 );
|
|
iname_buf = (char *)u4alloc_free( seq->file->code_base, 256 );
|
|
tname_buf = (char *)u4alloc_free( seq->file->code_base, 256 );
|
|
str_buf = (char *)u4alloc_free( seq->file->code_base, 256 );
|
|
master_expr_buf = (char *)u4alloc_free( seq->file->code_base, 1024 );
|
|
slave_expr_buf = (char *)u4alloc_free( seq->file->code_base, 1024 );
|
|
tempname_buf = (char *)u4alloc_free( seq->file->code_base, 512 );
|
|
if( !dname_buf || !iname_buf || !tname_buf || !str_buf ||
|
|
!master_expr_buf || !slave_expr_buf || !tempname_buf )
|
|
goto R4LEAVE;
|
|
|
|
retvalue = relate4retrieve_relate_foo( seq, open_files, spath,
|
|
dname_buf, iname_buf, tname_buf, str_buf, master_expr_buf,
|
|
slave_expr_buf, tempname_buf );
|
|
|
|
R4LEAVE:
|
|
if( dname_buf )
|
|
u4free( dname_buf );
|
|
if( iname_buf )
|
|
u4free( iname_buf );
|
|
if( tname_buf )
|
|
u4free( tname_buf );
|
|
if( str_buf )
|
|
u4free( str_buf );
|
|
if( master_expr_buf )
|
|
u4free( master_expr_buf );
|
|
if( slave_expr_buf )
|
|
u4free( slave_expr_buf );
|
|
if( tempname_buf )
|
|
u4free( tempname_buf );
|
|
|
|
return retvalue;
|
|
|
|
}
|
|
|
|
/* see the CodeReporter manual */
|
|
int S4FUNCTION obj4dataFieldSet( POBJ4 obj, char *fname, char ftype, int flength, int fdec )
|
|
{
|
|
POUT4OBJ oobj;
|
|
PREPORT4 report;
|
|
|
|
if( !obj )
|
|
return -1;
|
|
|
|
report = obj->area->report;
|
|
obj->field_type = ftype;
|
|
obj->field_len = flength;
|
|
obj->field_dec = fdec;
|
|
if( fname )
|
|
u4ncpy( obj->field_name, fname, sizeof(obj->field_name) );
|
|
else
|
|
|
|
oobj = (POUT4OBJ)l4first( &report->output_objs );
|
|
while( oobj )
|
|
{
|
|
if( oobj->obj == obj )
|
|
{
|
|
if( fname == NULL || ftype == 0 || flength == 0 )
|
|
l4remove( &report->output_objs, oobj );
|
|
return 0;
|
|
}
|
|
oobj = (POUT4OBJ)l4next( &report->output_objs, oobj );
|
|
}
|
|
|
|
oobj = (POUT4OBJ)u4alloc_free( obj->area->report->code_base, sizeof(OUT4OBJ) );
|
|
if( !oobj )
|
|
return -1;
|
|
oobj->obj = obj;
|
|
l4add( &report->output_objs, oobj );
|
|
return 0;
|
|
}
|
|
|
|
/* see the CodeReporter manual */
|
|
int S4FUNCTION report4dataFileSet( PREPORT4 report, char *fname )
|
|
{
|
|
if( !report )
|
|
return -1;
|
|
|
|
if( report->dfile_name )
|
|
u4free( report->dfile_name );
|
|
report->dfile_name = NULL;
|
|
|
|
if( fname == NULL )
|
|
return 0;
|
|
|
|
report->dfile_name = (char *)u4alloc_er( report->code_base, strlen(fname)+1 );
|
|
if( !report->dfile_name )
|
|
return -1;
|
|
|
|
u4ncpy( report->dfile_name, fname, strlen(fname)+1 );
|
|
return 0;
|
|
}
|
|
|
|
/* see the CodeReporter manual */
|
|
int S4FUNCTION report4dataGroup( PREPORT4 report, PGROUP4 group )
|
|
{
|
|
if( !report )
|
|
return -1;
|
|
|
|
report->output_group = group;
|
|
return 0;
|
|
}
|