codegen/QtScript: updated

codegen/QtScript: updated

Modified:
codegen/QtScript/QScriptEngine.prg

%%
%% Qt5xHb - Bindings libraries for Harbour/xHarbour and Qt Framework 5
%%
%% Copyright (C) 2018 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>
%%

$header

#include "hbclass.ch"

$addRequests

$beginClassFrom=QObject

   METHOD new
   METHOD delete
   METHOD abortEvaluation
   METHOD agent
   METHOD availableExtensions
   METHOD clearExceptions
   METHOD collectGarbage
   METHOD currentContext
   METHOD defaultPrototype
   METHOD evaluate
   METHOD globalObject
   METHOD hasUncaughtException
   METHOD importExtension
   METHOD importedExtensions
   METHOD installTranslatorFunctions
   METHOD isEvaluating
   METHOD newArray
   METHOD newDate
   METHOD newObject
   METHOD newQMetaObject
   METHOD newQObject
   METHOD newRegExp
   METHOD newVariant
   METHOD nullValue
   METHOD popContext
   METHOD processEventsInterval
   METHOD pushContext
   METHOD reportAdditionalMemoryCost
   METHOD setAgent
   METHOD setDefaultPrototype
   METHOD setGlobalObject
   METHOD setProcessEventsInterval
   METHOD toObject
   METHOD toStringHandle
   METHOD uncaughtException
   METHOD uncaughtExceptionBacktrace
   METHOD uncaughtExceptionLineNumber
   METHOD undefinedValue
   METHOD checkSyntax

$addSignals

$endClass

$destructor

#pragma BEGINDUMP

$includes

#include <QStringList>

$prototype=QScriptEngine()
$internalConstructor=|new1|

$prototype=QScriptEngine(QObject * parent)
$internalConstructor=|new2|QObject *

//[1]QScriptEngine()
//[2]QScriptEngine(QObject * parent)

