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