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

#include "d4all.h"
#include "u4trans.h"

#ifndef UNIX
   #ifdef __TURBOC__
      #pragma hdrstop
   #endif
#endif

#ifdef S4UNIX
   char *ltoa( long lVal, char *ptr, int num)
   {
      c4ltoa45( lVal, ptr, (num>0?num-1:num+1) ) ;
      ptr[ (num>0? num:-num)-1] = '\0' ;
      return( ptr ) ;
   }
#endif

#ifdef S4UTILS
#ifdef S4WINDOWS
#ifdef S4DLL_BUILD
   #define WM_UTIL_STATUS (WM_USER + 1)
   #define WM_UTIL_CLOSE  (WM_USER + 2)
   FILE *stdout, *stderr ;
   unsigned int messageType ; /* icon style for message box */

   char *statusStringBlank = "                         ";
   char *statusStringMessg = "Processing log file: ";
   char *statusStringBckSp = "\r";
   char *statusStringFormt = "%3d.%02d%%%%";
   char *statusStringSpace = "100.00  ";

void S4FUNCTION sendStatusMessage( int hWnd, int percentComp )
{
   SendMessage( hWnd, WM_UTIL_STATUS, percentComp, 0L ) ;
   return ;
}

void S4FUNCTION sendCloseMessage( int hWnd )
{
   SendMessage( hWnd, WM_UTIL_CLOSE, 0, 0L ) ;
   return ;
}

/****************************************************************************
**::  Function: getLogDatabases
**
*****************************************************************************
**
**    Function: getLogDatabases()
**
****************************************************************************/
#ifdef S4WINDOWS
int S4FUNCTION  getLogDatabases( char *logFileName, int hWndListBox )
{
   /* database required for a file selection listbox */
   static FIELD4INFO openFileName[] =
   {
      { "DBFNAME", 'C', 12, 0 },
      { "DBFPATH", 'C', 100, 0 },
      { "PATHLEN", 'N', 3, 0 },
      { 0, 0, 0 , 0 },
   } ;

   static TAG4INFO fileNameTags[] =
   {
      { "NAMETAG", "DBFNAME+DBFPATH", "", 0, 0 },
      { 0, 0, 0 , 0, 0 },
   };

   HCURSOR hCursor ;
   DWORD dwIndex ;
   CODE4 c4 ;
   TRAN4 *t4 = 0 ;
   DATA4 *openFile ;
   FIELD4 *fldDbfName = 0, *fldDbfPath = 0, *fldPathLen = 0 ;
   char *outMess[4], *data = 0, *cNone = "(none)" ;
   char buf[13], tmpBuf[256], pathBuf[256], *pathPtr, *tmpPtr ;
   long logFileLen;
   int rc = 0, tmpRc, tmpRc2, i = 0 ;
   unsigned int pathLen ;

   hCursor = SetCursor( LoadCursor( (HINSTANCE)NULL, IDC_WAIT ) ) ;

   code4init(&c4);
   c4.lockAttempts = WAIT4EVER;

   if( logFileName != 0 )
   {
      if( logFileName[0] != 0 )
      {
         rc = code4logOpen( &c4, logFileName, "" ) ;
         code4tranStatusSet( &c4, r4off ) ;
      }
      else
         rc = -1 ;
   }
   else
      rc = -1 ;

   if( rc != 0 )
   {
      outMess[0] = "Log File Error.\r\n" ;
      outMess[1] = "Ensure Log File <" ;
      outMess[2] = logFileName ;
      outMess[3] = "> is a backed up Log File.\r\n" ;
      util4out( &c4, stdout, outMess, 4 ) ;
   }

   if( rc == 0 )
      rc = file4refresh( &c4.transFile.file ) ;
   if( rc == 0 )
      logFileLen = file4len( &c4.transFile.file ) ;

   if( (rc == 0) && ( logFileLen > 0 ) )
   {
      t4 = &c4.c4trans.trans ;
      openFile = d4createTemp( &c4, openFileName, fileNameTags ) ;
      if( openFile == 0 )
         rc = -1 ;
   }

   if( rc == 0 )
   {
      fldDbfName = d4field( openFile, "DBFNAME" ) ;
      fldDbfPath = d4field( openFile, "DBFPATH" ) ;
      fldPathLen = d4field( openFile, "PATHLEN" ) ;
      d4tagSelect( openFile, d4tag( openFile, "NAMETAG" ) ) ;

      for( rc = tran4top( t4 ) ; ; rc = tran4skip( t4, TRAN4FORWARDS ) )
      {
         if( rc != 0 )
            break ;

         switch( tran4type(t4) )
         {
            case TRAN4OPEN :
               data = tran4getData( t4, 0L ) ;
               if( data == 0 )
               {
                  rc = -1 ;
                  break ;
               }
               rc = d4appendStart( openFile, 0 ) ;
               if( rc != 0 )
                  break ;
               memset( buf, 0, sizeof( buf ) ) ;
               memset( tmpBuf, 0, sizeof( tmpBuf ) ) ;
               memset( pathBuf, 0, sizeof( pathBuf ) ) ;
               memcpy( tmpBuf, data+2, *(short *)data ) ;
               u4namePiece( buf, sizeof( buf ), tmpBuf, 0, 1 ) ;
               u4namePiece( pathBuf, sizeof(pathBuf), tmpBuf, 1, 1 ) ;
               pathBuf[(strlen(pathBuf)-strlen(buf))] = 0 ;
               f4assign( fldDbfName, buf ) ;
               f4assign( fldDbfPath, pathBuf ) ;
               f4assignInt( fldPathLen, (int)strlen(pathBuf) ) ;
               rc = d4append( openFile ) ;
               break ;
         }
      }
      if( rc == r4eof )
         rc = 0 ;
   }

   if( rc == 0 )
   {
      for( rc = d4top( openFile ); rc == 0 ; rc = d4skip( openFile, 1L ) )
      {
         dwIndex = SendMessage( hWndListBox, LB_ADDSTRING, 0, (LPARAM) f4str( fldDbfName ) ) ;
         tmpPtr  = f4str( fldDbfPath ) ;
         pathLen = (unsigned int)f4int( fldPathLen ) ;
         pathPtr = (char *)u4allocDefault( (long)(pathLen+1) ) ;
         u4ncpy( pathPtr, tmpPtr, pathLen+1 ) ;
         SendMessage( hWndListBox, LB_SETITEMDATA, (WPARAM)dwIndex, (LPARAM) pathPtr ) ;
      }
      if( d4recCount( openFile ) == 0 )
         SendMessage( hWndListBox, LB_ADDSTRING, 0, (LPARAM) cNone ) ;
   }

   SetCursor( hCursor ) ;
   tmpRc  = rc ;
   tmpRc2 = c4.errorCode ;
   rc = code4close( &c4 ) ;
   code4transInitUndo( &c4.c4trans ) ;
   code4initUndo(&c4);

   if( rc < 0 || tmpRc < 0 || tmpRc2 != 0 )
      return -1 ;
   else
      return rc ;

}
#endif /* S4WINDOWS */

