678 lines
17 KiB
C
678 lines
17 KiB
C
|
/* m4file.c (c)Copyright Sequiter Software Inc., 1990-1994. All rights reserved. */
|
||
|
|
||
|
#include "d4all.h"
|
||
|
#ifndef S4UNIX
|
||
|
#ifdef __TURBOC__
|
||
|
#pragma hdrstop
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifndef S4MEMO_OFF
|
||
|
|
||
|
#ifndef S4SINGLE
|
||
|
/* ndx/clipper versions have no free chain--do not lock memo file */
|
||
|
#ifndef N4OTHER
|
||
|
/* the lock is forced since a memo file lock only lasts if the .dbf file is locked */
|
||
|
int S4FUNCTION memo4file_lock( MEMO4FILE *f4memo )
|
||
|
{
|
||
|
int rc, old_attempts ;
|
||
|
|
||
|
if ( f4memo->file_lock == 1 )
|
||
|
return 0 ;
|
||
|
|
||
|
if ( f4memo->file.hand == -1 )
|
||
|
return -1 ;
|
||
|
|
||
|
old_attempts = f4memo->file.code_base->lock_attempts ;
|
||
|
f4memo->file.code_base->lock_attempts = -1 ;
|
||
|
|
||
|
#ifdef S4MDX
|
||
|
rc = file4lock( &f4memo->file, L4LOCK_POS - 1L, 2L ) ;
|
||
|
#endif
|
||
|
|
||
|
#ifdef S4FOX
|
||
|
rc = file4lock( &f4memo->file, L4LOCK_POS, 1L ) ;
|
||
|
#endif
|
||
|
|
||
|
f4memo->file.code_base->lock_attempts = old_attempts ;
|
||
|
if ( rc == 0 )
|
||
|
f4memo->file_lock = 1 ;
|
||
|
#ifndef S4OPTIMIZE_OFF
|
||
|
file4refresh( &f4memo->file ) ; /* make sure all up to date */
|
||
|
#endif
|
||
|
return rc ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION memo4file_unlock( MEMO4FILE *f4memo )
|
||
|
{
|
||
|
int rc ;
|
||
|
|
||
|
if ( f4memo->file_lock == 0 )
|
||
|
return 0 ;
|
||
|
#ifdef S4MDX
|
||
|
rc = file4unlock( &f4memo->file, L4LOCK_POS - 1L, 2L ) ;
|
||
|
#endif
|
||
|
#ifdef S4FOX
|
||
|
rc = file4unlock( &f4memo->file, L4LOCK_POS, 1L ) ;
|
||
|
#endif
|
||
|
if ( rc == 0 )
|
||
|
f4memo->file_lock = 0 ;
|
||
|
return rc ;
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
int memo4file_open( MEMO4FILE *f4memo, DATA4 *d4, char *name )
|
||
|
{
|
||
|
MEMO4HEADER header ;
|
||
|
int rc ;
|
||
|
|
||
|
f4memo->data = d4 ;
|
||
|
|
||
|
if ( file4open( &f4memo->file, d4->code_base, name, 1 ) )
|
||
|
return -1 ;
|
||
|
|
||
|
#ifndef S4OPTIMIZE_OFF
|
||
|
file4optimize( &f4memo->file, d4->code_base->optimize, OPT4OTHER ) ;
|
||
|
#endif
|
||
|
|
||
|
if ( (rc = file4read_all(&f4memo->file, 0L, &header, sizeof(header))) < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
header.next_block = x4reverse_long( (void *)&header.next_block ) ;
|
||
|
#ifndef S4MNDX
|
||
|
#ifndef S4MFOX
|
||
|
header.x102 = 0x201 ;
|
||
|
#endif
|
||
|
header.block_size = x4reverse_short( (void *)&header.block_size ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef S4MFOX
|
||
|
f4memo->block_size = x4reverse_short( (void *)&header.block_size ) ;
|
||
|
#else
|
||
|
#ifdef S4MNDX
|
||
|
f4memo->block_size = MEMO4SIZE ;
|
||
|
#else
|
||
|
f4memo->block_size = header.block_size ;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
return rc ;
|
||
|
}
|
||
|
|
||
|
#ifdef S4MFOX
|
||
|
/* offset is # bytes from start of memo that reading should begin, read_max is
|
||
|
the maximum possible that can be read (limited to an unsigned int, so is
|
||
|
16-bit/32-bit compiler dependent.
|
||
|
*/
|
||
|
int memo4file_read_part( MEMO4FILE *f4memo, long memo_id, char **ptr_ptr, unsigned *len_ptr, unsigned long offset, unsigned read_max )
|
||
|
{
|
||
|
unsigned long pos, avail ;
|
||
|
MEMO4BLOCK memo_block ;
|
||
|
|
||
|
if ( memo_id <= 0L )
|
||
|
{
|
||
|
*len_ptr = 0 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
pos = memo_id * f4memo->block_size ;
|
||
|
|
||
|
if ( file4read_all( &f4memo->file, pos, &memo_block, sizeof( MEMO4BLOCK ) ) < 0)
|
||
|
return -1 ;
|
||
|
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
#ifdef S4MFOX
|
||
|
memo_block.type = x4reverse_long( (void *)&memo_block.type ) ;
|
||
|
#else
|
||
|
memo_block.start_pos = x4reverse_short( (void *)&memo_block.start_pos ) ;
|
||
|
#endif
|
||
|
memo_block.num_chars = x4reverse_long( (void *)&memo_block.num_chars ) ;
|
||
|
#endif
|
||
|
|
||
|
memo_block.num_chars = x4reverse_long( (void *)&memo_block.num_chars ) ;
|
||
|
|
||
|
avail = memo_block.num_chars - offset ;
|
||
|
if ( avail > (unsigned long)read_max )
|
||
|
avail = read_max ;
|
||
|
|
||
|
if ( avail > (unsigned long)*len_ptr )
|
||
|
{
|
||
|
if ( *len_ptr > 0 )
|
||
|
u4free( *ptr_ptr ) ;
|
||
|
*ptr_ptr = (char *)u4alloc_er( f4memo->file.code_base, memo_block.num_chars + 1 ) ;
|
||
|
if ( *ptr_ptr == 0 )
|
||
|
return e4memory ;
|
||
|
}
|
||
|
|
||
|
*len_ptr = (unsigned)avail ;
|
||
|
|
||
|
return (int)file4read_all( &f4memo->file, offset + pos + (long)(2*sizeof(S4LONG)), *ptr_ptr, *len_ptr ) ;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int memo4file_read( MEMO4FILE *f4memo, long memo_id, char **ptr_ptr, unsigned *len_ptr )
|
||
|
{
|
||
|
#ifdef S4MFOX
|
||
|
return memo4file_read_part( f4memo, memo_id, ptr_ptr, len_ptr, 0L, UINT_MAX ) ;
|
||
|
#else
|
||
|
long pos ;
|
||
|
#ifdef S4MNDX
|
||
|
long amt_read, read_max, len_read ;
|
||
|
char *t_ptr ;
|
||
|
#else
|
||
|
MEMO4BLOCK memo_block ;
|
||
|
unsigned final_len ;
|
||
|
#endif
|
||
|
|
||
|
if ( memo_id <= 0L )
|
||
|
{
|
||
|
*len_ptr = 0 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
pos = memo_id * f4memo->block_size ;
|
||
|
|
||
|
#ifdef S4MNDX
|
||
|
amt_read = 0 ;
|
||
|
read_max = *len_ptr ;
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
if ( MEMO4SIZE > read_max ) /* must increase the memo buffer size */
|
||
|
{
|
||
|
t_ptr = (char *)u4alloc_er( f4memo->file.code_base, amt_read + MEMO4SIZE + 1 ) ;
|
||
|
if ( t_ptr == 0 )
|
||
|
return e4memory ;
|
||
|
if ( *len_ptr > 0 )
|
||
|
{
|
||
|
memcpy( t_ptr, *ptr_ptr, *len_ptr ) ;
|
||
|
u4free( *ptr_ptr ) ;
|
||
|
}
|
||
|
*ptr_ptr = t_ptr ;
|
||
|
*len_ptr = (unsigned)( amt_read + MEMO4SIZE + 1 ) ;
|
||
|
read_max = MEMO4SIZE ;
|
||
|
}
|
||
|
|
||
|
len_read = file4read( &f4memo->file, pos + amt_read, *ptr_ptr + amt_read, read_max ) ;
|
||
|
if ( len_read <= 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
for ( ; len_read > 0 ; amt_read++, len_read-- )
|
||
|
if ( (*ptr_ptr)[amt_read] == 0x1A ) /* if done */
|
||
|
{
|
||
|
if ( amt_read > 0 )
|
||
|
{
|
||
|
t_ptr = (char *)u4alloc_free( f4memo->file.code_base, amt_read + 1 ) ;
|
||
|
if ( t_ptr == 0 )
|
||
|
{
|
||
|
/* this will result in a correct return, but extra */
|
||
|
/* space is still allocated at end of *ptr_ptr */
|
||
|
*ptr_ptr[amt_read] = 0 ;
|
||
|
*len_ptr = (unsigned)amt_read ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
memcpy( t_ptr, *ptr_ptr, (int)amt_read ) ;
|
||
|
t_ptr[amt_read] = 0 ;
|
||
|
}
|
||
|
else
|
||
|
t_ptr = 0 ;
|
||
|
|
||
|
u4free( *ptr_ptr ) ;
|
||
|
*ptr_ptr = t_ptr ;
|
||
|
*len_ptr = (unsigned)amt_read ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
read_max = 0 ;
|
||
|
}
|
||
|
#else
|
||
|
if ( file4read_all( &f4memo->file, pos, &memo_block, sizeof( MEMO4BLOCK ) ) < 0)
|
||
|
return -1 ;
|
||
|
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
memo_block.start_pos = x4reverse_short( (void *)&memo_block.start_pos ) ;
|
||
|
memo_block.num_chars = x4reverse_long( (void *)&memo_block.num_chars ) ;
|
||
|
#endif
|
||
|
|
||
|
if ( memo_block.minus_one != -1 ) /* must be an invalid entry, so return an empty entry */
|
||
|
{
|
||
|
*len_ptr = 0 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( memo_block.num_chars >= USHRT_MAX )
|
||
|
return e4( f4memo->file.code_base, e4info, E4_MEMO4FILE_RD ) ;
|
||
|
|
||
|
final_len = (unsigned)memo_block.num_chars - 2 * ( sizeof(short) ) - ( sizeof(S4LONG) ) ;
|
||
|
if ( final_len > *len_ptr )
|
||
|
{
|
||
|
if ( *len_ptr > 0 )
|
||
|
u4free( *ptr_ptr ) ;
|
||
|
*ptr_ptr = (char *)u4alloc_er( f4memo->file.code_base, final_len + 1 ) ;
|
||
|
if ( *ptr_ptr == 0 )
|
||
|
return e4memory ;
|
||
|
}
|
||
|
*len_ptr = final_len ;
|
||
|
|
||
|
return file4read_all( &f4memo->file, pos+ memo_block.start_pos, *ptr_ptr, final_len ) ;
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef S4MFOX
|
||
|
/* Writes partial data to a memo record.
|
||
|
Usage rules:
|
||
|
Must call this function with an offset == 0 to write 1st part of block
|
||
|
before any additional writing. In addition, the memo_len must be
|
||
|
accurately set during the first call in order to reserve the correct
|
||
|
amount of memo space ahead of time. Later calls just fill in data to
|
||
|
the reserved disk space.
|
||
|
len_write is the amount of data to write, offset is the number of
|
||
|
bytes from the beginning of the memo in which to write the data
|
||
|
Secondary calls to this function assume that everything has been
|
||
|
previously set up, and merely performs a file write to the reserved
|
||
|
space. The space is not checked to see whether or not it actually
|
||
|
is in the bounds specified, so use with care.
|
||
|
*/
|
||
|
int memo4file_write_part( MEMO4FILE *f4memo, long *memo_id_ptr, char *ptr, long memo_len, long offset, unsigned len_write )
|
||
|
{
|
||
|
int str_num_blocks ;
|
||
|
long pos ;
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
int rc, lock_cond ;
|
||
|
#endif
|
||
|
#endif
|
||
|
MEMO4BLOCK old_memo_block ;
|
||
|
MEMO4HEADER mh ;
|
||
|
unsigned len_read ;
|
||
|
long block_no ;
|
||
|
unsigned n_entry_blks = 0 ;
|
||
|
|
||
|
|
||
|
#ifdef S4DEBUG
|
||
|
if ( memo_id_ptr == 0 )
|
||
|
e4severe( e4parm, E4_MEMO4FILE_WR ) ;
|
||
|
#endif
|
||
|
|
||
|
if ( offset == 0 ) /* must do the set-up work */
|
||
|
{
|
||
|
if ( memo_len == 0 )
|
||
|
{
|
||
|
*memo_id_ptr = 0L ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
#ifdef S4DEBUG
|
||
|
if ( f4memo->block_size <= 1 )
|
||
|
e4severe( e4info, E4_INFO_IMS ) ;
|
||
|
#endif
|
||
|
|
||
|
str_num_blocks = (int) ((memo_len + sizeof(MEMO4BLOCK) + f4memo->block_size-1) / f4memo->block_size) ;
|
||
|
if ( *memo_id_ptr <= 0L )
|
||
|
block_no = 0L ;
|
||
|
else
|
||
|
{
|
||
|
block_no = *memo_id_ptr ;
|
||
|
pos = block_no * f4memo->block_size ;
|
||
|
|
||
|
file4read_all( &f4memo->file, pos, (char *)&old_memo_block, sizeof(old_memo_block) ) ;
|
||
|
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
#ifdef S4MFOX
|
||
|
old_memo_block.type = x4reverse_long( (void *)&old_memo_block.type ) ;
|
||
|
#else
|
||
|
old_memo_block.start_pos = x4reverse_short( (void *)&old_memo_block.start_pos ) ;
|
||
|
#endif
|
||
|
old_memo_block.num_chars = x4reverse_long( (void *)&old_memo_block.num_chars ) ;
|
||
|
#endif
|
||
|
|
||
|
old_memo_block.num_chars = x4reverse_long( (void *)&old_memo_block.num_chars ) ;
|
||
|
n_entry_blks = (unsigned) ((old_memo_block.num_chars + f4memo->block_size-1)/ f4memo->block_size ) ;
|
||
|
}
|
||
|
if ( n_entry_blks >= ((unsigned)str_num_blocks) && block_no ) /* write to existing position */
|
||
|
*memo_id_ptr = block_no ;
|
||
|
else /* read in header record */
|
||
|
{
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
lock_cond = f4memo->data->memo_file.file_lock ;
|
||
|
rc = memo4file_lock( &f4memo->data->memo_file ) ;
|
||
|
if ( rc )
|
||
|
return rc ;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
len_read = file4read( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
mh.next_block = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
mh.block_size = x4reverse_short( (void *)&mh.block_size ) ;
|
||
|
#endif
|
||
|
|
||
|
if ( f4memo->data->code_base->error_code < 0 )
|
||
|
{
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
if ( !lock_cond )
|
||
|
memo4file_unlock( &f4memo->data->memo_file ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
return -1 ;
|
||
|
}
|
||
|
|
||
|
if ( len_read != sizeof( mh ) )
|
||
|
{
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
if ( !lock_cond )
|
||
|
memo4file_unlock( &f4memo->data->memo_file ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
return file4read_error( &f4memo->file ) ;
|
||
|
}
|
||
|
|
||
|
*memo_id_ptr = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
mh.next_block = *memo_id_ptr + str_num_blocks ;
|
||
|
mh.next_block = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
mh.next_block = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
mh.block_size = x4reverse_short( (void *)&mh.block_size ) ;
|
||
|
#endif
|
||
|
|
||
|
file4write( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
|
||
|
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
if ( !lock_cond )
|
||
|
memo4file_unlock( &f4memo->data->memo_file ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
if ( memo4file_dump( f4memo, *memo_id_ptr, ptr, len_write ) < 0 )
|
||
|
return -1 ;
|
||
|
}
|
||
|
else
|
||
|
return file4write( &f4memo->file, *memo_id_ptr * f4memo->block_size + offset, ptr, len_write ) ;
|
||
|
|
||
|
return 0 ;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int memo4file_write( MEMO4FILE *f4memo, long *memo_id_ptr, char *ptr, unsigned ptr_len )
|
||
|
{
|
||
|
#ifdef S4MFOX
|
||
|
return memo4file_write_part( f4memo, memo_id_ptr, ptr, ptr_len, 0L, ptr_len ) ;
|
||
|
#else
|
||
|
int str_num_blocks ;
|
||
|
long pos ;
|
||
|
#ifndef S4MDX
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
int rc, lock_cond ;
|
||
|
#endif
|
||
|
#endif
|
||
|
#endif
|
||
|
#ifdef S4MNDX
|
||
|
MEMO4HEADER mh ;
|
||
|
long len_read ;
|
||
|
char buf[MEMO4SIZE] ;
|
||
|
int read_size, i ;
|
||
|
#else
|
||
|
MEMO4BLOCK old_memo_block ;
|
||
|
MEMO4CHAIN_ENTRY new_entry, cur, prev ;
|
||
|
int str_written ;
|
||
|
long prev_prev_entry, prev_prev_num ;
|
||
|
long file_len, extra_len ;
|
||
|
#endif
|
||
|
|
||
|
#ifdef S4DEBUG
|
||
|
if ( memo_id_ptr == 0 )
|
||
|
e4severe( e4parm, E4_MEMO4FILE_WR ) ;
|
||
|
#endif
|
||
|
|
||
|
#ifdef S4MNDX
|
||
|
if ( ptr_len == 0 )
|
||
|
{
|
||
|
*memo_id_ptr = 0L ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
str_num_blocks = (ptr_len + f4memo->block_size-1) / f4memo->block_size ;
|
||
|
|
||
|
if ( *memo_id_ptr <= 0L )
|
||
|
*memo_id_ptr = 0L ;
|
||
|
else /* read in old record to see if new entry can fit */
|
||
|
{
|
||
|
read_size = 0 ;
|
||
|
pos = *memo_id_ptr * f4memo->block_size ;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
read_size += MEMO4SIZE ;
|
||
|
|
||
|
len_read = file4read( &f4memo->file, pos, buf, MEMO4SIZE ) ;
|
||
|
if ( len_read <= 0 )
|
||
|
return file4read_error( &f4memo->file ) ;
|
||
|
|
||
|
for ( i=0 ; ((unsigned) i) < len_read ; i++ )
|
||
|
if ( buf[i] == (char)0x1A ) break ;
|
||
|
|
||
|
#ifdef S4DEBUG
|
||
|
if ( buf[i] != (char)0x1A && len_read != MEMO4SIZE )
|
||
|
return e4( f4memo->file.code_base, e4info, E4_INFO_CMF ) ;
|
||
|
#endif
|
||
|
|
||
|
pos += MEMO4SIZE ;
|
||
|
} while ( i >= MEMO4SIZE && buf[i] != (char) 0x1A ) ; /* Continue if Esc is not located */
|
||
|
|
||
|
if ( ((unsigned)read_size) <= ptr_len ) /* there is not room */
|
||
|
*memo_id_ptr = 0 ;
|
||
|
}
|
||
|
|
||
|
if ( *memo_id_ptr == 0 ) /* add entry at eof */
|
||
|
{
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
lock_cond = f4memo->data->memo_file.file_lock ;
|
||
|
rc = memo4file_lock( &f4memo->data->memo_file ) ;
|
||
|
if ( rc )
|
||
|
return rc ;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
len_read = file4read( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
mh.next_block = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
#endif
|
||
|
if ( f4memo->data->code_base->error_code < 0 )
|
||
|
{
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
if ( !lock_cond )
|
||
|
memo4file_unlock( &f4memo->data->memo_file ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
return -1 ;
|
||
|
}
|
||
|
|
||
|
if ( len_read != sizeof( mh ) )
|
||
|
{
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
if ( !lock_cond )
|
||
|
memo4file_unlock( &f4memo->data->memo_file ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
return file4read_error( &f4memo->file ) ;
|
||
|
}
|
||
|
|
||
|
*memo_id_ptr = mh.next_block ;
|
||
|
mh.next_block = *memo_id_ptr + str_num_blocks ;
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
mh.next_block = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
#endif
|
||
|
|
||
|
file4write( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
|
||
|
|
||
|
#ifndef S4SINGLE
|
||
|
#ifndef N4OTHER
|
||
|
if ( !lock_cond )
|
||
|
memo4file_unlock( &f4memo->data->memo_file ) ;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
mh.next_block = x4reverse_long( (void *)&mh.next_block ) ;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( memo4file_dump( f4memo, *memo_id_ptr, ptr, ptr_len ) < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
return 0 ;
|
||
|
#else
|
||
|
/* S4MMDX */
|
||
|
memset( (void *)&new_entry, 0, sizeof(new_entry) ) ;
|
||
|
new_entry.block_no = *memo_id_ptr ;
|
||
|
|
||
|
str_written = 0 ;
|
||
|
if ( ptr_len == 0 )
|
||
|
{
|
||
|
str_written = 1 ;
|
||
|
*memo_id_ptr = 0 ;
|
||
|
}
|
||
|
|
||
|
/* Initialize information about the old memo entry */
|
||
|
if ( new_entry.block_no <= 0L )
|
||
|
{
|
||
|
if ( str_written )
|
||
|
{
|
||
|
*memo_id_ptr = 0L ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
new_entry.num = 0 ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pos = new_entry.block_no * f4memo->block_size ;
|
||
|
|
||
|
file4read_all( &f4memo->file, pos, (char *)&old_memo_block, sizeof(old_memo_block) ) ;
|
||
|
#ifdef S4BYTE_SWAP
|
||
|
old_memo_block.start_pos = x4reverse_short( (void *)&old_memo_block.start_pos ) ;
|
||
|
old_memo_block.num_chars = x4reverse_long( (void *)&old_memo_block.num_chars ) ;
|
||
|
#endif
|
||
|
|
||
|
new_entry.num = ((unsigned)old_memo_block.num_chars + f4memo->block_size-1)/ f4memo->block_size ;
|
||
|
}
|
||
|
|
||
|
str_num_blocks = (ptr_len+2*(sizeof(short))+(sizeof(S4LONG))+ f4memo->block_size-1) / f4memo->block_size ;
|
||
|
|
||
|
if ( new_entry.num >= str_num_blocks && !str_written )
|
||
|
{
|
||
|
*memo_id_ptr = new_entry.block_no + new_entry.num - str_num_blocks ;
|
||
|
if ( memo4file_dump( f4memo, *memo_id_ptr, ptr, ptr_len ) < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
str_written = 1 ;
|
||
|
if ( new_entry.num == str_num_blocks )
|
||
|
return 0 ;
|
||
|
|
||
|
new_entry.num -= str_num_blocks ;
|
||
|
}
|
||
|
|
||
|
/* Initialize 'chain' */
|
||
|
memset( (void *)&cur, 0, sizeof(cur) ) ;
|
||
|
memset( (void *)&prev, 0, sizeof(prev) ) ;
|
||
|
|
||
|
for(;;)
|
||
|
{
|
||
|
if ( f4memo->data->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
memo4file_chain_flush( f4memo, &prev ) ;
|
||
|
prev_prev_entry = prev.block_no ;
|
||
|
prev_prev_num = prev.num ;
|
||
|
|
||
|
memcpy( (void *)&prev, (void *)&cur, sizeof(prev) ) ;
|
||
|
|
||
|
if ( new_entry.block_no > 0 && prev.next > new_entry.block_no )
|
||
|
{
|
||
|
/* See if the new entry fits in here */
|
||
|
memcpy( (void *)&cur, (void *)&new_entry, sizeof(cur) ) ;
|
||
|
new_entry.block_no = 0 ;
|
||
|
cur.next = prev.next ;
|
||
|
prev.next = cur.block_no ;
|
||
|
cur.to_disk = prev.to_disk = 1 ;
|
||
|
}
|
||
|
else
|
||
|
memo4file_chain_skip( f4memo, &cur ) ;
|
||
|
|
||
|
/* See if the entries can be combined. */
|
||
|
if ( prev.block_no + prev.num == cur.block_no && prev.num )
|
||
|
{
|
||
|
/* 'cur' becomes the combined groups. */
|
||
|
prev.to_disk = 0 ;
|
||
|
cur.to_disk = 1 ;
|
||
|
|
||
|
cur.block_no = prev.block_no ;
|
||
|
if ( cur.num >= 0 )
|
||
|
cur.num += prev.num ;
|
||
|
prev.block_no = prev_prev_entry ;
|
||
|
prev.num = prev_prev_num ;
|
||
|
}
|
||
|
|
||
|
if ( str_written )
|
||
|
{
|
||
|
if ( new_entry.block_no == 0 )
|
||
|
{
|
||
|
memo4file_chain_flush( f4memo, &prev ) ;
|
||
|
memo4file_chain_flush( f4memo, &cur ) ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
}
|
||
|
else /* 'str' is not yet written, try the current entry */
|
||
|
{
|
||
|
if ( cur.next == -1 ) /* End of file */
|
||
|
cur.num = str_num_blocks ;
|
||
|
|
||
|
if ( cur.num >= str_num_blocks )
|
||
|
{
|
||
|
cur.num -= str_num_blocks ;
|
||
|
*memo_id_ptr = cur.block_no + cur.num ;
|
||
|
memo4file_dump( f4memo, *memo_id_ptr, ptr, ptr_len ) ;
|
||
|
if ( cur.next == -1 ) /* if end of file */
|
||
|
{
|
||
|
/* For dBASE IV compatibility */
|
||
|
file_len = file4len( &f4memo->file ) ;
|
||
|
extra_len = f4memo->block_size - file_len % f4memo->block_size ;
|
||
|
if ( extra_len != f4memo->block_size )
|
||
|
file4len_set( &f4memo->file, file_len+extra_len ) ;
|
||
|
}
|
||
|
|
||
|
str_written = 1 ;
|
||
|
|
||
|
if ( cur.num == 0 )
|
||
|
{
|
||
|
if ( cur.next == -1 ) /* End of file */
|
||
|
prev.next = cur.block_no + str_num_blocks ;
|
||
|
else
|
||
|
prev.next = cur.next ;
|
||
|
prev.to_disk = 1 ;
|
||
|
cur.to_disk = 0 ;
|
||
|
}
|
||
|
else
|
||
|
cur.to_disk = 1 ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|