campo-sirio/cb5/m4file.c
alex a0f5e0898b This commit was generated by cvs2svn to compensate for changes in r975,
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
1995-02-06 15:33:45 +00:00

678 lines
17 KiB
C
Executable File

/* 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