#ifdef S4VBASIC

long S4FUNCTION ReturnCPtr( LPSTR string )
{
   return (long)string ;
}

#endif   /* S4VBASIC */
#endif   /* S4DLL_BUILD */
#endif   /* S4WINDOWS */

void util4out(CODE4 *c4, FILE *stream, char *str[], int numStr)
{
   int i;

   #ifndef S4WINDOWS
      for (i=0; i<numStr; i++)
         if (str[i] != 0)
            fprintf(stream, str[i]);
   #else
   #ifdef S4VBASIC
      int messageExists = 0, messageLen = 0, totalLen = 0 ;
      char *bufptr, buf[512] ;
      bufptr = buf ;

      for( i=0; i < numStr; i++ )
      {
         messageLen = strlen( str[i] )  ;
         if( messageLen > 0 )
         {
            messageExists = 1 ;
            if( (totalLen+messageLen) < sizeof(buf)-1 )
            {
               lstrcpy( (bufptr+totalLen), str[i] ) ;
               totalLen += messageLen ;
            }
            messageLen = 0 ;
         }
      }

      if( messageExists )
         MessageBox( (HWND)NULL, buf, "CodeUtility Message", messageType ) ;

   #endif
   #endif
}

void util4printCommandLine(CODE4 *c4, UTIL4FLAG u4[], int numFlags, char *programName)
{
   int i;
   char **commandLine, programExe[41], *spaces;

   if (programName == 0)
      return;
   u4namePiece(programExe, 41, programName, 0, 1);
#ifndef S4UNIX
   c4lower(programExe);
#endif
   spaces =(char *) u4allocFree(c4, strlen(programExe)+2);
   if (spaces == 0)
      return;
   spaces[strlen(programExe)+1] = 0;
   memset(spaces, ' ', strlen(programExe)+1);
   commandLine = (char **)u4allocFree(c4, (2*numFlags+2)*4);
   if (commandLine == 0)
   {
      u4free(spaces);
      return;
   }

   commandLine[0] = programExe;
   commandLine[1] = " [@<parameter file>]\r\n";
   for (i=0; i<numFlags; i++)
   {
      commandLine[2*i+2] = spaces;
      commandLine[2*i+3] = u4[i].descrip;
   }
/*   util4out(c4, stdout, commandLine, 2*i+2);*/

   u4free(commandLine);
   u4free(spaces);
}

