/* m4memo.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved.  */


#include "d4all.h"
#ifndef S4UNIX
   #ifdef __TURBOC__
      #pragma hdrstop
   #endif
#endif

#ifndef S4OFF_MEMO

#ifdef S4CLIENT
#ifndef S4OFF_WRITE
int S4FUNCTION d4memoCompress( DATA4 *data )
{
   int rc ;
   CONNECTION4 *connection ;
   CODE4 *c4 ;

   #ifdef S4VBASIC
      if ( c4parm_check( data, 2, E95201 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E95201 ) ;
   #endif

   c4 = data->codeBase ;
   if ( error4code( c4 ) < 0 )
      return e4codeBase ;

   if ( data->readOnly == 1 )
      return error4describe( c4, e4write, E80606, d4alias( data ), 0, 0 ) ;

   if ( data->dataFile->nFieldsMemo == 0 )
      return 0 ;

   rc = d4update( data ) ;
   if ( rc )
      return rc ;

   connection = data->dataFile->connection ;
   if ( connection == 0 )
      return error4stack( c4, e4connection, E95201 ) ;

   data->count = -1 ;
   data->dataFile->numRecs = -1 ;
   connection4assign( connection, CON4MEMO_COMPRESS, data4clientId( data ), data4serverId( data ) ) ;
   rc = connection4repeat( connection, -2, -1, -1, data ) ;
   if ( rc < 0 )
      connection4error( connection, c4, rc, E95201 ) ;

   return rc ;
}
#endif /* S4OFF_WRITE */
#endif /* S4CLIENT */
#endif /* S4OFF_MEMO */

#ifndef S4CLIENT

#ifndef S4OFF_MEMO
#ifdef S4MFOX
long memo4lenPart( MEMO4FILE *f4memo, long memoId )
{
   long pos ;
   int rc ;
   MEMO4BLOCK memoBlock ;

   if ( memoId <= 0L )
      return 0 ;

   pos = memoId * f4memo->blockSize ;
   rc = file4readAll( &f4memo->file, pos, &memoBlock, sizeof( MEMO4BLOCK ) ) ;
   if ( rc < 0 )
      return error4stack( f4memo->file.codeBase, rc, E95204 ) ;
   #ifdef S4BYTE_SWAP
      memoBlock.type = x4reverseLong( (void *)&memoBlock.type ) ;
      memoBlock.numChars = x4reverseLong( (void *)&memoBlock.numChars ) ;
   #endif

   return x4reverseLong( (void *)&memoBlock.numChars ) ;
}
#endif

#ifndef S4OFF_WRITE
int S4FUNCTION d4memoCompress( DATA4 *data )
{
   CODE4 *c4 ;
   int rc ;

   #ifdef S4VBASIC
      if ( c4parm_check( data, 2, E95201 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E95201 ) ;
   #endif

   c4 = data->codeBase ;
   if ( error4code( c4 ) < 0 )
      return e4codeBase ;

   if ( data->dataFile->nFieldsMemo == 0 )
      return 0 ;

   rc = d4update( data ) ;
   if ( rc )
      return rc ;

   #ifndef S4OFF_MULTI
      #ifdef S4SERVER
         rc = dfile4lockFile( data->dataFile, data4clientId( data ), data4serverId( data ) ) ;
      #else
         rc = d4lockFile( data ) ;
      #endif
      if ( rc )
         return rc ;
   #endif

   #ifndef S4OFF_TRAN
      if ( code4transEnabled( c4 ) )
         if ( tran4active( c4, data ) != 0 )
            return error4( c4, e4transViolation, E81502 ) ;
   #endif

   return dfile4memoCompress( data->dataFile, data ) ;
}

int dfile4memoCompress( DATA4FILE *data, DATA4 *d4 )
{
   char *rdBuf, *wrBuf, *ptr ;
   FILE4SEQ_READ rd ;
   FILE4SEQ_WRITE wr ;
   MEMO4FILE newFile ;
   CODE4 *c4 ;
   unsigned int bufSize, ptrLen, ptrMax, saveFlag ;
   long curCount, iRec, newId ;
   int  rc, i ;
   FIELD4 *field ;
   #ifdef S4MFOX
      long memoLen, memoType ;
      unsigned long pos ;

      memoType = 1 ;
   #endif

   #ifdef S4VBASIC
      if ( c4parm_check( d4, 2, E95201 ) )
         return -1 ;
   #endif

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E95201 ) ;
   #endif

   c4 = data->c4 ;
   if ( error4code( c4 ) < 0 )
      return e4codeBase ;

   if ( data->memoFile.file.hand == -1 )
      return 0 ;

   #ifndef S4OFF_MULTI
      #ifndef N4OTHER
         #ifdef S4SERVER
            rc = dfile4lockMemo( data ) ;
         #else
            rc = dfile4lockMemo( data ) ;
         #endif
         if ( rc )
            return rc ;
      #endif
   #endif

   saveFlag = c4->memSizeMemo ;
   c4->memSizeMemo = (unsigned int)data->memoFile.blockSize ;

   rc = memo4fileCreate( &newFile, c4, data, 0 ) ;
   if ( rc < 0 )
      return error4stack( c4, rc, E91102 ) ;

   c4->memSizeMemo = saveFlag ;
   newFile.blockSize = data->memoFile.blockSize ;

   rdBuf = wrBuf = 0 ;
   bufSize = c4->memSizeBuffer ;

   for (; bufSize > data->recWidth; bufSize -= 0x800 )
   {
      rdBuf = (char *)u4allocFree( c4, (long)bufSize ) ;
      if ( rdBuf == 0 )
         continue ;

      wrBuf = (char *)u4allocFree( c4, (long)bufSize ) ;
      if ( wrBuf )
         break ;

      u4free( rdBuf ) ;
      rdBuf = 0 ;
   }

   #ifdef S4ADVANCE_READ
      file4seqReadInitDo( &rd, &data->file, dfile4recordPosition( data, 1L ), rdBuf, bufSize, 1 ) ;
   #else
      file4seqReadInit( &rd, &data->file, dfile4recordPosition( data, 1L ), rdBuf, bufSize ) ;
   #endif
   file4seqWriteInit( &wr, &data->file, dfile4recordPosition( data, 1L ), wrBuf, bufSize ) ;

   curCount = dfile4recCount( data, data4serverId( d4 )  ) ;

   ptr = 0 ;
   ptrLen = ptrMax = 0 ;

   for ( iRec= 1L ; iRec <= curCount && rc == 0 ; iRec++ )
   {
      if ( file4seqReadAll( &rd, d4->record, data->recWidth ) < 0 )
         break ;

      for ( i = 0 ; i < d4->dataFile->nFieldsMemo ; i++ )
      {
         field = d4->fieldsMemo[i].field ;

         #ifdef S4FOX
            pos = 0L ;

            if ( f4null( field ) == 1 )
               memoLen = 0 ;
            else
               memoLen = memo4lenPart( &data->memoFile, f4long( field ) ) ;


            if ( memoLen > 0L )
            {
               newId = 0L ;
               do
               {
                  #ifdef E4ANALYZE
                     if ( pos > (unsigned long)memoLen )
                     {
                        rc = error4( c4, e4memoCorrupt, E91102 ) ;
                        break ;
                     }
                  #endif

                  ptrLen = ptrMax ;

                  if ( memo4fileReadPart( &data->memoFile, f4long( field ), &ptr, &ptrLen, pos, UINT_MAX - 100, &memoType ) < 0 )
                  {
                     rc = -1 ;
                     break ;
                  }

                  if ( ptrLen > ptrMax )
                     ptrMax = ptrLen ;

                  if ( memo4fileWritePart( &newFile, &newId, ptr, memoLen, pos, ptrLen, memoType ) < 0 )
                  {
                     rc = -1 ;
                     break ;
                  }
                  pos += ptrLen ;
               } while( pos != (unsigned long)memoLen ) ;
               c4ltoa45( newId, f4ptr(field), -( (int)field->len ) ) ;
            }
            else
               c4ltoa45( 0L, f4ptr(field), -( (int)field->len) ) ;
         #else
            ptrLen = ptrMax ;
            if ( memo4fileRead( &data->memoFile, f4long(field), &ptr, &ptrLen ) < 0 )
            {
               rc = -1 ;
               break ;
            }

            if ( ptrLen > ptrMax )
               ptrMax = ptrLen ;

            newId = 0L ;
            if ( memo4fileWrite( &newFile, &newId, ptr, ptrLen ) < 0 )
            {
               rc = -1 ;
               break ;
            }

            c4ltoa45( newId, f4ptr(field), - ((int) field->len) ) ;
         #endif
      }
      file4seqWrite( &wr, d4->record, data->recWidth ) ;
   }

   if ( rc < 0 )
      file4close( &newFile.file ) ;  /* error occurred */
   else
      file4seqWriteFlush(&wr) ;

   #ifdef S4ADVANCE_READ
      file4seqReadInitUndo( &rd ) ;
   #endif

   u4free( ptr ) ;
   u4free( rdBuf ) ;
   u4free( wrBuf ) ;

   if ( rc == 0 )
   {
      rc = file4replace( &data->memoFile.file, &newFile.file ) ;
      if ( rc == 0 )
         #ifdef S4MMDX
            if ( file4len( &data->memoFile.file ) < data->memoFile.blockSize )
               rc = file4lenSet( &data->memoFile.file, data->memoFile.blockSize ) ;
         #else
            if ( file4len( &data->memoFile.file ) < 512 )
               rc = file4lenSet( &data->memoFile.file, 512L ) ;
         #endif
   }

   return rc ;
}
#endif /* S4OFF_WRITE */

#ifndef S4MFOX
#ifndef S4MNDX

int memo4fileChainFlush( MEMO4FILE *f4memo, MEMO4CHAIN_ENTRY *chain )
{
   #ifdef S4BYTE_SWAP
      MEMO4CHAIN_ENTRY swap ;
   #endif

   if ( chain->toDisk )
   {
      chain->toDisk = 0 ;
      #ifdef S4BYTE_SWAP
         memcpy( (void *)&swap, (void *)chain, sizeof( MEMO4CHAIN_ENTRY ) ) ;
         swap.next = x4reverseLong( (void *)&swap.next ) ;
         swap.num = x4reverseLong( (void *)&swap.num ) ;

         return file4write( &f4memo->file, chain->blockNo * f4memo->blockSize, &swap, 2*sizeof(S4LONG) ) ;
      #else
         return file4write( &f4memo->file, chain->blockNo * f4memo->blockSize, chain, 2*sizeof(S4LONG) ) ;
      #endif
   }
   return 0 ;
}

int memo4fileChainSkip( MEMO4FILE *f4memo, MEMO4CHAIN_ENTRY *chain )
{
   unsigned lenRead ;

   chain->toDisk = 0 ;
   chain->blockNo = chain->next ;

   if ( chain->next < 0 )
      lenRead = 0 ;
   else
   {
      lenRead = file4read( &f4memo->file, chain->next * f4memo->blockSize, chain, sizeof(chain->next)+sizeof(chain->num) ) ;
      #ifdef S4BYTE_SWAP
         chain->next = x4reverseLong( (void *)&chain->next ) ;
         chain->num = x4reverseLong( (void *)&chain->num ) ;
      #endif
   }
   if ( f4memo->data->c4->errorCode < 0 )
      return -1 ;
   if ( lenRead == 0 )
   {
      chain->num = -1 ;
      chain->next = -1 ;
      return 0 ;
   }
   if ( lenRead != sizeof(chain->next)+sizeof(chain->num) )
      return file4readError( &f4memo->file, chain->next * f4memo->blockSize, sizeof(chain->next)+sizeof(chain->num), "memo4fileChainSkip" ) ;
   return 0 ;
}
#endif
#endif

#endif  /* S4OFF_MEMO */

/* Make the memo file entries current */
#ifndef S4OFF_MEMO
#ifndef S4OFF_MULTI
int d4validateMemoIds( DATA4 *data )
{
   int i, rc ;
   char *fromPtr ;

   #ifdef E4PARM_HIGH
      if ( data == 0 )
         return error4( 0, e4parm_null, E95203 ) ;
   #endif

   if ( data->memoValidated )
      return 0 ;

   if ( data->recNum > 0 )
   {
      #ifdef S4SERVER
         rc = dfile4lock( data->dataFile, data4clientId( data ), data4serverId( data ), data->recNum ) ;
      #else
         rc = d4lock( data, data->recNum ) ;
      #endif
      if ( rc )
         return rc ;
   }

   rc = d4readOld( data, data->recNum ) ;
   if ( rc < 0 )
      return error4stack( data->codeBase, rc, E95203 ) ;

   if ( data->recordChanged == 0 )   /* if the record has changed, leave intact */
      for ( i = 0 ; i < data->dataFile->nFieldsMemo ; i++ )
      {
         if ( data->fieldsMemo[i].isChanged == 0 )
         {
            fromPtr = data->recordOld + data->fieldsMemo[i].field->offset ;
            memcpy( f4ptr( data->fieldsMemo[i].field ), fromPtr, f4len( data->fieldsMemo[i].field ) ) ;  /* need f4len() because S4FOX 3.0 has 4 byte memos, not 10 byte */
         }
      }

   data->memoValidated = 1 ;
   return 0 ;
}
#endif  /* S4OFF_MULTI */
#endif  /* S4OFF_MEMO */
#endif  /* S4CLIENT */