723 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			723 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* m4file.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved.  */
 | 
						|
 | 
						|
#include "d4all.h"
 | 
						|
#ifndef S4UNIX
 | 
						|
   #ifdef __TURBOC__
 | 
						|
      #pragma hdrstop
 | 
						|
   #endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
#ifndef S4MEMO_OFF
 | 
						|
 | 
						|
#ifndef S4OFF_MULTI
 | 
						|
  /* 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 memo4fileLock( MEMO4FILE *f4memo )
 | 
						|
{
 | 
						|
   int rc, oldAttempts ;
 | 
						|
 | 
						|
   if ( f4memo->fileLock == 1 )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   if ( f4memo->file.hand == -1 )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
   oldAttempts = f4memo->file.codeBase->lockAttempts ;
 | 
						|
   f4memo->file.codeBase->lockAttempts = WAIT4EVER ;
 | 
						|
 | 
						|
   #ifdef S4MDX
 | 
						|
      rc = file4lock( &f4memo->file, L4LOCK_POS - 1L, 2L ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4FOX
 | 
						|
      rc = file4lock( &f4memo->file, L4LOCK_POS_OLD, 1L ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   f4memo->file.codeBase->lockAttempts = oldAttempts ;
 | 
						|
   if ( rc == 0 )
 | 
						|
      f4memo->fileLock = 1 ;
 | 
						|
   #ifndef S4OPTIMIZE_OFF
 | 
						|
      file4refresh( &f4memo->file ) ;   /* make sure all up to date */
 | 
						|
   #endif
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
int memo4fileUnlock( MEMO4FILE *f4memo )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   if ( f4memo->fileLock == 0 )
 | 
						|
      return 0 ;
 | 
						|
   #ifdef S4MDX
 | 
						|
      rc = file4unlock( &f4memo->file, L4LOCK_POS - 1L, 2L ) ;
 | 
						|
   #endif
 | 
						|
   #ifdef S4FOX
 | 
						|
      rc = file4unlock( &f4memo->file, L4LOCK_POS_OLD, 1L ) ;
 | 
						|
   #endif
 | 
						|
   if ( rc == 0 )
 | 
						|
      f4memo->fileLock = 0 ;
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
int memo4fileOpen( MEMO4FILE *f4memo, DATA4FILE *d4, char *name )
 | 
						|
{
 | 
						|
   MEMO4HEADER  header ;
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   f4memo->data = d4 ;
 | 
						|
 | 
						|
   if ( file4open( &f4memo->file, d4->c4, name, 1 ) )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
   #ifndef S4OPTIMIZE_OFF
 | 
						|
      file4optimize( &f4memo->file, d4->c4->optimize, OPT4OTHER ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( (rc = file4readAll(&f4memo->file, 0L, &header, sizeof(header))) < 0 )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
   #ifdef S4BYTE_SWAP
 | 
						|
      header.nextBlock = x4reverseLong( (void *)&header.nextBlock ) ;
 | 
						|
      #ifndef S4MNDX
 | 
						|
         #ifndef S4MFOX
 | 
						|
            header.x102 = 0x201 ;
 | 
						|
         #endif
 | 
						|
         header.blockSize = x4reverseShort( (void *)&header.blockSize ) ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4MFOX
 | 
						|
      f4memo->blockSize = x4reverseShort( (void *)&header.blockSize ) ;
 | 
						|
   #else
 | 
						|
      #ifdef S4MNDX
 | 
						|
         f4memo->blockSize = MEMO4SIZE ;
 | 
						|
      #else
 | 
						|
         f4memo->blockSize = header.blockSize ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef S4MFOX
 | 
						|
/* offset is # bytes from start of memo that reading should begin, readMax is
 | 
						|
   the maximum possible that can be read (limited to an unsigned int, so is
 | 
						|
   16-bit/32-bit compiler dependent.
 | 
						|
*/
 | 
						|
int memo4fileReadPart( MEMO4FILE *f4memo, long memoId, char **ptrPtr, unsigned *lenPtr, unsigned long offset, const unsigned readMax, long *type )
 | 
						|
{
 | 
						|
   unsigned long pos, avail ;
 | 
						|
   MEMO4BLOCK memoBlock ;
 | 
						|
 | 
						|
   if ( memoId <= 0L )
 | 
						|
   {
 | 
						|
      *lenPtr = 0 ;
 | 
						|
      return 0 ;
 | 
						|
   }
 | 
						|
 | 
						|
   pos = (unsigned long)memoId * f4memo->blockSize ;
 | 
						|
 | 
						|
   if ( file4readAll( &f4memo->file, pos, &memoBlock, sizeof( MEMO4BLOCK ) ) < 0)
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
   #ifdef S4BYTE_SWAP
 | 
						|
      #ifdef S4MFOX
 | 
						|
         memoBlock.type = x4reverseLong( (void *)&memoBlock.type ) ;
 | 
						|
      #else
 | 
						|
         memoBlock.startPos = x4reverseShort( (void *)&memoBlock.startPos ) ;
 | 
						|
      #endif
 | 
						|
      memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
 | 
						|
 | 
						|
   avail = memoBlock.numChars - offset ;
 | 
						|
   if ( avail > (unsigned long)readMax )
 | 
						|
      avail = readMax ;
 | 
						|
 | 
						|
   if ( avail > (unsigned long)*lenPtr )
 | 
						|
   {
 | 
						|
      if ( *lenPtr > 0 )
 | 
						|
         u4free( *ptrPtr ) ;
 | 
						|
      *ptrPtr = (char *)u4allocEr( f4memo->file.codeBase, avail + 1 ) ;
 | 
						|
      if ( *ptrPtr == 0 )
 | 
						|
         return e4memory ;
 | 
						|
   }
 | 
						|
 | 
						|
   *lenPtr = (unsigned)avail ;
 | 
						|
   *type = x4reverseLong( &memoBlock.type ) ;
 | 
						|
 | 
						|
   return (int)file4readAll( &f4memo->file, offset + pos + (long)(2*sizeof(S4LONG)), *ptrPtr, *lenPtr ) ;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4MNDX
 | 
						|
   extern char f4memoNullChar ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4MFOX
 | 
						|
int memo4fileRead( MEMO4FILE *f4memo, long memoId, char **ptrPtr, unsigned int *ptrLen, long *mType )
 | 
						|
#else
 | 
						|
int memo4fileRead( MEMO4FILE *f4memo, long memoId, char **ptrPtr, unsigned int *ptrLen )
 | 
						|
#endif
 | 
						|
{
 | 
						|
   #ifdef S4MFOX
 | 
						|
      return memo4fileReadPart( f4memo, memoId, ptrPtr, ptrLen, 0L, UINT_MAX -100, mType ) ;
 | 
						|
   #else
 | 
						|
      long pos ;
 | 
						|
      CODE4 *c4 ;
 | 
						|
      #ifdef S4MNDX
 | 
						|
         unsigned int amtRead, lenRead, loop ;
 | 
						|
         char *tPtr ;
 | 
						|
      #else
 | 
						|
         MEMO4BLOCK  memoBlock ;
 | 
						|
         unsigned finalLen ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      c4 = f4memo->file.codeBase ;
 | 
						|
 | 
						|
      #ifdef S4MNDX
 | 
						|
         if ( memoId <= 0L )
 | 
						|
         {
 | 
						|
            if ( *ptrPtr != &f4memoNullChar )
 | 
						|
               u4free( *ptrPtr ) ;
 | 
						|
            *ptrPtr = 0 ;
 | 
						|
            *ptrLen = 0 ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
 | 
						|
         pos = memoId * f4memo->blockSize ;
 | 
						|
 | 
						|
         amtRead = 0 ;
 | 
						|
 | 
						|
         if ( c4->memoUseBuffer == 0 )
 | 
						|
         {
 | 
						|
            c4->memoUseBuffer = (char*)u4allocEr( c4, MEMO4SIZE ) ;
 | 
						|
            if ( c4->memoUseBuffer == 0 )
 | 
						|
               return e4memory ;
 | 
						|
         }
 | 
						|
 | 
						|
         for( amtRead = 0 ;; )
 | 
						|
         {
 | 
						|
            lenRead = file4read( &f4memo->file, pos + amtRead, c4->memoUseBuffer, MEMO4SIZE ) ;
 | 
						|
            if ( lenRead <= 0 )
 | 
						|
               return -1 ;
 | 
						|
 | 
						|
            for ( loop = 0 ; lenRead > 0 ; loop++, lenRead-- )
 | 
						|
            {
 | 
						|
               if ( c4->memoUseBuffer[loop] == 0x1A ) /* if done */
 | 
						|
               {
 | 
						|
                  if ( loop + amtRead > 0 )
 | 
						|
                  {
 | 
						|
                     if ( *ptrLen < amtRead + loop )
 | 
						|
                     {
 | 
						|
                        tPtr = (char *)u4allocEr( c4, amtRead + loop + 1 ) ;
 | 
						|
                        if ( tPtr == 0 )
 | 
						|
                           return e4memory ;
 | 
						|
                        memcpy( tPtr, *ptrPtr, (int)amtRead ) ;
 | 
						|
                        if ( *ptrPtr != &f4memoNullChar )
 | 
						|
                           u4free( *ptrPtr ) ;
 | 
						|
                        *ptrPtr = tPtr ;
 | 
						|
                     }
 | 
						|
                     *ptrLen = amtRead + loop ;
 | 
						|
                     memcpy( *ptrPtr + amtRead, c4->memoUseBuffer, loop ) ;
 | 
						|
                     (*ptrPtr)[amtRead+loop] = 0 ;
 | 
						|
                     return 0 ;
 | 
						|
                  }
 | 
						|
                  else
 | 
						|
                  {
 | 
						|
                     tPtr = 0 ;
 | 
						|
                     if ( *ptrPtr != &f4memoNullChar )
 | 
						|
                        u4free( *ptrPtr ) ;
 | 
						|
                     *ptrPtr = 0 ;
 | 
						|
                     *ptrLen = 0 ;
 | 
						|
                  }
 | 
						|
                  return 0 ;
 | 
						|
               }
 | 
						|
            }
 | 
						|
 | 
						|
            lenRead = loop ;
 | 
						|
 | 
						|
            if ( *ptrLen < amtRead + lenRead )
 | 
						|
            {
 | 
						|
               tPtr = (char *)u4allocEr( c4, amtRead + lenRead + 1 ) ;
 | 
						|
               if ( tPtr == 0 )
 | 
						|
                  return e4memory ;
 | 
						|
               if ( *ptrLen > 0 )
 | 
						|
               {
 | 
						|
                  memcpy( tPtr, *ptrPtr, *ptrLen ) ;
 | 
						|
                  u4free( *ptrPtr ) ;
 | 
						|
               }
 | 
						|
               *ptrPtr = tPtr ;
 | 
						|
               *ptrLen = (unsigned)( amtRead + lenRead ) ;
 | 
						|
            }
 | 
						|
            memcpy( *ptrPtr + amtRead, c4->memoUseBuffer, lenRead ) ;
 | 
						|
 | 
						|
            amtRead += lenRead ;
 | 
						|
         }
 | 
						|
      #else
 | 
						|
         if ( memoId <= 0L )
 | 
						|
         {
 | 
						|
            *ptrLen = 0 ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
 | 
						|
         pos = memoId * f4memo->blockSize ;
 | 
						|
 | 
						|
         if ( file4readAll( &f4memo->file, pos, &memoBlock, sizeof( MEMO4BLOCK ) ) < 0)
 | 
						|
            return -1 ;
 | 
						|
 | 
						|
         #ifdef S4BYTE_SWAP
 | 
						|
            memoBlock.startPos = x4reverseShort( (void *)&memoBlock.startPos ) ;
 | 
						|
            memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
 | 
						|
         #endif
 | 
						|
 | 
						|
         if ( memoBlock.minusOne != -1 )  /* must be an invalid entry, so return an empty entry */
 | 
						|
         {
 | 
						|
            *ptrLen = 0 ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
         {
 | 
						|
            if ( memoBlock.numChars >= UINT_MAX )
 | 
						|
               return error4( c4, e4info, E95210 ) ;
 | 
						|
 | 
						|
            finalLen = (unsigned)memoBlock.numChars - 2 * ( sizeof(short) ) - ( sizeof(S4LONG) ) ;
 | 
						|
            if ( finalLen > *ptrLen )
 | 
						|
            {
 | 
						|
               if ( *ptrLen > 0 )
 | 
						|
                  u4free( *ptrPtr ) ;
 | 
						|
               *ptrPtr = (char *)u4allocEr( c4, finalLen + 1 ) ;
 | 
						|
               if ( *ptrPtr == 0 )
 | 
						|
                  return e4memory ;
 | 
						|
            }
 | 
						|
            *ptrLen = finalLen ;
 | 
						|
 | 
						|
            return file4readAll( &f4memo->file, pos+ memoBlock.startPos, *ptrPtr, finalLen ) ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4OFF_WRITE
 | 
						|
#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 memoLen 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.
 | 
						|
      lenWrite 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 memo4fileWritePart( MEMO4FILE *f4memo, long *memoIdPtr, const char *ptr, const long memoLen, const long offset, const unsigned lenWrite, const long type )
 | 
						|
{
 | 
						|
   int strNumBlocks ;
 | 
						|
   long pos ;
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      #ifndef N4OTHER
 | 
						|
         int rc, lockCond ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
   MEMO4BLOCK oldMemoBlock ;
 | 
						|
   MEMO4HEADER mh ;
 | 
						|
   unsigned lenRead ;
 | 
						|
   long blockNo ;
 | 
						|
   unsigned nEntryBlks = 0 ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( memoIdPtr == 0 )
 | 
						|
         return error4( 0, e4parm_null, E95208 ) ;
 | 
						|
      if ( f4memo->file.hand == -1 ) /* file closed! */
 | 
						|
         return error4( 0, e4parm, E95208 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( offset == 0 )   /* must do the set-up work */
 | 
						|
   {
 | 
						|
      if ( memoLen == 0 )
 | 
						|
      {
 | 
						|
         *memoIdPtr = 0L ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
 | 
						|
      #ifdef E4MISC
 | 
						|
         if ( f4memo->blockSize <= 1 )
 | 
						|
            return error4( f4memo->data->c4, e4info, E85202 ) ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      strNumBlocks = (int) ((memoLen + sizeof(MEMO4BLOCK) + f4memo->blockSize-1) / f4memo->blockSize) ;
 | 
						|
      if ( *memoIdPtr <= 0L )
 | 
						|
         blockNo = 0L ;
 | 
						|
      else
 | 
						|
      {
 | 
						|
         blockNo = *memoIdPtr ;
 | 
						|
         pos = blockNo * f4memo->blockSize ;
 | 
						|
 | 
						|
         file4readAll( &f4memo->file, pos, (char *)&oldMemoBlock, sizeof(oldMemoBlock) ) ;
 | 
						|
 | 
						|
         #ifdef S4BYTE_SWAP
 | 
						|
            #ifdef S4MFOX
 | 
						|
               oldMemoBlock.type = x4reverseLong( (void *)&oldMemoBlock.type ) ;
 | 
						|
            #else
 | 
						|
               oldMemoBlock.startPos = x4reverseShort( (void *)&oldMemoBlock.startPos ) ;
 | 
						|
            #endif
 | 
						|
            oldMemoBlock.numChars = x4reverseLong( (void *)&oldMemoBlock.numChars ) ;
 | 
						|
         #endif
 | 
						|
 | 
						|
         oldMemoBlock.numChars = x4reverseLong( (void *)&oldMemoBlock.numChars ) ;
 | 
						|
         nEntryBlks = (unsigned) ((oldMemoBlock.numChars + f4memo->blockSize-1)/ f4memo->blockSize ) ;
 | 
						|
      }
 | 
						|
      if ( nEntryBlks >= ((unsigned)strNumBlocks) && blockNo )  /* write to existing position */
 | 
						|
         *memoIdPtr = blockNo ;
 | 
						|
      else  /* read in header record */
 | 
						|
      {
 | 
						|
         #ifndef S4OFF_MULTI
 | 
						|
         #ifndef N4OTHER
 | 
						|
            lockCond = f4memo->data->memoFile.fileLock ;
 | 
						|
            rc = memo4fileLock( &f4memo->data->memoFile ) ;
 | 
						|
            if ( rc )
 | 
						|
               return rc ;
 | 
						|
         #endif
 | 
						|
         #endif
 | 
						|
 | 
						|
         lenRead = file4read( &f4memo->file, 0L, &mh, sizeof( mh ) ) ;
 | 
						|
         #ifdef S4BYTE_SWAP
 | 
						|
            mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
            mh.blockSize = x4reverseShort( (void *)&mh.blockSize ) ;
 | 
						|
         #endif
 | 
						|
 | 
						|
         if ( error4code( f4memo->data->c4 ) < 0 )
 | 
						|
         {
 | 
						|
            #ifndef S4OFF_MULTI
 | 
						|
            #ifndef N4OTHER
 | 
						|
               if ( !lockCond )
 | 
						|
                  memo4fileUnlock( &f4memo->data->memoFile ) ;
 | 
						|
            #endif
 | 
						|
            #endif
 | 
						|
            return -1 ;
 | 
						|
         }
 | 
						|
 | 
						|
         if ( lenRead != sizeof( mh ) )
 | 
						|
         {
 | 
						|
            #ifndef S4OFF_MULTI
 | 
						|
            #ifndef N4OTHER
 | 
						|
               if ( !lockCond )
 | 
						|
                  memo4fileUnlock( &f4memo->data->memoFile ) ;
 | 
						|
            #endif
 | 
						|
            #endif
 | 
						|
            return file4readError( &f4memo->file, 0L, sizeof( mh ), "memo4fileWritePart" ) ;
 | 
						|
         }
 | 
						|
 | 
						|
         *memoIdPtr = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
         mh.nextBlock = *memoIdPtr + strNumBlocks ;
 | 
						|
         mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
 | 
						|
         #ifdef S4BYTE_SWAP
 | 
						|
            mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
            mh.blockSize = x4reverseShort( (void *)&mh.blockSize ) ;
 | 
						|
         #endif
 | 
						|
 | 
						|
         file4write( &f4memo->file, 0L, &mh, sizeof( mh ) ) ;
 | 
						|
 | 
						|
         #ifndef S4OFF_MULTI
 | 
						|
         #ifndef N4OTHER
 | 
						|
            if ( !lockCond )
 | 
						|
               memo4fileUnlock( &f4memo->data->memoFile ) ;
 | 
						|
         #endif
 | 
						|
         #endif
 | 
						|
      }
 | 
						|
      if ( memo4fileDump( f4memo, *memoIdPtr, ptr, lenWrite, memoLen, type ) < 0 )
 | 
						|
         return -1 ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
      return file4write( &f4memo->file, *memoIdPtr * f4memo->blockSize + offset + sizeof( oldMemoBlock ), ptr, lenWrite ) ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif /* S4MFOX */
 | 
						|
 | 
						|
int memo4fileWrite( MEMO4FILE *f4memo, long *memoIdPtr, const char *ptr, const unsigned ptrLen )
 | 
						|
{
 | 
						|
   #ifdef S4MFOX
 | 
						|
      return memo4fileWritePart( f4memo, memoIdPtr, ptr, (long)ptrLen, 0L, ptrLen, 1L ) ;
 | 
						|
   #else
 | 
						|
      int strNumBlocks ;
 | 
						|
      long pos ;
 | 
						|
      #ifndef S4MDX
 | 
						|
         #ifndef S4OFF_MULTI
 | 
						|
            #ifndef N4OTHER
 | 
						|
               int rc, lockCond ;
 | 
						|
            #endif
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
      #ifdef S4MNDX
 | 
						|
         MEMO4HEADER mh ;
 | 
						|
         long lenRead ;
 | 
						|
         char buf[MEMO4SIZE] ;
 | 
						|
         int readSize, i ;
 | 
						|
      #else
 | 
						|
         MEMO4BLOCK oldMemoBlock ;
 | 
						|
         MEMO4CHAIN_ENTRY newEntry, cur, prev ;
 | 
						|
         int strWritten ;
 | 
						|
         long prevPrevEntry, prevPrevNum ;
 | 
						|
         long fileLen, extraLen ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      #ifdef E4PARM_LOW
 | 
						|
         if ( memoIdPtr == 0 )
 | 
						|
            return error4( 0, e4parm_null, E95209 ) ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      #ifdef S4MNDX
 | 
						|
         if ( ptrLen == 0 )
 | 
						|
         {
 | 
						|
            *memoIdPtr = 0L ;
 | 
						|
            return 0 ;
 | 
						|
         }
 | 
						|
 | 
						|
         strNumBlocks = (int)(((long)ptrLen + f4memo->blockSize-1) / f4memo->blockSize) ;
 | 
						|
 | 
						|
         if ( *memoIdPtr <= 0L )
 | 
						|
            *memoIdPtr = 0L ;
 | 
						|
         else    /* read in old record to see if new entry can fit */
 | 
						|
         {
 | 
						|
            readSize = 0 ;
 | 
						|
            pos = *memoIdPtr * f4memo->blockSize ;
 | 
						|
 | 
						|
            do
 | 
						|
            {
 | 
						|
               readSize += MEMO4SIZE ;
 | 
						|
 | 
						|
               lenRead = file4read( &f4memo->file, pos, buf, MEMO4SIZE ) ;
 | 
						|
               if ( lenRead <= 0 )
 | 
						|
                  return file4readError( &f4memo->file, pos, MEMO4SIZE, "memo4fileWrite()" ) ;
 | 
						|
 | 
						|
               for ( i=0 ; ((long) i) < lenRead ; i++ )
 | 
						|
                  if ( buf[i] == (char)0x1A )  break ;
 | 
						|
 | 
						|
               #ifdef E4MISC
 | 
						|
                  if ( buf[i] != (char)0x1A && lenRead != MEMO4SIZE )
 | 
						|
                     return error4( f4memo->file.codeBase, e4info, E85203 ) ;
 | 
						|
               #endif
 | 
						|
 | 
						|
               pos += MEMO4SIZE ;
 | 
						|
            } while ( i >= MEMO4SIZE && buf[i] != (char) 0x1A ) ;  /* Continue if Esc is not located */
 | 
						|
 | 
						|
            if ( ((unsigned)readSize) <= ptrLen )   /* there is not room */
 | 
						|
               *memoIdPtr = 0 ;
 | 
						|
         }
 | 
						|
 | 
						|
         if ( *memoIdPtr == 0 )   /* add entry at eof */
 | 
						|
         {
 | 
						|
            #ifndef S4OFF_MULTI
 | 
						|
               #ifndef N4OTHER
 | 
						|
                  lockCond = f4memo->data->memoFile.fileLock ;
 | 
						|
                  rc = memo4fileLock( &f4memo->data->memoFile ) ;
 | 
						|
                  if ( rc )
 | 
						|
                     return rc ;
 | 
						|
               #endif
 | 
						|
            #endif
 | 
						|
 | 
						|
            lenRead = file4read( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
 | 
						|
            #ifdef S4BYTE_SWAP
 | 
						|
               mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
            #endif
 | 
						|
            if ( error4code( f4memo->data->c4 ) < 0 )
 | 
						|
            {
 | 
						|
               #ifndef S4OFF_MULTI
 | 
						|
                  #ifndef N4OTHER
 | 
						|
                     if ( !lockCond )
 | 
						|
                        memo4fileUnlock( &f4memo->data->memoFile ) ;
 | 
						|
                  #endif
 | 
						|
               #endif
 | 
						|
               return -1 ;
 | 
						|
            }
 | 
						|
 | 
						|
            if ( lenRead != sizeof( mh ) )
 | 
						|
            {
 | 
						|
               #ifndef S4OFF_MULTI
 | 
						|
                  #ifndef N4OTHER
 | 
						|
                     if ( !lockCond )
 | 
						|
                        memo4fileUnlock( &f4memo->data->memoFile ) ;
 | 
						|
                  #endif
 | 
						|
               #endif
 | 
						|
               return file4readError( &f4memo->file, 0L, sizeof( mh ), "memo4fileWrite()" ) ;
 | 
						|
            }
 | 
						|
 | 
						|
            *memoIdPtr = mh.nextBlock ;
 | 
						|
            mh.nextBlock = *memoIdPtr + strNumBlocks ;
 | 
						|
            #ifdef S4BYTE_SWAP
 | 
						|
               mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
            #endif
 | 
						|
 | 
						|
            file4write( &f4memo->file, 0, &mh, sizeof( mh ) ) ;
 | 
						|
 | 
						|
            #ifndef S4OFF_MULTI
 | 
						|
               #ifndef N4OTHER
 | 
						|
                  if ( !lockCond )
 | 
						|
                     memo4fileUnlock( &f4memo->data->memoFile ) ;
 | 
						|
               #endif
 | 
						|
            #endif
 | 
						|
 | 
						|
            #ifdef S4BYTE_SWAP
 | 
						|
               mh.nextBlock = x4reverseLong( (void *)&mh.nextBlock ) ;
 | 
						|
            #endif
 | 
						|
         }
 | 
						|
 | 
						|
 | 
						|
         if ( memo4fileDump( f4memo, *memoIdPtr, ptr, ptrLen, ptrLen ) < 0 )
 | 
						|
            return -1 ;
 | 
						|
 | 
						|
         return 0 ;
 | 
						|
      #else
 | 
						|
         /* S4MMDX */
 | 
						|
         memset( (void *)&newEntry, 0, sizeof(newEntry) ) ;
 | 
						|
         newEntry.blockNo = *memoIdPtr ;
 | 
						|
 | 
						|
         strWritten = 0 ;
 | 
						|
         if ( ptrLen == 0 )
 | 
						|
         {
 | 
						|
            strWritten = 1 ;
 | 
						|
            *memoIdPtr = 0 ;
 | 
						|
         }
 | 
						|
 | 
						|
         /* Initialize information about the old memo entry */
 | 
						|
         if ( newEntry.blockNo <= 0L )
 | 
						|
         {
 | 
						|
            if ( strWritten )
 | 
						|
            {
 | 
						|
               *memoIdPtr = 0L ;
 | 
						|
               return 0 ;
 | 
						|
            }
 | 
						|
            newEntry.num = 0 ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
         {
 | 
						|
            pos = newEntry.blockNo * f4memo->blockSize ;
 | 
						|
 | 
						|
            file4readAll( &f4memo->file, pos, (char *)&oldMemoBlock, sizeof(oldMemoBlock) ) ;
 | 
						|
            #ifdef S4BYTE_SWAP
 | 
						|
               oldMemoBlock.startPos = x4reverseShort( (void *)&oldMemoBlock.startPos ) ;
 | 
						|
               oldMemoBlock.numChars = x4reverseLong( (void *)&oldMemoBlock.numChars ) ;
 | 
						|
            #endif
 | 
						|
 | 
						|
            newEntry.num = (unsigned)(((long)oldMemoBlock.numChars + (long)f4memo->blockSize-1)/ f4memo->blockSize ) ;
 | 
						|
         }
 | 
						|
 | 
						|
         strNumBlocks = (int)(((long)ptrLen+2*(sizeof(short))+(sizeof(S4LONG))+ f4memo->blockSize-1) / f4memo->blockSize ) ;
 | 
						|
 | 
						|
         if ( newEntry.num >= strNumBlocks  &&  !strWritten )
 | 
						|
         {
 | 
						|
            *memoIdPtr = newEntry.blockNo + newEntry.num - strNumBlocks ;
 | 
						|
            if ( memo4fileDump( f4memo, *memoIdPtr, ptr, ptrLen, ptrLen ) < 0 )
 | 
						|
               return -1 ;
 | 
						|
 | 
						|
            strWritten = 1 ;
 | 
						|
            if ( newEntry.num == strNumBlocks )
 | 
						|
               return 0 ;
 | 
						|
 | 
						|
            newEntry.num -= strNumBlocks ;
 | 
						|
         }
 | 
						|
 | 
						|
         /* Initialize 'chain' */
 | 
						|
         memset( (void *)&cur, 0, sizeof(cur) ) ;
 | 
						|
         memset( (void *)&prev, 0, sizeof(prev) ) ;
 | 
						|
 | 
						|
         for(;;)
 | 
						|
         {
 | 
						|
            if ( error4code( f4memo->data->c4 ) < 0 )
 | 
						|
               return -1 ;
 | 
						|
 | 
						|
            memo4fileChainFlush( f4memo, &prev ) ;
 | 
						|
            prevPrevEntry = prev.blockNo ;
 | 
						|
            prevPrevNum = prev.num ;
 | 
						|
 | 
						|
            memcpy( (void *)&prev, (void *)&cur, sizeof(prev) ) ;
 | 
						|
 | 
						|
            if ( newEntry.blockNo > 0  &&  prev.next > newEntry.blockNo )
 | 
						|
            {
 | 
						|
               /* See if the new entry fits in here */
 | 
						|
               memcpy( (void *)&cur, (void *)&newEntry, sizeof(cur) ) ;
 | 
						|
               newEntry.blockNo = 0 ;
 | 
						|
               cur.next  = prev.next ;
 | 
						|
               prev.next = cur.blockNo ;
 | 
						|
               cur.toDisk = prev.toDisk = 1 ;
 | 
						|
            }
 | 
						|
            else
 | 
						|
               memo4fileChainSkip( f4memo, &cur ) ;
 | 
						|
 | 
						|
            /* See if the entries can be combined. */
 | 
						|
            if ( prev.blockNo + prev.num == cur.blockNo && prev.num )
 | 
						|
            {
 | 
						|
               /* 'cur' becomes the combined groups. */
 | 
						|
               prev.toDisk = 0 ;
 | 
						|
               cur.toDisk  = 1 ;
 | 
						|
 | 
						|
               cur.blockNo = prev.blockNo ;
 | 
						|
               if ( cur.num >= 0 )
 | 
						|
                  cur.num  += prev.num ;
 | 
						|
               prev.blockNo = prevPrevEntry ;
 | 
						|
               prev.num = prevPrevNum ;
 | 
						|
            }
 | 
						|
 | 
						|
            if ( strWritten )
 | 
						|
            {
 | 
						|
               if ( newEntry.blockNo == 0 )
 | 
						|
               {
 | 
						|
                  memo4fileChainFlush( f4memo, &prev ) ;
 | 
						|
                  memo4fileChainFlush( f4memo, &cur ) ;
 | 
						|
                  return 0 ;
 | 
						|
               }
 | 
						|
            }
 | 
						|
            else  /* 'str' is not yet written, try the current entry */
 | 
						|
            {
 | 
						|
               if ( cur.next == -1 )  /* End of file */
 | 
						|
                  cur.num = strNumBlocks ;
 | 
						|
 | 
						|
               if ( cur.num >= strNumBlocks )
 | 
						|
               {
 | 
						|
                  cur.num -= strNumBlocks ;
 | 
						|
                  *memoIdPtr = cur.blockNo + cur.num ;
 | 
						|
                  memo4fileDump( f4memo, *memoIdPtr, ptr, ptrLen, ptrLen ) ;
 | 
						|
                  if ( cur.next == -1 ) /* if end of file */
 | 
						|
                  {
 | 
						|
                     /* For dBASE IV compatibility */
 | 
						|
                     fileLen  = file4len( &f4memo->file ) ;
 | 
						|
                     extraLen = f4memo->blockSize -  fileLen % f4memo->blockSize ;
 | 
						|
                     if ( extraLen != f4memo->blockSize )
 | 
						|
                        file4lenSet( &f4memo->file, fileLen+extraLen ) ;
 | 
						|
                  }
 | 
						|
 | 
						|
                  strWritten = 1 ;
 | 
						|
 | 
						|
                  if ( cur.num == 0 )
 | 
						|
                  {
 | 
						|
                     if ( cur.next == -1 ) /* End of file */
 | 
						|
                        prev.next = cur.blockNo + strNumBlocks ;
 | 
						|
                     else
 | 
						|
                        prev.next = cur.next ;
 | 
						|
                     prev.toDisk = 1 ;
 | 
						|
                     cur.toDisk = 0 ;
 | 
						|
                  }
 | 
						|
                  else
 | 
						|
                     cur.toDisk = 1 ;
 | 
						|
               }
 | 
						|
            }
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
}
 | 
						|
#endif /* S4OFF_WRITE */
 | 
						|
#endif /* S4MEMO_OFF */
 | 
						|
 | 
						|
#endif /* S4CLIENT */
 |