static int util4processFlags(CODE4 *c4, UTIL4FLAG u4[], int numFlags, char* argv[], int argc)
{
   int i, j, found, count, flag, index;
   char *outMess[3];

   outMess[2] = "\r\n\r\n";
   for (j=1; j<argc; j++)
   {
      if (*argv[j] != '-' && *argv[j] != '/')  /* not a switch */
      {
         outMess[0] = "Command line error! Expecting flag but found value: ";
         outMess[1] = argv[j];
         util4out(c4, stdout, outMess, 3);
         return(-1);
      }
      found = 0;
      for (i=0; i<numFlags && !found; i++)
      {
         if (u4[i].len > strlen(argv[j]+1))
            continue;
         if (u4[i].caseSens)
         {
            if (strncmp(u4[i].name, argv[j]+1, strlen(argv[j]+1)) != 0)  /* not this switch */
               continue;
         }
         else
         {
            if (strnicmp(u4[i].name, argv[j]+1, strlen(argv[j]+1)) != 0)  /* not this switch */
               continue;
         }
         found = 1;
         if (u4[i].found != 0)
         {
            if (u4[i].multiples == 0)  /* discard multiples */
               break;
            if (u4[i].multiples == -1)
            {
               outMess[0] = "Command line error! Flag found more than once: ";
               outMess[1] = argv[j];
               util4out(c4, stdout, outMess, 3);
               return(-1);
            }
            if (u4[i].multiples == 1 && u4[i].values != 0)
            {
               for (; u4[i].numPtr>0; u4[i].numPtr-=4)
                  u4free(u4[i].ptr[u4[i].numPtr/4-1]);
               u4free(u4[i].ptr);
            }
         }
         if (u4[i].values == 0)
         {
            if (u4[i].ptr == 0)
            {
               u4[i].ptr = (char **)u4allocFree(c4, 4);
               if (u4[i].ptr == 0)
                  return(-1);
               u4[i].ptr[0] = (char *)u4allocFree(c4, 1);
               if (u4[i].ptr[0] == 0)
                  return(-1);
               u4[i].numPtr = 4;
            }
            *u4[i].ptr[0] = 1;
            u4[i].found = 1;
            continue;
         }
         count = u4[i].values > 0 ? u4[i].values : -u4[i].values;
         flag = j;
         while (count > 0 && j+1 < argc && *argv[j+1] != '-' && *argv[j+1] != '/')
         {
            j++;
            if (u4[i].ptr == 0)
            {
               u4[i].ptr = (char **)u4allocFree(c4, 4);
               if (u4[i].ptr == 0)
                  return(-1);
               if (u4[i].multiples == 2 && !u4[i].exact)
               {
                  u4[i].ptr[0] = (char *)u4allocFree(c4, strlen(argv[j])+2);
                  if (u4[i].ptr[0] == 0)
                     return(-1);
                  *u4[i].ptr[0] = index = 1;
                  strcpy(u4[i].ptr[0]+1, argv[j]);
               }
               else
               {
                  u4[i].ptr[0] = (char *)u4allocFree(c4, strlen(argv[j])+1);
                  if (u4[i].ptr[0] == 0)
                     return(-1);
                  strcpy(u4[i].ptr[0], argv[j]);
               }
               u4[i].numPtr = 4;
            }
            else
               if (u4[i].multiples == 1 && count == u4[i].values)  /* replace */
               {
                  for (; u4[i].numPtr>0; u4[i].numPtr-=4)
                     u4free(u4[i].ptr[u4[i].numPtr/4-1]);
                  u4[i].ptr[0] = (char *)u4allocFree(c4, strlen(argv[j])+1);
                  if (u4[i].ptr[0] == 0)
                     return(-1);
                  u4[i].numPtr = 4;
                  strcpy(u4[i].ptr[0], argv[j]);
               }
               else  /* add */
               {
                  if (count == u4[i].values)
                     index = *u4[i].ptr[u4[i].numPtr/4-1] + 1;
                  if (u4allocAgain(c4, (char **)&u4[i].ptr, &u4[i].numPtr, u4[i].numPtr+4) == e4memory)
                     return(-1);
                  u4[i].numPtr -= 4;
                  if (u4[i].multiples == 2 && !u4[i].exact)
                  {
                     u4[i].ptr[u4[i].numPtr/4] = (char *)u4allocFree(c4, strlen(argv[j])+2);
                     if (u4[i].ptr[u4[i].numPtr/4] == 0)
                        return(-1);
                     *u4[i].ptr[u4[i].numPtr/4] = index;
                     strcpy(u4[i].ptr[u4[i].numPtr/4]+1, argv[j]);
                  }
                  else
                  {
                     u4[i].ptr[u4[i].numPtr/4] = (char *)u4allocFree(c4, strlen(argv[j])+1);
                     if (u4[i].ptr[u4[i].numPtr/4] == 0)
                        return(-1);
                     strcpy(u4[i].ptr[u4[i].numPtr/4], argv[j]);
                  }
                  u4[i].numPtr += 4;
               }
            count--;
         }
         if ((u4[i].exact && count > 0) || (count == u4[i].values))
         {
            outMess[0] = "Command line error! Not enough values for flag: ";
            outMess[1] = argv[flag];
            util4out(c4, stdout, outMess, 3);
            return(-1);
         }
         u4[i].found = 1;
      }
      if (!found)
      {
         outMess[0] = "Command line error! Unknown flag: ";
         outMess[1] = argv[j];
         util4out(c4, stdout, outMess, 3);
         return(-1);
      }
   }
   return(0);
}