HB_FUNC_STATIC( QSCRIPTENGINE_NEW )
{
  if( ISNUMPAR(0) )
  {
    QScriptEngine_new1();
  }
  else if( ISNUMPAR(1) && ISQOBJECT(1) )
  {
    QScriptEngine_new2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$deleteMethod

$prototype=void abortEvaluation(const QScriptValue & result = QScriptValue())
$method=|void|abortEvaluation|const QScriptValue &=QScriptValue()

$prototype=QScriptEngineAgent * agent() const
$method=|QScriptEngineAgent *|agent|

$prototype=QStringList availableExtensions() const
$method=|QStringList|availableExtensions|

$prototype=void clearExceptions()
$method=|void|clearExceptions|

$prototype=void collectGarbage()
$method=|void|collectGarbage|

$prototype=QScriptContext * currentContext() const
$method=|QScriptContext *|currentContext|

$prototype=QScriptValue defaultPrototype(int metaTypeId) const
$method=|QScriptValue|defaultPrototype|int

$prototype=QScriptValue evaluate(const QString & program, const QString & fileName = QString(), int lineNumber = 1)
$internalMethod=|QScriptValue|evaluate,evaluate1|const QString &,const QString &=QString(),int=1

$prototype=QScriptValue evaluate(const QScriptProgram & program)
$internalMethod=|QScriptValue|evaluate,evaluate2|const QScriptProgram &

//[1]QScriptValue evaluate(const QString & program, const QString & fileName = QString(), int lineNumber = 1)
//[2]QScriptValue evaluate(const QScriptProgram & program)

HB_FUNC_STATIC( QSCRIPTENGINE_EVALUATE )
{
  if( ISBETWEEN(1,3) && ISCHAR(1) && ISOPTCHAR(2) && ISOPTNUM(3) )
  {
    QScriptEngine_evaluate1();
  }
  else if( ISNUMPAR(1) && ISQSCRIPTPROGRAM(1) )
  {
    QScriptEngine_evaluate2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue globalObject() const
$method=|QScriptValue|globalObject|

$prototype=bool hasUncaughtException() const
$method=|bool|hasUncaughtException|

$prototype=QScriptValue importExtension(const QString & extension)
$method=|QScriptValue|importExtension|const QString &

$prototype=QStringList importedExtensions() const
$method=|QStringList|importedExtensions|

$prototype=void installTranslatorFunctions(const QScriptValue & object = QScriptValue())
$method=|void|installTranslatorFunctions|const QScriptValue &=QScriptValue()

$prototype=bool isEvaluating() const
$method=|bool|isEvaluating|

$prototype=QScriptValue newArray(uint length = 0)
$method=|QScriptValue|newArray|uint=0

$prototype=QScriptValue newDate(const QDateTime & value)
$method=|QScriptValue|newDate|const QDateTime &

$prototype=QScriptValue newObject()
$internalMethod=|QScriptValue|newObject,newObject1|

$prototype=QScriptValue newObject(QScriptClass * scriptClass, const QScriptValue & data = QScriptValue())
$internalMethod=|QScriptValue|newObject,newObject2|QScriptClass *,const QScriptValue &=QScriptValue()

//[1]QScriptValue newObject()
//[2]QScriptValue newObject(QScriptClass * scriptClass, const QScriptValue & data = QScriptValue())

HB_FUNC_STATIC( QSCRIPTENGINE_NEWOBJECT )
{
  if( ISNUMPAR(0) )
  {
    QScriptEngine_newObject1();
  }
  else if( ISBETWEEN(1,2) && ISQSCRIPTCLASS(1) && (ISQSCRIPTVALUE(2)||ISNIL(2))  )
  {
    QScriptEngine_newObject2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue newQMetaObject(const QMetaObject * metaObject, const QScriptValue & ctor = QScriptValue())
$method=|QScriptValue|newQMetaObject|const QMetaObject *,const QScriptValue &=QScriptValue()

$prototype=QScriptValue newQObject(QObject * object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)
%% TODO: revisar
$internalMethod=|QScriptValue|newQObject,newQObject1|QObject *,QScriptEngine::ValueOwnership=QScriptEngine::QtOwnership,QScriptEngine::QObjectWrapOptions=0

$prototype=QScriptValue newQObject(const QScriptValue & scriptObject, QObject * qtObject, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)
%% TODO: revisar
$internalMethod=|QScriptValue|newQObject,newQObject2|const QScriptValue &,QObject *,QScriptEngine::ValueOwnership=QScriptEngine::QtOwnership,QScriptEngine::QObjectWrapOptions=0

//[1]QScriptValue newQObject(QObject * object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)
//[2]QScriptValue newQObject(const QScriptValue & scriptObject, QObject * qtObject, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)

HB_FUNC_STATIC( QSCRIPTENGINE_NEWQOBJECT )
{
  if( ISBETWEEN(1,3) && ISQOBJECT(1) && ISOPTNUM(2) && (ISNUM(3)||ISNIL(3)) )
  {
    QScriptEngine_newQObject1();
  }
  else if( ISBETWEEN(2,4) && ISQSCRIPTVALUE(1) && ISQOBJECT(2) && ISOPTNUM(3) && (ISNUM(4)||ISNIL(4)) )
  {
    QScriptEngine_newQObject2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue newRegExp(const QRegExp & regexp)
$internalMethod=|QScriptValue|newRegExp,newRegExp1|const QRegExp &

$prototype=QScriptValue newRegExp(const QString & pattern, const QString & flags)
$internalMethod=|QScriptValue|newRegExp,newRegExp2|const QString &,const QString &

//[1]QScriptValue newRegExp(const QRegExp & regexp)
//[2]QScriptValue newRegExp(const QString & pattern, const QString & flags)

HB_FUNC_STATIC( QSCRIPTENGINE_NEWREGEXP )
{
  if( ISNUMPAR(1) && ISQREGEXP(1) )
  {
    QScriptEngine_newRegExp1();
  }
  else if( ISNUMPAR(2) && ISCHAR(1) && ISCHAR(2) )
  {
    QScriptEngine_newRegExp2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue newVariant(const QVariant & value)
$internalMethod=|QScriptValue|newVariant,newVariant1|const QVariant &

$prototype=QScriptValue newVariant(const QScriptValue & object, const QVariant & value)
$internalMethod=|QScriptValue|newVariant,newVariant2|const QScriptValue &,const QVariant &

//[1]QScriptValue newVariant(const QVariant & value)
//[2]QScriptValue newVariant(const QScriptValue & object, const QVariant & value)

HB_FUNC_STATIC( QSCRIPTENGINE_NEWVARIANT )
{
  if( ISNUMPAR(1) && ISQVARIANT(1) )
  {
    QScriptEngine_newVariant1();
  }
  else if( ISNUMPAR(2) && ISQSCRIPTVALUE(1) && ISQVARIANT(2) )
  {
    QScriptEngine_newVariant2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue nullValue()
$method=|QScriptValue|nullValue|

$prototype=void popContext()
$method=|void|popContext|

$prototype=int processEventsInterval() const
$method=|int|processEventsInterval|

$prototype=QScriptContext * pushContext()
$method=|QScriptContext *|pushContext|

$prototype=void reportAdditionalMemoryCost(int size)
$method=|void|reportAdditionalMemoryCost|int

$prototype=void setAgent(QScriptEngineAgent * agent)
$method=|void|setAgent|QScriptEngineAgent *

$prototype=void setDefaultPrototype(int metaTypeId, const QScriptValue & prototype)
$method=|void|setDefaultPrototype|int,const QScriptValue &

$prototype=void setGlobalObject(const QScriptValue & object)
$method=|void|setGlobalObject|const QScriptValue &

$prototype=void setProcessEventsInterval(int interval)
$method=|void|setProcessEventsInterval|int

$prototype=QScriptValue toObject(const QScriptValue & value)
$method=|QScriptValue|toObject|const QScriptValue &

$prototype=QScriptString toStringHandle(const QString & str)
$method=|QScriptString|toStringHandle|const QString &

$prototype=QScriptValue uncaughtException() const
$method=|QScriptValue|uncaughtException|

$prototype=QStringList uncaughtExceptionBacktrace() const
$method=|QStringList|uncaughtExceptionBacktrace|

$prototype=int uncaughtExceptionLineNumber() const
$method=|int|uncaughtExceptionLineNumber|

$prototype=QScriptValue undefinedValue()
$method=|QScriptValue|undefinedValue|

$prototype=static QScriptSyntaxCheckResult checkSyntax(const QString & program)
$staticMethod=|QScriptSyntaxCheckResult|checkSyntax|const QString &

$beginSignals
$signal=|signalHandlerException(QScriptValue)
$endSignals

#pragma ENDDUMP

%%
%% Qt5xHb - Bindings libraries for Harbour/xHarbour and Qt Framework 5
%%
%% Copyright (C) 2018 Marcos Antonio Gambeta <marcosgambeta AT outlook DOT com>
%%

$header

#include "hbclass.ch"

$addRequests

$beginClassFrom=QObject

   METHOD new
   METHOD delete
   METHOD abortEvaluation
   METHOD agent
   METHOD availableExtensions
   METHOD clearExceptions
   METHOD collectGarbage
   METHOD currentContext
   METHOD defaultPrototype
   METHOD evaluate
   METHOD globalObject
   METHOD hasUncaughtException
   METHOD importExtension
   METHOD importedExtensions
   METHOD installTranslatorFunctions
   METHOD isEvaluating
   METHOD newArray
   METHOD newDate
   METHOD newObject
   METHOD newQMetaObject
   METHOD newQObject
   METHOD newRegExp
   METHOD newVariant
   METHOD nullValue
   METHOD popContext
   METHOD processEventsInterval
   METHOD pushContext
   METHOD reportAdditionalMemoryCost
   METHOD setAgent
   METHOD setDefaultPrototype
   METHOD setGlobalObject
   METHOD setProcessEventsInterval
   METHOD toObject
   METHOD toStringHandle
   METHOD uncaughtException
   METHOD uncaughtExceptionBacktrace
   METHOD uncaughtExceptionLineNumber
   METHOD undefinedValue
   METHOD checkSyntax

   METHOD onSignalHandlerException

$endClass

$destructor

#pragma BEGINDUMP

$includes

#include <QStringList>

$prototype=QScriptEngine()
$internalConstructor=|new1|

$prototype=QScriptEngine(QObject * parent)
$internalConstructor=|new2|QObject *

//[1]QScriptEngine()
//[2]QScriptEngine(QObject * parent)

HB_FUNC_STATIC( QSCRIPTENGINE_NEW )
{
  if( ISNUMPAR(0) )
  {
    QScriptEngine_new1();
  }
  else if( ISNUMPAR(1) && ISQOBJECT(1) )
  {
    QScriptEngine_new2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$deleteMethod

$prototype=void abortEvaluation(const QScriptValue & result = QScriptValue())
$method=|void|abortEvaluation|const QScriptValue &=QScriptValue()

$prototype=QScriptEngineAgent * agent() const
$method=|QScriptEngineAgent *|agent|

$prototype=QStringList availableExtensions() const
$method=|QStringList|availableExtensions|

$prototype=void clearExceptions()
$method=|void|clearExceptions|

$prototype=void collectGarbage()
$method=|void|collectGarbage|

$prototype=QScriptContext * currentContext() const
$method=|QScriptContext *|currentContext|

$prototype=QScriptValue defaultPrototype(int metaTypeId) const
$method=|QScriptValue|defaultPrototype|int

$prototype=QScriptValue evaluate(const QString & program, const QString & fileName = QString(), int lineNumber = 1)
$internalMethod=|QScriptValue|evaluate,evaluate1|const QString &,const QString &=QString(),int=1

$prototype=QScriptValue evaluate(const QScriptProgram & program)
$internalMethod=|QScriptValue|evaluate,evaluate2|const QScriptProgram &

//[1]QScriptValue evaluate(const QString & program, const QString & fileName = QString(), int lineNumber = 1)
//[2]QScriptValue evaluate(const QScriptProgram & program)

HB_FUNC_STATIC( QSCRIPTENGINE_EVALUATE )
{
  if( ISBETWEEN(1,3) && ISCHAR(1) && ISOPTCHAR(2) && ISOPTNUM(3) )
  {
    QScriptEngine_evaluate1();
  }
  else if( ISNUMPAR(1) && ISQSCRIPTPROGRAM(1) )
  {
    QScriptEngine_evaluate2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue globalObject() const
$method=|QScriptValue|globalObject|

$prototype=bool hasUncaughtException() const
$method=|bool|hasUncaughtException|

$prototype=QScriptValue importExtension(const QString & extension)
$method=|QScriptValue|importExtension|const QString &

$prototype=QStringList importedExtensions() const
$method=|QStringList|importedExtensions|

$prototype=void installTranslatorFunctions(const QScriptValue & object = QScriptValue())
$method=|void|installTranslatorFunctions|const QScriptValue &=QScriptValue()

$prototype=bool isEvaluating() const
$method=|bool|isEvaluating|

$prototype=QScriptValue newArray(uint length = 0)
$method=|QScriptValue|newArray|uint=0

$prototype=QScriptValue newDate(const QDateTime & value)
$method=|QScriptValue|newDate|const QDateTime &

$prototype=QScriptValue newObject()
$internalMethod=|QScriptValue|newObject,newObject1|

$prototype=QScriptValue newObject(QScriptClass * scriptClass, const QScriptValue & data = QScriptValue())
$internalMethod=|QScriptValue|newObject,newObject2|QScriptClass *,const QScriptValue &=QScriptValue()

//[1]QScriptValue newObject()
//[2]QScriptValue newObject(QScriptClass * scriptClass, const QScriptValue & data = QScriptValue())

HB_FUNC_STATIC( QSCRIPTENGINE_NEWOBJECT )
{
  if( ISNUMPAR(0) )
  {
    QScriptEngine_newObject1();
  }
  else if( ISBETWEEN(1,2) && ISQSCRIPTCLASS(1) && (ISQSCRIPTVALUE(2)||ISNIL(2))  )
  {
    QScriptEngine_newObject2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue newQMetaObject(const QMetaObject * metaObject, const QScriptValue & ctor = QScriptValue())
$method=|QScriptValue|newQMetaObject|const QMetaObject *,const QScriptValue &=QScriptValue()

$prototype=QScriptValue newQObject(QObject * object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)
%% TODO: revisar
$internalMethod=|QScriptValue|newQObject,newQObject1|QObject *,QScriptEngine::ValueOwnership=QScriptEngine::QtOwnership,QScriptEngine::QObjectWrapOptions=0

$prototype=QScriptValue newQObject(const QScriptValue & scriptObject, QObject * qtObject, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)
%% TODO: revisar
$internalMethod=|QScriptValue|newQObject,newQObject2|const QScriptValue &,QObject *,QScriptEngine::ValueOwnership=QScriptEngine::QtOwnership,QScriptEngine::QObjectWrapOptions=0

//[1]QScriptValue newQObject(QObject * object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)
//[2]QScriptValue newQObject(const QScriptValue & scriptObject, QObject * qtObject, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions & options = 0)

HB_FUNC_STATIC( QSCRIPTENGINE_NEWQOBJECT )
{
  if( ISBETWEEN(1,3) && ISQOBJECT(1) && ISOPTNUM(2) && (ISNUM(3)||ISNIL(3)) )
  {
    QScriptEngine_newQObject1();
  }
  else if( ISBETWEEN(2,4) && ISQSCRIPTVALUE(1) && ISQOBJECT(2) && ISOPTNUM(3) && (ISNUM(4)||ISNIL(4)) )
  {
    QScriptEngine_newQObject2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue newRegExp(const QRegExp & regexp)
$internalMethod=|QScriptValue|newRegExp,newRegExp1|const QRegExp &

$prototype=QScriptValue newRegExp(const QString & pattern, const QString & flags)
$internalMethod=|QScriptValue|newRegExp,newRegExp2|const QString &,const QString &

//[1]QScriptValue newRegExp(const QRegExp & regexp)
//[2]QScriptValue newRegExp(const QString & pattern, const QString & flags)

HB_FUNC_STATIC( QSCRIPTENGINE_NEWREGEXP )
{
  if( ISNUMPAR(1) && ISQREGEXP(1) )
  {
    QScriptEngine_newRegExp1();
  }
  else if( ISNUMPAR(2) && ISCHAR(1) && ISCHAR(2) )
  {
    QScriptEngine_newRegExp2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue newVariant(const QVariant & value)
$internalMethod=|QScriptValue|newVariant,newVariant1|const QVariant &

$prototype=QScriptValue newVariant(const QScriptValue & object, const QVariant & value)
$internalMethod=|QScriptValue|newVariant,newVariant2|const QScriptValue &,const QVariant &

//[1]QScriptValue newVariant(const QVariant & value)
//[2]QScriptValue newVariant(const QScriptValue & object, const QVariant & value)

HB_FUNC_STATIC( QSCRIPTENGINE_NEWVARIANT )
{
  if( ISNUMPAR(1) && ISQVARIANT(1) )
  {
    QScriptEngine_newVariant1();
  }
  else if( ISNUMPAR(2) && ISQSCRIPTVALUE(1) && ISQVARIANT(2) )
  {
    QScriptEngine_newVariant2();
  }
  else
  {
    hb_errRT_BASE( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
  }
}

$prototype=QScriptValue nullValue()
$method=|QScriptValue|nullValue|

$prototype=void popContext()
$method=|void|popContext|

$prototype=int processEventsInterval() const
$method=|int|processEventsInterval|

$prototype=QScriptContext * pushContext()
$method=|QScriptContext *|pushContext|

$prototype=void reportAdditionalMemoryCost(int size)
$method=|void|reportAdditionalMemoryCost|int

$prototype=void setAgent(QScriptEngineAgent * agent)
$method=|void|setAgent|QScriptEngineAgent *

$prototype=void setDefaultPrototype(int metaTypeId, const QScriptValue & prototype)
$method=|void|setDefaultPrototype|int,const QScriptValue &

$prototype=void setGlobalObject(const QScriptValue & object)
$method=|void|setGlobalObject|const QScriptValue &

$prototype=void setProcessEventsInterval(int interval)
$method=|void|setProcessEventsInterval|int

$prototype=QScriptValue toObject(const QScriptValue & value)
$method=|QScriptValue|toObject|const QScriptValue &

$prototype=QScriptString toStringHandle(const QString & str)
$method=|QScriptString|toStringHandle|const QString &

$prototype=QScriptValue uncaughtException() const
$method=|QScriptValue|uncaughtException|

$prototype=QStringList uncaughtExceptionBacktrace() const
$method=|QStringList|uncaughtExceptionBacktrace|

$prototype=int uncaughtExceptionLineNumber() const
$method=|int|uncaughtExceptionLineNumber|

$prototype=QScriptValue undefinedValue()
$method=|QScriptValue|undefinedValue|

$prototype=static QScriptSyntaxCheckResult checkSyntax(const QString & program)
$staticMethod=|QScriptSyntaxCheckResult|checkSyntax|const QString &

$beginSignals
$signal=|signalHandlerException(QScriptValue)
$endSignals

#pragma ENDDUMP


[DBF] Ignore Decimal byte for non numeric columns

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System.IO
USING XSharp.RDD.Enums
USING System.Collections.Generic
USING System.Linq
USING XSharp.RDD
// The classes below are simple. No properties, but all public fields.

BEGIN NAMESPACE XSharp.RDD.Support

/// Helper class to store the scope and codeblock for a DbEval() operation.
CLASS DbEvalInfo

	/// A code block to be evaluated with DbEval() on each row of the work area that is in the range defined by ScopeInfo.
	PUBLIC Block	 AS ICodeblock

	/// A DbScopeInfo structure limiting the evaluation of Block.
	PUBLIC ScopeInfo AS DbScopeInfo
    /// Construct a DbEvalInfo object.
    CONSTRUCTOR()
        SELF:ScopeInfo := DbScopeInfo{}
        RETURN
END CLASS

/// Helper class to store a filter condition for a table.
CLASS DbFilterInfo
	/// A string representing the source code for itmCobExpr.
	PUBLIC FilterText	AS STRING

	/// A code block representing the condition that is evaluated at each cursor location.  If the result of the evaluation is FALSE, the cursor location requested is invalid according to the current filter condition.
	PUBLIC FilterBlock	AS ICodeblock

	/// A flag that is TRUE if a filter is active.
	PUBLIC Active		AS LOGIC

	/// A flag that is TRUE if a filter is optimized.
	PUBLIC Optimized	AS LOGIC

	///Clear the filter fields.
	METHOD Clear() AS VOID
		SELF:FilterBlock := NULL
		SELF:FilterText	 := NULL
		SELF:Active		 := FALSE
		SELF:Optimized	 := FALSE
		RETURN

	///Clone the filter object.
	METHOD Clone AS DbFilterInfo
		LOCAL oCLone AS DbFilterInfo
		oCLone := DbFilterInfo{}
		oCLone:FilterBlock := SELF:FilterBlock
		oClone:FilterText  := SELF:FilterText
		oClone:Optimized   := SELF:Optimized
		oClone:Active	   := FALSE
		RETURN oClone

    /// Construct a DbFilterInfo object.
    CONSTRUCTOR
        SELF:Clear()
        RETURN

	METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:FilterBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:FilterText)
            SELF:FilterBlock := oRDD:Compile(SELF:FilterText)
        ENDIF
END CLASS

/// Helper structure to store information needed to lock a row or table for exclusive access.
STRUCTURE DbLockInfo
	/// An Item indicating the ID of the row to lock.  This member is meaningful only if Method is set to EXCLUSIVE or MULTIPLE.
	PUBLIC RecId		AS OBJECT

	/// A constant indicating the type of lock to obtain.  The possible values are of the Lockmethod enum.
	PUBLIC @@Method AS LockMethod

	/// A flag that is TRUE if the lock operation was successful.
	PUBLIC Result		AS LOGIC
	/// List of possible Locking Methods
	ENUM LockMethod
		/// Lock a row, releasing currently locked rows.
		MEMBER Exclusive := 1
		/// Lock a row, maintaining currently locked rows.
		MEMBER Multiple  := 2
		/// Lock a table, releasing locks currently held.
		MEMBER File 	 := 3
	END ENUM
END STRUCTURE

/// Helper class to store information needed to open a table.
CLASS DbOpenInfo
	/// Should the table be opened Readonly?
	PUBLIC ReadOnly 	AS LOGIC
	/// Should the table be opened Shared?
	PUBLIC Shared		AS LOGIC
	/// Unique Alias that the table has. This must be a valid XBase Identifier
	PUBLIC Alias		AS STRING
	/// The extension for the table that must be opened.
	PUBLIC Extension    AS STRING
	/// The filename (optionally includig a path) for the table that must be opened.
	PUBLIC FileName		AS STRING
	/// Workarea number in which the table will be opened.
	PUBLIC WorkArea		AS DWORD
    /// Construct a DbOpenInfo object.

	CONSTRUCTOR()
        SUPER()
    /// Construct a DbOpenInfo object.
	CONSTRUCTOR(sFileName AS STRING, sAlias AS STRING, dwWorkArea AS DWORD, lShared AS LOGIC, lReadOnly AS LOGIC)
		FileName 	:= sFileName
        Extension   := Path.GetExtension(sFileName)
		IF String.IsNullOrEmpty( sAlias )
			Alias := Path.GetFileNameWithoutExtension( sFileName )
		ELSE
			Alias	 	:= sAlias
		ENDIF
		WorkArea	:= dwWorkArea
		Shared		:= lShared
		ReadOnly	:= lReadOnly
	/// Return the numeric FileMode based on the Shared and Readonly flags
	PUBLIC PROPERTY FileMode AS DWORD
	GET
		LOCAL nMode AS DWORD
		nMode := FO_COMPAT
		IF (Shared)
			nMode |= FO_SHARED
		ELSE
			nMode |= FO_EXCLUSIVE
		ENDIF
		IF (ReadOnly)
			nMode |= FO_READ
		ELSE
			nMode |= FO_READWRITE
		ENDIF
		RETURN nMode
	END GET
	END PROPERTY
    PUBLIC METHOD Clone() AS DbOpenInfo
        RETURN (DbOpenInfo) SELF:MemberwiseClone()
END CLASS

/// Helper class to store information needed to create a conditional order.
CLASS DbOrderCondInfo
	///  A flag that is TRUE if one or more valid conditions have been specified in the structure.
	PUBLIC Active			AS LOGIC
	///  A flag that is TRUE if open orders should remain open while the new order is being created.
	PUBLIC Additive			AS LOGIC
	///  A flag that is TRUE if all rows are to be processed during order creation.
	PUBLIC All				AS LOGIC
	/// A flag that is TRUE if the new order will be a custom built order.
	PUBLIC Custom			AS LOGIC
	///  A flag that is TRUE if the order should be created in descending order.
	PUBLIC DESCENDING 	AS LOGIC
	/// A code block defining the expression to evaluate every StepSize rows during the creation of the order.  The code block referenced should return a logical value: TRUE indicates that creation of the order should continue normally, and FALSE indicates that order creation should terminate.
	PUBLIC EvalBlock		AS ICodeblock
	/// A code block defining the for condition to use for the creation and maintenance of the order.
	PUBLIC ForBlock			AS ICodeblock
	/// A string defining the for condition to use for the creation and maintenance of the order.
	PUBLIC ForExpression	AS STRING
	/// The number of rows to process for order creation.
	PUBLIC NextCount		AS LONG
	/// A flag that is TRUE if the for condition may NOT be optimized,
	PUBLIC NoOptimize		AS LOGIC
	///  A single row number to include in the order.
	PUBLIC RecNo			AS LONG
	/// A flag that is TRUE if only the rows specified by lStartRecno through end-of-file are to be included in the order.
	PUBLIC Rest				AS LOGIC
	/// A flag indicating whether the order is to be scoped. fScoped will be TRUE if WhileBlock, NextCount, Recno, Rest, or All is specified.
	PUBLIC Scoped			AS LOGIC
	/// The row at which to begin processing when either the NextCount or Rest scoping options are specified.
	PUBLIC StartRecNo		AS LONG
	/// The frequency of the evaluation of EvalBlock.
	PUBLIC StepSize			AS LONG
	/// A flag that is TRUE if only rows in the controlling order are to be included in the order.
	PUBLIC UseCurrent		AS LOGIC
	/// A code block defining the while condition to use for the creation of the order.  An empty value indicates that no while condition is being imposed.
	PUBLIC WhileBlock		AS ICodeblock
	/// A string defining the for while condition to use for the creation and maintenance of the order.
	PUBLIC WhileExpression	AS STRING

    METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:WhileBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:WhileExpression)
            SELF:WhileBlock := oRDD:Compile(SELF:WhileExpression)
        ENDIF
        IF SELF:ForBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:ForExpression)
            SELF:ForBlock := oRDD:Compile(SELF:ForExpression)
        ENDIF
    METHOD Validate() AS VOID
        SELF:Active := FALSE
        SELF:Scoped := FALSE
        IF SELF:All .OR. SELF:ForBlock != NULL .OR. SELF:WhileBlock != NULL .OR.  ! String.IsNullOrEmpty(SELF:ForExpression ) ;
            .OR. SELF:NextCount != 0 .OR. SELF:RecNo != 0 .OR. SELF:Rest  .OR. SELF:Descending .OR. ! String.IsNullOrEmpty(SELF:WhileExpression)
            SELF:Active := TRUE
        ENDIF
        IF SELF:EvalBlock != NULL .AND. SELF:StepSize == 0
            SELF:StepSize := 1
        ENDIF
        IF SELF:Active
            IF SELF:All .OR. SELF:WhileBlock != NULL .OR. SELF:NextCount != 0 .OR. SELF:RecNo != 0 .OR. SELF:Rest
                SELF:Scoped := TRUE
            ENDIF
        ENDIF

    METHOD Clone() AS DbOrderCondInfo
        RETURN (DbOrderCondInfo) SELF:MemberwiseClone()

END CLASS

/// Helper class to store information needed to create a new order.
CLASS DbOrderCreateInfo
	/// The index file name.
	PUBLIC BagName		AS STRING
	/// The order name or number to create in BagName.
	PUBLIC Order		AS OBJECT
	/// The key expression defining the order.
	PUBLIC Expression	AS STRING
	/// A flag that is TRUE if the order should contain only unique keys.
	PUBLIC Unique		AS LOGIC
	/// A code block containing the key expression defining the order imposed on the work area.
	PUBLIC Block		AS ICodeblock
	/// A DbOrderCondInfo object containing information about the condition (if any) for the order.
	PUBLIC OrdCondInfo	AS DbOrderCondInfo

    METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:Block == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:Expression)
            SELF:Block := oRDD:Compile(SELF:Expression)
        ENDIF
        IF SELF:OrdCondInfo != NULL
            SELF:OrdCondInfo:Compile(oRDD)
        ENDIF

   METHOD Clone() AS DbOrderCreateInfo
        RETURN (DbOrderCreateInfo) SELF:MemberwiseClone()

END CLASS

/// Helper class to store information needed to open/address an order.
CLASS DbOrderInfo
	/// A flag that is TRUE if all tags of the index file must be opened.
	PUBLIC AllTags		AS LOGIC
	/// A code block containing the key expression defining the order imposed on the work area.
	PUBLIC Expression	AS ICodeblock
	/// An object containing the order name or number
	PUBLIC Order		AS OBJECT
	/// The index file name.
	PUBLIC BagName		AS STRING
	/// Return value for some order operations.
	PUBLIC Result		AS OBJECT

    METHOD Clone() AS DbOrderInfo
        RETURN (DbOrderInfo) SELF:MemberwiseClone()
    PROPERTY IsEmpty AS LOGIC
        GET
            IF Order == NULL
                RETURN String.IsNullOrEmpty(BagName)
            ENDIF
            IF Order IS LONG .AND. (LONG) Order = 0
                RETURN String.IsNullOrEmpty(BagName)
            ENDIF
            RETURN FALSE
        END GET
    END PROPERTY
END CLASS

/// Helper class to store a list of relational information.
CLASS DbRelInfo
	/// The expression used to reposition the cursor of the child table when this relation is resolved.
	PUBLIC Key			AS STRING
	/// A code block used to reposition the cursor of the child table when this relation is resolved.
	PUBLIC Block		AS ICodeblock
	/// A reference to the child RDD for the relation.
	PUBLIC Child		AS IRDD
	/// A reference to the parent RDD for the relation.
	PUBLIC Parent		AS IRDD

    /// name of the relation. Defaults to the parent alias = '_' + child alias.
	PUBLIC Name         AS STRING
    METHOD Compile() AS VOID
        IF SELF:Block == NULL .AND. SELF:Parent != NULL .AND. ! String.IsNullOrWhiteSpace(SELF:Key)
            SELF:Block := SELF:Parent:Compile(SELF:Key)
        ENDIF

    METHOD Clone() AS DbRelInfo
        RETURN (DbRelInfo) SELF:MemberwiseClone()

END CLASS

/// Helper class to store references to all of the scope clause expressions.
CLASS DbScopeInfo
	/// A flag that is TRUE if a process should ignore duplicate key values.
	PUBLIC IgnoreDuplicates AS LOGIC
	/// A flag that is TRUE if a process should ignore any filter condition imposed on the current work area.
	PUBLIC IgnoreFilter		AS LOGIC
	///  A flag that is TRUE if a process should include deleted rows.
	PUBLIC IncludeDeleted	AS LOGIC
	/// A code block representing the conditional for clause.  A for condition is, essentially, a filter that hides rows for which the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC ForBlock			AS ICodeblock
	/// A string representing the conditional for clause.  A for condition is, essentially, a filter that hides rows for which the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC ForExpression	AS STRING
	/// A flag that is TRUE if the last row of the current scope is required.
	PUBLIC Last				AS LOGIC
	/// Permits continuation of a process for the next lNext rows, while obeying for and while clauses.
	PUBLIC NextCount		AS LONG
	/// Permits continuation of a process for a single row number, while obeying for and while clauses.
	PUBLIC RecId			AS OBJECT
	/// A flag that is TRUE if a process should continue stepping through data from the current work area cursor position until logical end-of-file.
	PUBLIC Rest				AS LOGIC
	/// A code block representing the conditional while clause.  A while condition permits continuation of a process that steps through rows until the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC WhileBlock		AS ICodeblock
	/// A string representing the conditional while clause.  A while condition permits continuation of a process that steps through rows until the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC WhileExpression	AS STRING
	/// Construct a DbScopeInfo object.
	CONSTRUCTOR()
		SELF:Clear()

	///Clear the scope fields.
	PUBLIC METHOD Clear() AS VOID
		IgnoreDuplicates := FALSE
		IgnoreFilter	 := FALSE
		IncludeDeleted 	 := FALSE
		ForBlock		 := NULL
		ForExpression	 := NULL
		Last			 := FALSE
		NextCount		 := 0
		RecId			 := NULL
		Rest			 := FALSE
		WhileBlock		 := NULL
		WhileExpression  := NULL

	///Clone the scopeinfo object.
	METHOD Clone AS DbScopeInfo
		RETURN (DbScopeInfo) SELF:MemberwiseClone()

	METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:WhileBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:WhileExpression)
            SELF:WhileBlock := oRDD:Compile(SELF:WhileExpression)
        ENDIF
        IF SELF:ForBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:ForExpression)
            SELF:ForBlock := oRDD:Compile(SELF:ForExpression)
        ENDIF
END CLASS

/// Helper structure to store information needed to perform a seek operation
STRUCTURE DbSeekInfo
	/// A flag that is TRUE if the last occurrence of the specified key value is to be sought, rather than the first.
	PUBLIC Last 	AS LOGIC
	/// A flag that is TRUE if a soft seek is to be performed.
	PUBLIC SoftSeek AS LOGIC
	/// An object containing the key value to find.
	PUBLIC Value AS OBJECT
END STRUCTURE

/// Helper class to store information needed to perform a physical sort.
CLASS DbSortInfo
	/// A DbTransInfo object holding the destination work area, column transfer information, and scoping information for the Sort() method.
	PUBLIC TransInfo  AS DbTransInfo
	/// An array of DbSortItem structures defining the key values for the sort.  Note that the key values are processed in the order that they appear in this array.
	PUBLIC Items	  AS DbSortItem[]
	/// Number of items in the Items array.
    PROPERTY ItemCount  AS LONG GET Items:Length
    /// Construct a DbSortInfo object.
    CONSTRUCTOR(transItemCount AS LONG, sortItemCount AS LONG)
        SELF:TransInfo := DbTransInfo{transItemCount}
        SELF:Items     := DbSortItem[]{sortItemCount}
        RETURN
END CLASS

/// Helper structure to store information about a single sort key value.
STRUCTURE DbSortItem
	/// A one-based index indicating the column on which the sort is based.
	PUBLIC FieldNo 	AS LONG
	/// The offset of the field in the workarea buffer.
	PUBLIC OffSet	AS LONG
	/// The length of the field in the workarea buffer.
	PUBLIC Length	AS LONG
	/// One or more constants that function as sort optimization and control flags.
    /// They are passed to your RDD Sort() routine from the high-level wrapper function for the DBSort() function.
	PUBLIC Flags	AS  DbSortFlags

END STRUCTURE

/// Helper class to store information needed for the global transfer of data items from one work area to another.
CLASS DbTransInfo
	/// A DbScopeInfo object describing the limits of the scope of the transfer.
	PUBLIC Scope		AS DbScopeInfo
	/// The source work area.
	PUBLIC Source		AS IRDD
	/// The destination work area.
	PUBLIC Destination 	AS IRDD
	/// An array of DbTransItem structures defining the items to transfer to the destination work area. This is usually a list of column mappings from the source to the destination.
	PUBLIC Items		AS DbTransItem[]
	/// Transfer attributes specified using one or more of the constants Match or PutRec.
	PUBLIC Flags		AS DbTransInfoFlags
    /// Number of items in the Items array.
    PUBLIC PROPERTY ItemCount AS LONG AUTO
    /// Construct a DbTransInfo object.
    CONSTRUCTOR(itemCount AS LONG)
        SELF:Items := DbTransItem[]{itemCount}
        SELF:Scope := DbScopeInfo{}
        SELF:ItemCount := itemCount
        SELF:Flags := DbTransInfoFlags.None
END CLASS

/// Helper structure to store information about a single piece of data (usually a column) to transfer from one work area to another.
STRUCTURE DbTransItem
	/// A one-based field index in the source work area.
	PUBLIC Source 		AS LONG
	/// A one-based field index in the destination work area.
	PUBLIC Destination 	AS LONG
END STRUCTURE

/// Helper class for the RDD system to store field information
CLASS RddFieldInfo
	PUBLIC Name 		AS STRING
	PUBLIC FieldType 	AS DBFieldType
	PUBLIC Length 		AS LONG
	PUBLIC Decimals 	AS LONG
	PUBLIC Alias 		AS STRING
    	PUBLIC Flags        AS DbfFieldFlags
	PUBLIC Offset       AS LONG

     /// Construct a RddFieldInfo object.
	CONSTRUCTOR(sName AS STRING, sType AS STRING, nLength AS LONG, nDecimals AS LONG, nOffSet := -1 AS LONG)
		Name 		:= sName
		Length 		:= nLength
		Decimals 	:= nDecimals
        	Flags       := DbfFieldFlags.None
		IF !String.IsNullOrEmpty(sType)
			FieldType := (DbFieldType) Char.ToUpper(sType[0])
			IF sType:IndexOf("0",1) >= 0
			    Flags |= DbfFieldFlags.Nullable
			ENDIF
			IF FieldType:IsBinary() .OR. sType:IndexOf("B", 1) >= 0
			    Flags |= DbfFieldFlags.Binary
			ENDIF
            IF sType:Contains('+')
                Flags |= DbfFieldFlags.AutoIncrement
            ENDIF
		ELSE
			FieldType := DBFieldType.Unknown
		ENDIF
		IF String.Compare(Name, _NULLFLAGS, TRUE) == 0
		    Flags |= DbfFieldFlags.System
		    Flags |= DbfFieldFlags.Binary
		ENDIF
		Alias       := sName
		SELF:Offset := nOffSet
		RETURN
    /// Construct a RddFieldInfo object.
	CONSTRUCTOR(sName AS STRING, nType AS DbFieldType, nLength AS LONG, nDecimals AS LONG, nOffSet := -1 AS LONG, nFlags := DbfFieldFlags.None AS DbfFieldFlags)
		SELF:Name 		:= sName
		SELF:FieldType 	:= nType
		SELF:Length 	:= nLength
		SELF:Decimals 	:= nDecimals
		SELF:Alias      := sName
		SELF:Offset     := nOffSet
        	SELF:Flags      := nFLags
		RETURN

    CONSTRUCTOR(oInfo AS RddFieldInfo)
 		SELF:Name 		:= oInfo:Name
		SELF:FieldType 	:= oInfo:FieldType
		SELF:Length 	:= oInfo:Length
		SELF:Alias      := oInfo:Alias
		SELF:Flags      := oInfo:Flags
		SELF:OffSet     := oInfo:OffSet
        IF SELF:FieldType:HasDecimals()
        	SELF:Decimals 	:= oInfo:Decimals
        ENDIF

    /// Clone a RddFieldInfo object.
	METHOD Clone() AS RddFieldInfo
        VAR info := (RddFieldInfo) SELF:MemberwiseClone()
        RETURN info

    /// Check if two fields match in type, length and decimals.
    METHOD SameType(oFld AS RDDFieldInfo) AS LOGIC
        RETURN SELF:FieldType == oFld:FieldType .AND. SELF:Length == oFld:Length .AND. SELF:Decimals == oFld:Decimals

    VIRTUAL METHOD Validate() AS LOGIC
        RETURN TRUE

    OVERRIDE METHOD ToString() AS STRING
        RETURN SELF:Name+" ('"+SELF:FieldTypeStr+"',"+SELF:Length:ToString()+","+SELF:Decimals:ToString()+","+SELF:Flags:ToString()+")"

    PROPERTY FieldTypeStr AS STRING GET ((CHAR) SELF:FieldType):ToString()
    PROPERTY IsMemo      AS LOGIC GET SELF:FieldType:IsMemo()
    PROPERTY IsBinary    AS LOGIC GET SELF:FieldType:IsBinary()
    PROPERTY IsNullable  AS LOGIC GET SELF:Flags:HasFlag(DbfFieldFlags.Nullable)
    PROPERTY IsAutoIncrement AS LOGIC GET SELF:Flags:HasFLag(DbfFieldFlags.AutoIncrement)
    PROPERTY IsStandard  AS LOGIC GET SELF:FieldType:IsStandard()
    PROPERTY IsVfp       AS LOGIC GET SELF:FieldType:IsVfp()
    PROPERTY IsVarLength AS LOGIC GET SELF:FieldType:IsVarLength()

END CLASS

STATIC CLASS RDDExtensions
    STATIC METHOD IsMemo(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DBFieldType.Memo
        CASE DbFieldType.Picture
        CASE DbFieldType.General
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsVarLength(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DbFieldType.VarBinary
        CASE DbFieldType.VarChar
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsStandard(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DbFieldType.Character
        CASE DbFieldType.Date
        CASE DbFieldType.Logic
        CASE DbFieldType.Memo
        CASE DbFieldType.Number
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsBinary(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DBFieldType.Integer
        CASE DbFieldType.Currency
        CASE DbFieldType.Double
        CASE DbFieldType.Picture
        CASE DbFieldType.Blob
        CASE DbFieldType.VarBinary
        CASE DbFieldType.VarChar
        CASE DbFieldType.DateTime
            RETURN TRUE
        END SWITCH
        RETURN FALSE
    STATIC METHOD HasDecimals(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DbFieldType.Double
        CASE DbFieldType.Float
        CASE DBFieldType.Number
            RETURN TRUE
        END SWITCH
        RETURN FALSE
    STATIC METHOD IsVfp(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DBFieldType.Character
        CASE DbFieldType.Blob
        CASE DbFieldType.Currency
        CASE DBFieldType.Date
        CASE DBFieldType.DateTime
        CASE DbFieldType.Double
        CASE DbFieldType.Float
        CASE DbFieldType.General
        CASE DBFieldType.Integer
        CASE DBFieldType.Logic
        CASE DBFieldType.Memo
        CASE DBFieldType.Number
        CASE DbFieldType.Picture
        CASE DbFieldType.VarBinary
        CASE DbFieldType.VarChar
        CASE DbFieldType.NullFlags
            RETURN TRUE
        END SWITCH
        RETURN FALSE
END CLASS
END NAMESPACE

BEGIN NAMESPACE XSharp

/// Helper class for VoDbTrans and VoDbSort()
CLASS _FieldNames
    /// List of field names.
    PUBLIC fields AS STRING[]
    /// Number of fields in the list.
    PROPERTY fieldCount AS LONG GET fields:Length
    /// Construct a _FieldNames object.
    CONSTRUCTOR (aFields AS IList<STRING>)
        SELF:Fields := aFields:ToArray()
        RETURN
END CLASS

/// Helper class for DbJoin()
CLASS _JoinList
    /// Area number of destination workarea.
    PUBLIC uiDestSel AS DWORD
    /// List of field areas and positions.
    PUBLIC Fields AS _JoinField[]
    /// Number of fields in the list.
    PUBLIC PROPERTY Count AS LONG GET Fields:Length
    /// Construct a _JoinList object.
    PUBLIC CONSTRUCTOR(nFields AS LONG)
        SELF:Fields := _JoinField[]{nFields}
        RETURN
END CLASS

/// Helper structure for DbJoin()
STRUCTURE _JoinField
    /// Source workarea number.
    PUBLIC Area AS DWORD
    /// Source field position.
    PUBLIC Pos  AS DWORD
END STRUCTURE

/// Helper structure to store information for a list of RDD names for DbUseArea()
STRUCTURE _RddList
    /// List of RDD names.
    EXPORT atomRddName AS STRING[]
    /// Number of names in the list.
    PROPERTY uiRDDCount AS DWORD GET (DWORD) atomRDDName:Length

    /// Construct _RddList from class Tree.
    CONSTRUCTOR(oRDD AS WorkArea)
        VAR names := List<STRING>{}
        VAR type  := oRDD:GetType()
        DO WHILE type != typeof(WorkArea)
            VAR name := type:Name:ToUpper()
            // map names to VO compatible names
            IF name == "DBF"
                names:Add("CAVODBF")
            ELSE
                names:Add(name)
            ENDIF
            type := type:BaseType
        ENDDO
        names:Reverse()
        atomRDDName := names:ToArray()
    /// Construct _RddList from list of names.
    CONSTRUCTOR(aNames AS STRING[])
        atomRDDName := aNames
        RETURN

END STRUCTURE
END NAMESPACE

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System.IO
USING XSharp.RDD.Enums
USING System.Collections.Generic
USING System.Linq
USING XSharp.RDD
// The classes below are simple. No properties, but all public fields.

BEGIN NAMESPACE XSharp.RDD.Support

/// Helper class to store the scope and codeblock for a DbEval() operation.
CLASS DbEvalInfo

	/// A code block to be evaluated with DbEval() on each row of the work area that is in the range defined by ScopeInfo.
	PUBLIC Block	 AS ICodeblock

	/// A DbScopeInfo structure limiting the evaluation of Block.
	PUBLIC ScopeInfo AS DbScopeInfo
    /// Construct a DbEvalInfo object.
    CONSTRUCTOR()
        SELF:ScopeInfo := DbScopeInfo{}
        RETURN
END CLASS

/// Helper class to store a filter condition for a table.
CLASS DbFilterInfo
	/// A string representing the source code for itmCobExpr.
	PUBLIC FilterText	AS STRING

	/// A code block representing the condition that is evaluated at each cursor location.  If the result of the evaluation is FALSE, the cursor location requested is invalid according to the current filter condition.
	PUBLIC FilterBlock	AS ICodeblock

	/// A flag that is TRUE if a filter is active.
	PUBLIC Active		AS LOGIC

	/// A flag that is TRUE if a filter is optimized.
	PUBLIC Optimized	AS LOGIC

	///Clear the filter fields.
	METHOD Clear() AS VOID
		SELF:FilterBlock := NULL
		SELF:FilterText	 := NULL
		SELF:Active		 := FALSE
		SELF:Optimized	 := FALSE
		RETURN

	///Clone the filter object.
	METHOD Clone AS DbFilterInfo
		LOCAL oCLone AS DbFilterInfo
		oCLone := DbFilterInfo{}
		oCLone:FilterBlock := SELF:FilterBlock
		oClone:FilterText  := SELF:FilterText
		oClone:Optimized   := SELF:Optimized
		oClone:Active	   := FALSE
		RETURN oClone

    /// Construct a DbFilterInfo object.
    CONSTRUCTOR
        SELF:Clear()
        RETURN

	METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:FilterBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:FilterText)
            SELF:FilterBlock := oRDD:Compile(SELF:FilterText)
        ENDIF
END CLASS

/// Helper structure to store information needed to lock a row or table for exclusive access.
STRUCTURE DbLockInfo
	/// An Item indicating the ID of the row to lock.  This member is meaningful only if Method is set to EXCLUSIVE or MULTIPLE.
	PUBLIC RecId		AS OBJECT

	/// A constant indicating the type of lock to obtain.  The possible values are of the Lockmethod enum.
	PUBLIC @@Method AS LockMethod

	/// A flag that is TRUE if the lock operation was successful.
	PUBLIC Result		AS LOGIC
	/// List of possible Locking Methods
	ENUM LockMethod
		/// Lock a row, releasing currently locked rows.
		MEMBER Exclusive := 1
		/// Lock a row, maintaining currently locked rows.
		MEMBER Multiple  := 2
		/// Lock a table, releasing locks currently held.
		MEMBER File 	 := 3
	END ENUM
END STRUCTURE

/// Helper class to store information needed to open a table.
CLASS DbOpenInfo
	/// Should the table be opened Readonly?
	PUBLIC ReadOnly 	AS LOGIC
	/// Should the table be opened Shared?
	PUBLIC Shared		AS LOGIC
	/// Unique Alias that the table has. This must be a valid XBase Identifier
	PUBLIC Alias		AS STRING
	/// The extension for the table that must be opened.
	PUBLIC Extension    AS STRING
	/// The filename (optionally includig a path) for the table that must be opened.
	PUBLIC FileName		AS STRING
	/// Workarea number in which the table will be opened.
	PUBLIC WorkArea		AS DWORD
    /// Construct a DbOpenInfo object.

	CONSTRUCTOR()
        SUPER()
    /// Construct a DbOpenInfo object.
	CONSTRUCTOR(sFileName AS STRING, sAlias AS STRING, dwWorkArea AS DWORD, lShared AS LOGIC, lReadOnly AS LOGIC)
		FileName 	:= sFileName
        Extension   := Path.GetExtension(sFileName)
		IF String.IsNullOrEmpty( sAlias )
			Alias := Path.GetFileNameWithoutExtension( sFileName )
		ELSE
			Alias	 	:= sAlias
		ENDIF
		WorkArea	:= dwWorkArea
		Shared		:= lShared
		ReadOnly	:= lReadOnly
	/// Return the numeric FileMode based on the Shared and Readonly flags
	PUBLIC PROPERTY FileMode AS DWORD
	GET
		LOCAL nMode AS DWORD
		nMode := FO_COMPAT
		IF (Shared)
			nMode |= FO_SHARED
		ELSE
			nMode |= FO_EXCLUSIVE
		ENDIF
		IF (ReadOnly)
			nMode |= FO_READ
		ELSE
			nMode |= FO_READWRITE
		ENDIF
		RETURN nMode
	END GET
	END PROPERTY
    PUBLIC METHOD Clone() AS DbOpenInfo
        RETURN (DbOpenInfo) SELF:MemberwiseClone()
END CLASS

/// Helper class to store information needed to create a conditional order.
CLASS DbOrderCondInfo
	///  A flag that is TRUE if one or more valid conditions have been specified in the structure.
	PUBLIC Active			AS LOGIC
	///  A flag that is TRUE if open orders should remain open while the new order is being created.
	PUBLIC Additive			AS LOGIC
	///  A flag that is TRUE if all rows are to be processed during order creation.
	PUBLIC All				AS LOGIC
	/// A flag that is TRUE if the new order will be a custom built order.
	PUBLIC Custom			AS LOGIC
	///  A flag that is TRUE if the order should be created in descending order.
	PUBLIC DESCENDING 	AS LOGIC
	/// A code block defining the expression to evaluate every StepSize rows during the creation of the order.  The code block referenced should return a logical value: TRUE indicates that creation of the order should continue normally, and FALSE indicates that order creation should terminate.
	PUBLIC EvalBlock		AS ICodeblock
	/// A code block defining the for condition to use for the creation and maintenance of the order.
	PUBLIC ForBlock			AS ICodeblock
	/// A string defining the for condition to use for the creation and maintenance of the order.
	PUBLIC ForExpression	AS STRING
	/// The number of rows to process for order creation.
	PUBLIC NextCount		AS LONG
	/// A flag that is TRUE if the for condition may NOT be optimized,
	PUBLIC NoOptimize		AS LOGIC
	///  A single row number to include in the order.
	PUBLIC RecNo			AS LONG
	/// A flag that is TRUE if only the rows specified by lStartRecno through end-of-file are to be included in the order.
	PUBLIC Rest				AS LOGIC
	/// A flag indicating whether the order is to be scoped. fScoped will be TRUE if WhileBlock, NextCount, Recno, Rest, or All is specified.
	PUBLIC Scoped			AS LOGIC
	/// The row at which to begin processing when either the NextCount or Rest scoping options are specified.
	PUBLIC StartRecNo		AS LONG
	/// The frequency of the evaluation of EvalBlock.
	PUBLIC StepSize			AS LONG
	/// A flag that is TRUE if only rows in the controlling order are to be included in the order.
	PUBLIC UseCurrent		AS LOGIC
	/// A code block defining the while condition to use for the creation of the order.  An empty value indicates that no while condition is being imposed.
	PUBLIC WhileBlock		AS ICodeblock
	/// A string defining the for while condition to use for the creation and maintenance of the order.
	PUBLIC WhileExpression	AS STRING

    METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:WhileBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:WhileExpression)
            SELF:WhileBlock := oRDD:Compile(SELF:WhileExpression)
        ENDIF
        IF SELF:ForBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:ForExpression)
            SELF:ForBlock := oRDD:Compile(SELF:ForExpression)
        ENDIF
    METHOD Validate() AS VOID
        SELF:Active := FALSE
        SELF:Scoped := FALSE
        IF SELF:All .OR. SELF:ForBlock != NULL .OR. SELF:WhileBlock != NULL .OR.  ! String.IsNullOrEmpty(SELF:ForExpression ) ;
            .OR. SELF:NextCount != 0 .OR. SELF:RecNo != 0 .OR. SELF:Rest  .OR. SELF:Descending .OR. ! String.IsNullOrEmpty(SELF:WhileExpression)
            SELF:Active := TRUE
        ENDIF
        IF SELF:EvalBlock != NULL .AND. SELF:StepSize == 0
            SELF:StepSize := 1
        ENDIF
        IF SELF:Active
            IF SELF:All .OR. SELF:WhileBlock != NULL .OR. SELF:NextCount != 0 .OR. SELF:RecNo != 0 .OR. SELF:Rest
                SELF:Scoped := TRUE
            ENDIF
        ENDIF

    METHOD Clone() AS DbOrderCondInfo
        RETURN (DbOrderCondInfo) SELF:MemberwiseClone()

END CLASS

/// Helper class to store information needed to create a new order.
CLASS DbOrderCreateInfo
	/// The index file name.
	PUBLIC BagName		AS STRING
	/// The order name or number to create in BagName.
	PUBLIC Order		AS OBJECT
	/// The key expression defining the order.
	PUBLIC Expression	AS STRING
	/// A flag that is TRUE if the order should contain only unique keys.
	PUBLIC Unique		AS LOGIC
	/// A code block containing the key expression defining the order imposed on the work area.
	PUBLIC Block		AS ICodeblock
	/// A DbOrderCondInfo object containing information about the condition (if any) for the order.
	PUBLIC OrdCondInfo	AS DbOrderCondInfo

    METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:Block == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:Expression)
            SELF:Block := oRDD:Compile(SELF:Expression)
        ENDIF
        IF SELF:OrdCondInfo != NULL
            SELF:OrdCondInfo:Compile(oRDD)
        ENDIF

   METHOD Clone() AS DbOrderCreateInfo
        RETURN (DbOrderCreateInfo) SELF:MemberwiseClone()

END CLASS

/// Helper class to store information needed to open/address an order.
CLASS DbOrderInfo
	/// A flag that is TRUE if all tags of the index file must be opened.
	PUBLIC AllTags		AS LOGIC
	/// A code block containing the key expression defining the order imposed on the work area.
	PUBLIC Expression	AS ICodeblock
	/// An object containing the order name or number
	PUBLIC Order		AS OBJECT
	/// The index file name.
	PUBLIC BagName		AS STRING
	/// Return value for some order operations.
	PUBLIC Result		AS OBJECT

    METHOD Clone() AS DbOrderInfo
        RETURN (DbOrderInfo) SELF:MemberwiseClone()
    PROPERTY IsEmpty AS LOGIC
        GET
            IF Order == NULL
                RETURN String.IsNullOrEmpty(BagName)
            ENDIF
            IF Order IS LONG .AND. (LONG) Order = 0
                RETURN String.IsNullOrEmpty(BagName)
            ENDIF
            RETURN FALSE
        END GET
    END PROPERTY
END CLASS

/// Helper class to store a list of relational information.
CLASS DbRelInfo
	/// The expression used to reposition the cursor of the child table when this relation is resolved.
	PUBLIC Key			AS STRING
	/// A code block used to reposition the cursor of the child table when this relation is resolved.
	PUBLIC Block		AS ICodeblock
	/// A reference to the child RDD for the relation.
	PUBLIC Child		AS IRDD
	/// A reference to the parent RDD for the relation.
	PUBLIC Parent		AS IRDD

    /// name of the relation. Defaults to the parent alias = '_' + child alias.
	PUBLIC Name         AS STRING
    METHOD Compile() AS VOID
        IF SELF:Block == NULL .AND. SELF:Parent != NULL .AND. ! String.IsNullOrWhiteSpace(SELF:Key)
            SELF:Block := SELF:Parent:Compile(SELF:Key)
        ENDIF

    METHOD Clone() AS DbRelInfo
        RETURN (DbRelInfo) SELF:MemberwiseClone()

END CLASS

/// Helper class to store references to all of the scope clause expressions.
CLASS DbScopeInfo
	/// A flag that is TRUE if a process should ignore duplicate key values.
	PUBLIC IgnoreDuplicates AS LOGIC
	/// A flag that is TRUE if a process should ignore any filter condition imposed on the current work area.
	PUBLIC IgnoreFilter		AS LOGIC
	///  A flag that is TRUE if a process should include deleted rows.
	PUBLIC IncludeDeleted	AS LOGIC
	/// A code block representing the conditional for clause.  A for condition is, essentially, a filter that hides rows for which the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC ForBlock			AS ICodeblock
	/// A string representing the conditional for clause.  A for condition is, essentially, a filter that hides rows for which the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC ForExpression	AS STRING
	/// A flag that is TRUE if the last row of the current scope is required.
	PUBLIC Last				AS LOGIC
	/// Permits continuation of a process for the next lNext rows, while obeying for and while clauses.
	PUBLIC NextCount		AS LONG
	/// Permits continuation of a process for a single row number, while obeying for and while clauses.
	PUBLIC RecId			AS OBJECT
	/// A flag that is TRUE if a process should continue stepping through data from the current work area cursor position until logical end-of-file.
	PUBLIC Rest				AS LOGIC
	/// A code block representing the conditional while clause.  A while condition permits continuation of a process that steps through rows until the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC WhileBlock		AS ICodeblock
	/// A string representing the conditional while clause.  A while condition permits continuation of a process that steps through rows until the condition evaluates to FALSE.  The string value is provided for storage, while the code block is provided as a parameter for the EvalBlock() method.
	PUBLIC WhileExpression	AS STRING
	/// Construct a DbScopeInfo object.
	CONSTRUCTOR()
		SELF:Clear()

	///Clear the scope fields.
	PUBLIC METHOD Clear() AS VOID
		IgnoreDuplicates := FALSE
		IgnoreFilter	 := FALSE
		IncludeDeleted 	 := FALSE
		ForBlock		 := NULL
		ForExpression	 := NULL
		Last			 := FALSE
		NextCount		 := 0
		RecId			 := NULL
		Rest			 := FALSE
		WhileBlock		 := NULL
		WhileExpression  := NULL

	///Clone the scopeinfo object.
	METHOD Clone AS DbScopeInfo
		RETURN (DbScopeInfo) SELF:MemberwiseClone()

	METHOD Compile(oRDD AS IRDD) AS VOID
        IF SELF:WhileBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:WhileExpression)
            SELF:WhileBlock := oRDD:Compile(SELF:WhileExpression)
        ENDIF
        IF SELF:ForBlock == NULL .AND. ! String.IsNullOrWhiteSpace(SELF:ForExpression)
            SELF:ForBlock := oRDD:Compile(SELF:ForExpression)
        ENDIF
END CLASS

/// Helper structure to store information needed to perform a seek operation
STRUCTURE DbSeekInfo
	/// A flag that is TRUE if the last occurrence of the specified key value is to be sought, rather than the first.
	PUBLIC Last 	AS LOGIC
	/// A flag that is TRUE if a soft seek is to be performed.
	PUBLIC SoftSeek AS LOGIC
	/// An object containing the key value to find.
	PUBLIC Value AS OBJECT
END STRUCTURE

/// Helper class to store information needed to perform a physical sort.
CLASS DbSortInfo
	/// A DbTransInfo object holding the destination work area, column transfer information, and scoping information for the Sort() method.
	PUBLIC TransInfo  AS DbTransInfo
	/// An array of DbSortItem structures defining the key values for the sort.  Note that the key values are processed in the order that they appear in this array.
	PUBLIC Items	  AS DbSortItem[]
	/// Number of items in the Items array.
    PROPERTY ItemCount  AS LONG GET Items:Length
    /// Construct a DbSortInfo object.
    CONSTRUCTOR(transItemCount AS LONG, sortItemCount AS LONG)
        SELF:TransInfo := DbTransInfo{transItemCount}
        SELF:Items     := DbSortItem[]{sortItemCount}
        RETURN
END CLASS

/// Helper structure to store information about a single sort key value.
STRUCTURE DbSortItem
	/// A one-based index indicating the column on which the sort is based.
	PUBLIC FieldNo 	AS LONG
	/// The offset of the field in the workarea buffer.
	PUBLIC OffSet	AS LONG
	/// The length of the field in the workarea buffer.
	PUBLIC Length	AS LONG
	/// One or more constants that function as sort optimization and control flags.
    /// They are passed to your RDD Sort() routine from the high-level wrapper function for the DBSort() function.
	PUBLIC Flags	AS  DbSortFlags

END STRUCTURE

/// Helper class to store information needed for the global transfer of data items from one work area to another.
CLASS DbTransInfo
	/// A DbScopeInfo object describing the limits of the scope of the transfer.
	PUBLIC Scope		AS DbScopeInfo
	/// The source work area.
	PUBLIC Source		AS IRDD
	/// The destination work area.
	PUBLIC Destination 	AS IRDD
	/// An array of DbTransItem structures defining the items to transfer to the destination work area. This is usually a list of column mappings from the source to the destination.
	PUBLIC Items		AS DbTransItem[]
	/// Transfer attributes specified using one or more of the constants Match or PutRec.
	PUBLIC Flags		AS DbTransInfoFlags
    /// Number of items in the Items array.
    PUBLIC PROPERTY ItemCount AS LONG AUTO
    /// Construct a DbTransInfo object.
    CONSTRUCTOR(itemCount AS LONG)
        SELF:Items := DbTransItem[]{itemCount}
        SELF:Scope := DbScopeInfo{}
        SELF:ItemCount := itemCount
        SELF:Flags := DbTransInfoFlags.None
END CLASS

/// Helper structure to store information about a single piece of data (usually a column) to transfer from one work area to another.
STRUCTURE DbTransItem
	/// A one-based field index in the source work area.
	PUBLIC Source 		AS LONG
	/// A one-based field index in the destination work area.
	PUBLIC Destination 	AS LONG
END STRUCTURE

/// Helper class for the RDD system to store field information
CLASS RddFieldInfo
	PUBLIC Name 		AS STRING
	PUBLIC FieldType 	AS DBFieldType
	PUBLIC Length 		AS LONG
	PUBLIC Decimals 	AS LONG
	PUBLIC Alias 		AS STRING
    	PUBLIC Flags        AS DbfFieldFlags
	PUBLIC Offset       AS LONG

     /// Construct a RddFieldInfo object.
	CONSTRUCTOR(sName AS STRING, sType AS STRING, nLength AS LONG, nDecimals AS LONG, nOffSet := -1 AS LONG)
		Name 		:= sName
		Length 		:= nLength
		Decimals 	:= nDecimals
        	Flags       := DbfFieldFlags.None
		IF !String.IsNullOrEmpty(sType)
			FieldType := (DbFieldType) Char.ToUpper(sType[0])
			IF sType:IndexOf("0",1) >= 0
			    Flags |= DbfFieldFlags.Nullable
			ENDIF
			IF FieldType:IsBinary() .OR. sType:IndexOf("B", 1) >= 0
			    Flags |= DbfFieldFlags.Binary
			ENDIF
            IF sType:Contains('+')
                Flags |= DbfFieldFlags.AutoIncrement
            ENDIF
		ELSE
			FieldType := DBFieldType.Unknown
		ENDIF
		IF String.Compare(Name, _NULLFLAGS, TRUE) == 0
		    Flags |= DbfFieldFlags.System
		    Flags |= DbfFieldFlags.Binary
		ENDIF
		Alias       := sName
		SELF:Offset := nOffSet
		RETURN
    /// Construct a RddFieldInfo object.
	CONSTRUCTOR(sName AS STRING, nType AS DbFieldType, nLength AS LONG, nDecimals AS LONG, nOffSet := -1 AS LONG, nFlags := DbfFieldFlags.None AS DbfFieldFlags)
		SELF:Name 		:= sName
		SELF:FieldType 	:= nType
		SELF:Length 	:= nLength
		SELF:Decimals 	:= nDecimals
		SELF:Alias      := sName
		SELF:Offset     := nOffSet
        	SELF:Flags      := nFLags
		RETURN

    CONSTRUCTOR(oInfo AS RddFieldInfo)
 		SELF:Name 		:= oInfo:Name
		SELF:FieldType 	:= oInfo:FieldType
		SELF:Length 	:= oInfo:Length
		SELF:Decimals 	:= oInfo:Decimals
		SELF:Alias      := oInfo:Alias
		SELF:Flags      := oInfo:Flags
		SELF:OffSet     := oInfo:OffSet

    /// Clone a RddFieldInfo object.
	METHOD Clone() AS RddFieldInfo
        VAR info := (RddFieldInfo) SELF:MemberwiseClone()
        RETURN info

    /// Check if two fields match in type, length and decimals.
    METHOD SameType(oFld AS RDDFieldInfo) AS LOGIC
        RETURN SELF:FieldType == oFld:FieldType .AND. SELF:Length == oFld:Length .AND. SELF:Decimals == oFld:Decimals

    VIRTUAL METHOD Validate() AS LOGIC
        RETURN TRUE

    OVERRIDE METHOD ToString() AS STRING
        RETURN SELF:Name+" ('"+SELF:FieldTypeStr+"',"+SELF:Length:ToString()+","+SELF:Decimals:ToString()+","+SELF:Flags:ToString()+")"

    PROPERTY FieldTypeStr AS STRING GET ((CHAR) SELF:FieldType):ToString()
    PROPERTY IsMemo      AS LOGIC GET SELF:FieldType:IsMemo()
    PROPERTY IsBinary    AS LOGIC GET SELF:FieldType:IsBinary()
    PROPERTY IsNullable  AS LOGIC GET SELF:Flags:HasFlag(DbfFieldFlags.Nullable)
    PROPERTY IsAutoIncrement AS LOGIC GET SELF:Flags:HasFLag(DbfFieldFlags.AutoIncrement)
    PROPERTY IsStandard  AS LOGIC GET SELF:FieldType:IsStandard()
    PROPERTY IsVfp       AS LOGIC GET SELF:FieldType:IsVfp()
    PROPERTY IsVarLength AS LOGIC GET SELF:FieldType:IsVarLength()

END CLASS

STATIC CLASS RDDExtensions
    STATIC METHOD IsMemo(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DBFieldType.Memo
        CASE DbFieldType.Picture
        CASE DbFieldType.General
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsVarLength(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DbFieldType.VarBinary
        CASE DbFieldType.VarChar
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsStandard(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DbFieldType.Character
        CASE DbFieldType.Date
        CASE DbFieldType.Logic
        CASE DbFieldType.Memo
        CASE DbFieldType.Number
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsBinary(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DBFieldType.Integer
        CASE DbFieldType.Currency
        CASE DbFieldType.Double
        CASE DbFieldType.Picture
        CASE DbFieldType.Blob
        CASE DbFieldType.VarBinary
        CASE DbFieldType.VarChar
        CASE DbFieldType.DateTime
            RETURN TRUE
        END SWITCH
        RETURN FALSE

    STATIC METHOD IsVfp(SELF eType AS DBFieldType ) AS LOGIC
        SWITCH eType
        CASE DBFieldType.Character
        CASE DbFieldType.Blob
        CASE DbFieldType.Currency
        CASE DBFieldType.Date
        CASE DBFieldType.DateTime
        CASE DbFieldType.Double
        CASE DbFieldType.Float
        CASE DbFieldType.General
        CASE DBFieldType.Integer
        CASE DBFieldType.Logic
        CASE DBFieldType.Memo
        CASE DBFieldType.Number
        CASE DbFieldType.Picture
        CASE DbFieldType.VarBinary
        CASE DbFieldType.VarChar
        CASE DbFieldType.NullFlags
            RETURN TRUE
        END SWITCH
        RETURN FALSE
END CLASS
END NAMESPACE

BEGIN NAMESPACE XSharp

/// Helper class for VoDbTrans and VoDbSort()
CLASS _FieldNames
    /// List of field names.
    PUBLIC fields AS STRING[]
    /// Number of fields in the list.
    PROPERTY fieldCount AS LONG GET fields:Length
    /// Construct a _FieldNames object.
    CONSTRUCTOR (aFields AS IList<STRING>)
        SELF:Fields := aFields:ToArray()
        RETURN
END CLASS

/// Helper class for DbJoin()
CLASS _JoinList
    /// Area number of destination workarea.
    PUBLIC uiDestSel AS DWORD
    /// List of field areas and positions.
    PUBLIC Fields AS _JoinField[]
    /// Number of fields in the list.
    PUBLIC PROPERTY Count AS LONG GET Fields:Length
    /// Construct a _JoinList object.
    PUBLIC CONSTRUCTOR(nFields AS LONG)
        SELF:Fields := _JoinField[]{nFields}
        RETURN
END CLASS

/// Helper structure for DbJoin()
STRUCTURE _JoinField
    /// Source workarea number.
    PUBLIC Area AS DWORD
    /// Source field position.
    PUBLIC Pos  AS DWORD
END STRUCTURE

/// Helper structure to store information for a list of RDD names for DbUseArea()
STRUCTURE _RddList
    /// List of RDD names.
    EXPORT atomRddName AS STRING[]
    /// Number of names in the list.
    PROPERTY uiRDDCount AS DWORD GET (DWORD) atomRDDName:Length

    /// Construct _RddList from class Tree.
    CONSTRUCTOR(oRDD AS WorkArea)
        VAR names := List<STRING>{}
        VAR type  := oRDD:GetType()
        DO WHILE type != typeof(WorkArea)
            VAR name := type:Name:ToUpper()
            // map names to VO compatible names
            IF name == "DBF"
                names:Add("CAVODBF")
            ELSE
                names:Add(name)
            ENDIF
            type := type:BaseType
        ENDDO
        names:Reverse()
        atomRDDName := names:ToArray()
    /// Construct _RddList from list of names.
    CONSTRUCTOR(aNames AS STRING[])
        atomRDDName := aNames
        RETURN

END STRUCTURE
END NAMESPACE


[rdd/dbf] Shared input buffer instance (buffer locking)

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

// Please note that this code code expects zero based arrays
#pragma options ("az", ON)

USING System
USING System.Collections.Generic
USING System.Text
USING System.IO
USING XSharp.RDD.Enums
USING XSharp.RDD.Support

BEGIN NAMESPACE XSharp.RDD

	CLASS InputBuffer
        CONST INBUFFER_MAX_SIZE := 16384 AS INT

        PROTECT _stream        AS Stream
        PROTECT _name          AS STRING
        PROTECT _recordLength  AS LONG
        PROTECT _headerLength  AS LONG
        PROTECT _shared        AS LOGIC

        PROTECT _look_ahead    AS INT
        PROTECT _look_behind   AS INT
        PROTECT _inBuffer      AS BYTE[]
        PROTECT PROPERTY _inBufferOfs AS LONG GET _weakBuffer:InBufferOfs SET _weakBuffer:InBufferOfs := VALUE
        PROTECT PROPERTY _inBufferLen   AS LONG GET _weakBuffer:InBufferLen SET _weakBuffer:InBufferLen := VALUE
        PROTECT PROPERTY _inBufferTick  AS INT GET _weakBuffer:InBufferTick SET _weakBuffer:InBufferTick := VALUE

        PRIVATE _weakBuffer    AS WeakBuffer

        CLASS WeakBuffer
            INTERNAL RefCount := 1      AS WORD
            INTERNAL Buffer             AS BYTE[]
            INTERNAL InBufferOfs := 0   AS LONG
            INTERNAL InBufferLen := 0   AS LONG
            INTERNAL InBufferTick := 0  AS INT
            CONSTRUCTOR(size AS LONG)
                Buffer := BYTE[]{size}
            INTERNAL METHOD Resize(size AS LONG) AS VOID
                System.Array.Resize(REF Buffer, size)
        END CLASS

        PRIVATE STATIC BufferCache := Dictionary<STRING, WeakBuffer>{} AS Dictionary<STRING, WeakBuffer>

        CONSTRUCTOR(stream AS Stream, headerLength AS INT, recordLength AS INT, shared AS LOGIC) AS VOID
            _stream := stream
            _name := (stream ASTYPE FileStream)?:Name
            _recordLength := recordLength
            _headerLength := headerLength
            _shared := shared

            VAR nRec := INBUFFER_MAX_SIZE / SELF:_recordLength
            _look_ahead := nRec - nRec/4
            _look_behind := nRec - _look_ahead - 1

            IF _look_ahead > 0 && _look_behind >= 0
                VAR size := (1+SELF:_look_ahead+SELF:_look_behind)*SELF:_recordLength
                IF _name != NULL
                    BEGIN LOCK BufferCache
                        LOCAL t AS WeakBuffer
                        IF BufferCache:TryGetValue(_name, OUT t)
                            t:RefCount += 1
                            IF size != t:Buffer:Length
                                t:Resize(size)
                            ENDIF
                        ELSE
                            t := WeakBuffer{size}
                            BufferCache:Add(_name, t)
                        ENDIF
                        _weakBuffer := t
                        _inBuffer := t:Buffer
                    END LOCK
                ELSE
                    _weakBuffer := WeakBuffer{size}
                    _inBuffer := _weakBuffer:Buffer
                ENDIF
            ELSE
                _weakBuffer := NULL
                _inBuffer := NULL
            ENDIF

            RETURN

        DESTRUCTOR()
                IF _name != NULL
                    BEGIN LOCK BufferCache
                        LOCAL t AS WeakBuffer
                        IF BufferCache:TryGetValue(_name, OUT t)
                            t:RefCount -= 1
                            IF t:RefCount < 1
                                BufferCache:Remove(_name)
                            ENDIF
                        ENDIF
                    END LOCK
                ENDIF
            RETURN

        PRIVATE METHOD ReadAt(position AS LONG, buffer AS BYTE[], offset AS LONG, length AS LONG) AS LONG
            LOCAL result AS LONG
            TRY
                _stream:Position := position
                result := _stream:Read(buffer, offset, length)
            CATCH
                result := -1
            END TRY
            RETURN result

        PRIVATE METHOD WriteAt(position AS LONG, buffer AS BYTE[], offset AS LONG, length AS LONG) AS LOGIC
            LOCAL result AS LOGIC
            TRY
                _stream:Position := position
                _stream:Write(buffer, offset, length)
                result := TRUE
            CATCH
                result := FALSE
            END TRY
            RETURN result

        METHOD Read(offset AS LONG, buffer AS BYTE[], size AS LONG) AS LOGIC
            LOCAL tick := 0 AS INT
            IF _inBuffer == NULL
                RETURN SELF:ReadAt(offset, buffer, 0, size) == size
            ENDIF
            BEGIN LOCK _weakBuffer
                IF SELF:_shared
                    VAR refresh := XSharp.RuntimeState.GetValue<REAL8>(Set.Refresh)
                    IF refresh < 0
                        RETURN SELF:ReadAt(offset, buffer, 0, size) == size
                    ENDIF
                    tick := System.Environment.TickCount
                    IF refresh > 0 .AND. (tick - _inBufferTick) >= 1000*refresh
                        _inBufferLen := 0
                    ENDIF
                ENDIF
                IF _inBufferOfs > offset .OR. _inBufferOfs+_inBufferLen < offset+size
                    LOCAL ofs AS LONG
                    IF offset > _inBufferOfs
                        ofs := offset - SELF:_look_behind*SELF:_recordLength
                    ELSE
                        ofs := offset - SELF:_look_ahead*SELF:_recordLength
                    ENDIF
                    IF ofs < SELF:_headerLength
                        ofs := SELF:_headerLength
                    ENDIF
                    VAR len := _inBuffer:Length
                    VAR bwd := FALSE
                    IF ofs > _inBufferOfs .AND. ofs < _inBufferOfs+_inBufferLen
                        VAR delta := ofs - _inBufferOfs
                        _inBufferLen -= delta
                        _inBufferOfs := ofs
                        ofs += _inBufferLen
                        len -= _inBufferLen
                        Array.Copy(_inBuffer, delta, _inBuffer, 0, _inBufferLen)
                    ELSEIF ofs < _inBufferOfs .AND. ofs+len > _inBufferOfs .AND. _inBufferLen > 0
                        VAR delta := _inBufferOfs - ofs
                        IF _inBufferLen+delta > len
                            _inBufferLen -= _inBufferLen + delta - len
                        ENDIF
                        _inBufferOfs := ofs
                        len := delta
                        bwd := TRUE
                        Array.Copy(_inBuffer, 0, _inBuffer, delta, _inBufferLen)
                    ELSE
                        _inBufferLen := 0
                        _inBufferOfs := ofs
                    ENDIF

                    _inBufferTick := tick
                    VAR res := SELF:ReadAt(ofs, _inBuffer, ofs-_inBufferOfs, len)
                    IF res > 0
                        _inBufferLen += res
                        IF bwd .AND. res != len
                            _inBufferLen := res
                        ENDIF
                    ELSE
                        _inBufferLen := 0
                    ENDIF

                    IF _inBufferOfs+_inBufferLen < offset+size
                        RETURN FALSE
                    ENDIF
                ENDIF
                Array.Copy( _inBuffer, offset - _inBufferOfs, buffer, 0, size )
            END LOCK
            RETURN TRUE

        METHOD Write(offset AS LONG, buffer AS BYTE[], size AS LONG) AS LOGIC
            VAR res := SELF:WriteAt(offset, buffer, 0, size)
            IF res .AND. _inBuffer != NULL
                BEGIN LOCK _weakBuffer
                    IF offset <= _inBufferOfs+_inBufferLen .AND. offset+size >= _inBufferOfs
                        VAR buffer_ofs := Math.Max( 0, _inBufferOfs - offset )
                        Array.Copy( buffer, buffer_ofs, _inBuffer, Math.Max( 0, offset - _inBufferOfs), size - buffer_ofs )
                    ENDIF
                END LOCK
            ENDIF
            RETURN res

        METHOD Invalidate() AS VOID
            _inBufferOfs := 0
            _inBufferLen := 0
            RETURN
    END CLASS

END NAMESPACE // XSharp.RDD

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

// Please note that this code code expects zero based arrays
#pragma options ("az", ON)

USING System
USING System.Collections.Generic
USING System.Text
USING System.IO
USING XSharp.RDD.Enums
USING XSharp.RDD.Support

BEGIN NAMESPACE XSharp.RDD

	CLASS InputBuffer
        CONST INBUFFER_MAX_SIZE := 16384 AS INT

        PROTECT _stream        AS Stream
        PROTECT _name          AS STRING
        PROTECT _recordLength  AS LONG
        PROTECT _headerLength  AS LONG
        PROTECT _shared        AS LOGIC

        PROTECT _look_ahead    AS INT
        PROTECT _look_behind   AS INT
        PROTECT _inBuffer      AS BYTE[]
        PROTECT _inBufferOfs   AS LONG
        PROTECT _inBufferLen   AS LONG
        PROTECT _inBufferTick  AS INT

        CLASS WeakBuffer
            INTERNAL RefCount := 1 AS WORD
            INTERNAL Buffer AS BYTE[]
            CONSTRUCTOR(size AS LONG)
                Buffer := BYTE[]{size}
            INTERNAL METHOD Resize(size AS LONG) AS VOID
                System.Array.Resize(REF Buffer, size)
        END CLASS

        PRIVATE STATIC BufferCache := Dictionary<STRING, WeakBuffer>{} AS Dictionary<STRING, WeakBuffer>

        CONSTRUCTOR(stream AS Stream, headerLength AS INT, recordLength AS INT, shared AS LOGIC) AS VOID
            _stream := stream
            _name := (stream ASTYPE FileStream)?:Name
            _recordLength := recordLength
            _headerLength := headerLength
            _shared := shared
            _inBufferOfs := 0
            _inBufferLen := 0

            VAR nRec := INBUFFER_MAX_SIZE / SELF:_recordLength
            _look_ahead := nRec - nRec/4
            _look_behind := nRec - _look_ahead - 1

            IF _look_ahead > 0 && _look_behind >= 0
                IF _name != NULL
                    BEGIN LOCK BufferCache
                        LOCAL t AS WeakBuffer
                        VAR size := (1+SELF:_look_ahead+SELF:_look_behind)*SELF:_recordLength
                        IF BufferCache:TryGetValue(_name, OUT t)
                            t:RefCount += 1
                            IF size != t:Buffer:Length
                                t:Resize(size)
                            ENDIF
                        ELSE
                            t := WeakBuffer{size}
                            BufferCache:Add(_name, t)
                        ENDIF
                        _inBuffer := t:Buffer
                    END LOCK
                ELSE
                    _inBuffer := BYTE[]{(1+SELF:_look_ahead+SELF:_look_behind)*SELF:_recordLength}
                ENDIF
            ELSE
                _inBuffer := NULL
            ENDIF

            RETURN

        DESTRUCTOR()
                IF _name != NULL
                    BEGIN LOCK BufferCache
                        LOCAL t AS WeakBuffer
                        IF BufferCache:TryGetValue(_name, OUT t)
                            t:RefCount -= 1
                            IF t:RefCount < 1
                                BufferCache:Remove(_name)
                            ENDIF
                        ENDIF
                    END LOCK
                ENDIF
            RETURN

        PRIVATE METHOD ReadAt(position AS LONG, buffer AS BYTE[], offset AS LONG, length AS LONG) AS LONG
            LOCAL result AS LONG
            TRY
                _stream:Position := position
                result := _stream:Read(buffer, offset, length)
            CATCH
                result := -1
            END TRY
            RETURN result

        PRIVATE METHOD WriteAt(position AS LONG, buffer AS BYTE[], offset AS LONG, length AS LONG) AS LOGIC
            LOCAL result AS LOGIC
            TRY
                _stream:Position := position
                _stream:Write(buffer, offset, length)
                result := TRUE
            CATCH
                result := FALSE
            END TRY
            RETURN result

        METHOD Read(offset AS LONG, buffer AS BYTE[], size AS LONG) AS LOGIC
            LOCAL tick := 0 AS INT
            IF _inBuffer == NULL
                RETURN SELF:ReadAt(offset, buffer, 0, size) == size
            ENDIF
            IF SELF:_shared
                VAR refresh := XSharp.RuntimeState.GetValue<REAL8>(Set.Refresh)
                IF refresh < 0
                    RETURN SELF:ReadAt(offset, buffer, 0, size) == size
                ENDIF
                tick := System.Environment.TickCount
                IF refresh > 0 .AND. (tick - _inBufferTick) >= 1000*refresh
                    _inBufferLen := 0
                ENDIF
            ENDIF
            IF _inBufferOfs > offset .OR. _inBufferOfs+_inBufferLen < offset+size
                LOCAL ofs AS LONG
                IF offset > _inBufferOfs
                    ofs := offset - SELF:_look_behind*SELF:_recordLength
                ELSE
                    ofs := offset - SELF:_look_ahead*SELF:_recordLength
                ENDIF
                IF ofs < SELF:_headerLength
                    ofs := SELF:_headerLength
                ENDIF
                VAR len := _inBuffer:Length
                VAR bwd := FALSE
                IF ofs > _inBufferOfs .AND. ofs < _inBufferOfs+_inBufferLen
                    VAR delta := ofs - _inBufferOfs
                    _inBufferLen -= delta
                    _inBufferOfs := ofs
                    ofs += _inBufferLen
                    len -= _inBufferLen
                    Array.Copy(_inBuffer, delta, _inBuffer, 0, _inBufferLen)
                ELSEIF ofs < _inBufferOfs .AND. ofs+len > _inBufferOfs .AND. _inBufferLen > 0
                    VAR delta := _inBufferOfs - ofs
                    IF _inBufferLen+delta > len
                        _inBufferLen -= _inBufferLen + delta - len
                    ENDIF
                    _inBufferOfs := ofs
                    len := delta
                    bwd := TRUE
                    Array.Copy(_inBuffer, 0, _inBuffer, delta, _inBufferLen)
                ELSE
                    _inBufferLen := 0
                    _inBufferOfs := ofs
                ENDIF

                _inBufferTick := tick
                VAR res := SELF:ReadAt(ofs, _inBuffer, ofs-_inBufferOfs, len)
                IF res > 0
                    _inBufferLen += res
                    IF bwd .AND. res != len
                        _inBufferLen := res
                    ENDIF
                ELSE
                    _inBufferLen := 0
                ENDIF

                IF _inBufferOfs+_inBufferLen < offset+size
                    RETURN FALSE
                ENDIF
            ENDIF
            Array.Copy( _inBuffer, offset - _inBufferOfs, buffer, 0, size )
            RETURN TRUE

        METHOD Write(offset AS LONG, buffer AS BYTE[], size AS LONG) AS LOGIC
            VAR res := SELF:WriteAt(offset, buffer, 0, size)
            IF res .AND. _inBuffer != NULL
                IF offset <= _inBufferOfs+_inBufferLen .AND. offset+size >= _inBufferOfs
                    VAR buffer_ofs := Math.Max( 0, _inBufferOfs - offset )
                    Array.Copy( buffer, buffer_ofs, _inBuffer, Math.Max( 0, offset - _inBufferOfs), size - buffer_ofs )
                ENDIF
            ENDIF
            RETURN res

        METHOD Invalidate() AS VOID
            _inBufferOfs := 0
            _inBufferLen := 0
            RETURN
    END CLASS

END NAMESPACE // XSharp.RDD