//*****************************************************************************
//
// FILE:        DBaseVar.h
//
// WRITTEN BY:  Keimpe
//
// DATE:        1/94
//
// UPDATED:     5/95
//
// REVISION:    $Revision:   2.16  $
//
// VERSION:     Visual dBASE
//
// DESCRIPTION:
//              Header for Visual dBASE EXTERN examples.
//
//              This file defines the DBaseVar and DVar classes. DBaseVar
//              member functions make the actual calls into the EXTERN system.
//              The DVar class is a "smart pointer" wrapper around the DBaseVar
//              class to facilitate usage of local DBaseVar objects.
//
//*****************************************************************************

// Definitions of the DBaseVar and DVar classes.

#ifndef DBASEVAR_H

   // Used to test programs including DBaseVar.h under DOS.
#ifndef DOSTEST

#include <windows.h>
#include "dbaseext.h"

   // End of DOSTEST.
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <limits.h>

   // If you want to test the C++ class under DOS, define DOSTEST.
#ifndef DOSTEST

//
// Macro to use what ever kind of exception handling that is desired.
//
#ifndef DBASETHROW
#define DBASETHROW  DBase()->ReturnError()   // Throw to dBASE, show error
#endif


// DBaseVar class.

class DBaseVar {

public:

   ///////// Routines to get parts of a DBaseVar object. /////////

   BOOL Logical(){
      BOOL b;
      if( DBase()->VarGetLogical(this,&b) != 0){
         DBASETHROW;
      }
      return b;
   }

   DoubleType Double(){
      DoubleType d;
      if( DBase()->VarGetDouble(this,&d) != 0){
         DBASETHROW;
      }
      return d;
   }

   long Long(){
      long l;
      if( DBase()->VarGetLong(this,&l) != 0){
         DBASETHROW;
      }
      return l;
   }

   char *String(){
      char *pStr;
      if( DBase()->VarGetString(this,&pStr) != 0){
         DBASETHROW;
      }
      return pStr;
   }

   int StringLen(){
      int Len;
      if( DBase()->VarGetStringLen(this,&Len) != 0){
         DBASETHROW;
      }
      return Len;
   }

   char *StringBuffer(){
      char *pStr;
      if( (pStr = DBase()->VarGetStringBuffer(this)) == NULL){
         DBASETHROW;
      }
      return pStr;
   }

   void Property(char *PropName, DBaseVar *Result){

         // Convert PropName to upper case.
      strupr( PropName );

      if( DBase()->VarGetProperty(this,PropName,Result) != 0){
         DBASETHROW;
      }
   }

   void Element(DBaseVar *Result, int Size, DBaseVar **Index){
      if( DBase()->VarGetElement(this,Result,Size,Index) != 0 ){
         DBASETHROW;
      }
   }

   char Type(){
      return DBase()->VarGetType(this);
   }


   ///////// Routines to set parts of a DBaseVar object. /////////

   void Set( DBaseVar *Original ){
      DBase()->VarSetVar( this, Original );
   }

   BOOL SetLogical(BOOL b){
      DBase()->VarSetLogical(this,b);
      return b;
   }

   DoubleType SetDouble(DoubleType d){
      DBase()->VarSetDouble(this,d);
      return d;
   }

   long SetLong(long l){
      DBase()->VarSetLong(this,l);
      return l;
   }

   char *SetZString( char *pStr ){
      DBase()->VarSetZString(this,pStr);
      return pStr;
   }

   void SetStringLen(int Len){
      DBase()->VarSetStringLen(this,Len);
   }

   void SetProperty(char *PropName, DBaseVar *pVar){

         // Convert PropName to upper case.
      strupr( PropName );

      if(DBase()->VarSetProperty(this,PropName,pVar)){
         DBASETHROW;
      }
   }

   void SetElement(int cDim, DBaseVar **ppVars, DBaseVar *pValue){
      if(DBase()->VarSetElement(this,cDim,ppVars,pValue)){
         DBASETHROW;
      }
   }

   void SetCodeBlock(char* code){
      if(DBase()->VarSetCodeBlock(this,code)){
         DBASETHROW;
      }
   }


   ///////// Routine to execute a codeblock of a DBaseVar object. /////////

   void RunCodeBlock(DBaseVar *pDest, int iParaCount, DBaseVar** ppParas){
      if(DBase()->VarRunCode(this,pDest,iParaCount,ppParas)){
         DBASETHROW;
      }
   }
};

//
//  A DVar is a smart pointer to a DBaseVar.  When used in a structure or
//  as a local variable, the variable's construction and destruction is
//  managed.
//  There are conversion and access operators to automatically manage the
//  variable as a DBaseVar.
//
//  NOTE: DVARs can't be used as parameters of functions that are called
//        directly from Visual dBASE.  DVar parameters trigger a destructor
//        call at the end of the function because the function is assumed
//        to be called with temporary DVar objects as arguments.  Functions
//        called from Visual dBASE however are called with DBaseVar *'s as
//        arguments.


   // Property is used to detect if a DVAR is not used as a parameter
   // of a function called by the Visual dBASE side.
#ifndef NDEBUG
#define SETPROPERTY Property = 12345
#else
#define SETPROPERTY
#endif

class DVar {
private:
   DBaseVar *pVar;
   long      Property;     // Used to ensure it's really a DVar
public:
   //
   // Member access treats DVar's and DBaseVars the same.
   //
   DBaseVar * operator ->(){
      return pVar;
   }

   //
   // Any function that expects a DBaseVar* can also accept a DVar
   //
   operator DBaseVar*(){
      return pVar;
   }

   //
   // Utility function to force conversion to a DBaseVar (in ... cases)
   //
   DBaseVar* Var(){
      return pVar;
   }

   //
   // Constructors
   //
   DVar(){                           // Default constructor
      pVar = DBase()->MakeVar();
      SETPROPERTY;
   }

   DVar(DBaseVar *original){         // Construct from DBaseVar *
      pVar = DBase()->MakeVar();
      pVar->Set(original);
      SETPROPERTY;
   }

   DVar(BOOL b){                     // Construct from BOOL
      pVar = DBase()->MakeVar();
      pVar->SetLogical(b);
      SETPROPERTY;
   }

   DVar(DoubleType d){              // Construct from double
      pVar = DBase()->MakeVar();
      pVar->SetDouble(d);
      SETPROPERTY;
   }

   DVar(double d){                    // Construct from double
      pVar = DBase()->MakeVar();
      pVar->SetDouble(d);
      SETPROPERTY;
   }


   DVar(long l){                     // Construct from long
      pVar = DBase()->MakeVar();
      pVar->SetLong(l);
      SETPROPERTY;
   }

   DVar(char *pVal){                 // Construct from char *
      pVar = DBase()->MakeVar();
      pVar->SetZString(pVal);
      SETPROPERTY;
   }

   //
   // Destructor
   //
   ~DVar(){
#ifndef NDEBUG
      assert( Property == 12345 );
#endif
      DBase()->DestroyVar(pVar);

   }
};

   // End of DOSTEST.
#endif

#define DBASEVAR_H
#endif