void util4flagsFree(UTIL4FLAG u4[], int numFlags)
{
   int i ;

   for (i=0; i<numFlags; i++)
   {
      for (; u4[i].numPtr>0; u4[i].numPtr-=4)
         u4free(u4[i].ptr[u4[i].numPtr/4-1]);
      u4free(u4[i].ptr);
   }
}

int util4parseCommandLine(CODE4 *c4, UTIL4FLAG u4[], int numFlags, char* argv[], int argc)
{
   int rc, quotes, inArg, j;
   unsigned int i, lenRead, buffSize ;
   long len, offset=0;
   char *buff;
   char **argvParse;
   int argcParse;
   FILE4 f4;

   if ((*argv[1] == '-' || *argv[1] == '/') && *(argv[1]+1) == '?')
      return(-1);
   if (*argv[1] == '@')
   {
      rc = file4open(&f4, c4, argv[1]+1, 0);
      if (rc != 0)
         return(rc);
      len = file4len(&f4);
      if (len < 0)
      {
         file4close(&f4);
         return((int) len);
      }
      if (len >= 65001)
      {
         buff = (char *)u4allocFree(c4, 65001);
         buffSize = 65000;
      }
      else
      {
         buff = (char *)u4allocFree(c4, len+1);
         buffSize = (unsigned int)len;
      }
      if (buff == 0)
      {
         file4close(&f4);
         return(-1);
      }
      while (len-offset > 0)
      {
         lenRead = file4read(&f4, offset, buff, buffSize);
         if (lenRead == 0)
         {
            rc = -1;
            break;
         }
         quotes = 0;
         inArg = 0;
         argcParse = 0;
         for (i=0; i<lenRead; i++)
         {
            if (!quotes && buff[i] == '\"')
               quotes = 1;
            if (quotes && buff[i] == '\"' && i > 0 && buff[i-1] != '\\')
               quotes = 0;
            if (buff[i] < 32 || buff[i] == 127)
            {
               buff[i] = 0;
               inArg = 0;
            }
            if (!quotes && buff[i] == ' ')
            {
               buff[i] = 0;
               inArg = 0;
            }
            if (!inArg && buff[i] > 32)
            {
               inArg = 1;
               argcParse++;
            }
         }
         if (inArg)
            argcParse--;
         if (argcParse < 1)
            break;
         argvParse = (char **)u4allocFree(c4, 4*(argcParse+1));
         if (argvParse == 0)
         {
            rc = -1;
            break;
         }
         i = 0;
         for (j=0; j<argcParse; j++)
         {
            while (buff[i] == 0)
               i++;
            argvParse[j+1] = buff+i;
            i += strlen(buff+i);
         }
         offset += i;
         rc = util4processFlags(c4, u4, numFlags, argvParse, argcParse+1);
         u4free(argvParse);
         if (rc != 0)
            break;
      }
      u4free(buff);
      if (rc != 0)
         file4close(&f4);
      else
         rc = file4close(&f4);
      if (rc == 0)
         rc = util4processFlags(c4, u4, numFlags, argv+1, argc-1);
   }
   else
      rc = util4processFlags(c4, u4, numFlags, argv, argc);
   if (rc != 0)
      util4flagsFree(u4, numFlags);
   return(rc);
}

char *util4rightJ(char *str, int len)
{
   short i=-1;

   len--;
   while ((++i <= len) && (str[i] != 0));
   if (i > len)
      return str;
   while (i > -1)
      str[len--] = str[i--];
   while (len > -1)
      str[len--] = ' ';
   return str;
}

int util4checkOnOffCommandLine(CODE4 *c4, UTIL4FLAG u4[], int flag, int def)
{
   char *outMess[5];

   if (u4[flag].ptr == 0)
      return(def);
   c4upper( u4[flag].ptr[0] ) ;
   if (strcmp(u4[flag].ptr[0], "OFF") == 0)
      return(0);
   if (strcmp(u4[flag].ptr[0], "ON") == 0)
      return(1);
   outMess[0] = "Command line error! -";
   outMess[1] = u4[flag].name;
   outMess[2] = " value ";
   outMess[3] = u4[flag].ptr[0];
   outMess[4] = " is not ON or OFF.\r\n";
   util4out(c4, stdout, outMess, 5);
   return(-1);
}

long util4checkRangeCommandLine(CODE4 *c4, UTIL4FLAG u4[], int flag, long def, long lRange, long hRange)
{
   char *outMess[9];
   char tempLow[12], tempHigh[12];
   long temp;

   if (u4[flag].ptr == 0)
      return(def);
   temp = atol(u4[flag].ptr[0]);
   if (hRange - lRange < 0)
      return(temp);
   if (temp > hRange || temp < lRange)
   {
      outMess[0] = "Command line error! -";
      outMess[1] = u4[flag].name;
      outMess[2] = " value ";
      outMess[3] = u4[flag].ptr[0];
      outMess[4] = " is out of range ";
      outMess[5] = ltoa(lRange, tempLow, 10);
      outMess[6] = " to ";
      outMess[7] = ltoa(hRange, tempHigh, 10);
      outMess[8] = ".\r\n";
      util4out(c4, stdout, outMess, 9);
      return(lRange-1);
   }
   return(temp);
}

#ifndef S4OFF_TRAN
#ifndef S4OFF_COMMUNICATIONS

int tran4serverEof( TRAN4 *trans, unsigned long *tranFileEof )
{
   CONNECTION4 *connection ;
   int rc ;
   CONNECTION4TRAN_EOF_INFO_OUT *out ;

   #ifdef E4PARM_LOW
      if ( trans == 0 || tranFileEof == 0 )
         return e4parm_null ;
   #endif

   if ( trans->c4trans->c4->defaultServer == 0 )
      return r4noServer ;

   connection = trans->c4trans->c4->defaultServer->connect ;
   #ifdef E4ANALYZE
      if ( connection == 0 )
         return e4struct ;
   #endif

   connection4assign( connection, CON4TRAN_EOF, 0l, 0l ) ;
   connection4send( connection ) ;
   rc = connection4receive( connection ) ;
   if ( rc < 0 )
      return rc ;

   rc = connection4status( connection ) ;
   if ( rc < 0 )
      return rc ;

   if ( connection4len( connection ) != sizeof( CONNECTION4TRAN_EOF_INFO_OUT ) )
      return e4packetLen ;
   out = (CONNECTION4TRAN_EOF_INFO_OUT *)connection4data( connection ) ;

   *tranFileEof = out->eof ;
   return 0 ;
}

int tran4serverEofHalt( TRAN4 *trans, unsigned long *tranFileEof )
{
   CONNECTION4 *connection ;
   int rc ;
   CONNECTION4TRAN_EOF_HALT_INFO_OUT *out ;

   #ifdef E4PARM_LOW
      if ( trans == 0 || tranFileEof == 0 )
         return e4parm_null ;
   #endif

   if ( trans->c4trans->c4->defaultServer == 0 )
      return r4noServer ;

   connection = trans->c4trans->c4->defaultServer->connect ;
   #ifdef E4ANALYZE
      if ( connection == 0 )
         return e4struct ;
   #endif

   connection4assign( connection, CON4TRAN_EOF_HALT, 0l, 0l ) ;
   connection4send( connection ) ;
   rc = connection4receive( connection ) ;
   if ( rc < 0 )
      return rc ;

   rc = connection4status( connection ) ;
   if ( rc < 0 )
      return rc ;

   if ( connection4len( connection ) != sizeof( CONNECTION4TRAN_EOF_HALT_INFO_OUT ) )
      return e4packetLen ;
   out = (CONNECTION4TRAN_EOF_HALT_INFO_OUT *)connection4data( connection ) ;

   *tranFileEof = out->eof ;
   return 0 ;
}

#endif  /* S4OFF_COMMUNICATIONS */
#endif  /* S4OFF_TRAN */
#endif  /* S4UTILS */