/*  xbexpfnc.cpp

    Xbase64 project source code

    This file contains logic for handling Xbase expressions.

    Copyright (C) 1997,2003  Gary A Kunkel
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


    Contact:
    
     Email:
    
      xdb-devel@lists.sourceforge.net
      xdb-users@lists.sourceforge.net
      
      
     Regular Mail:
     
       XBase Support
       149C South Main St
       Keller Texas, 76248     
       USA
*/

#ifdef __WIN32__
#include <xbase64/xbwincfg.h>
#else
#include <xbase64/xbconfig.h>
#endif

#include <xbase64/xbase64.h>
#ifdef XB_EXPRESSIONS

#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <xbase64/xbexp.h>
//#include <xbase64/xbexcept.h>


/*! \file xbexpfnc.cpp
*/

/*************************************************************************/
//! Short description.
/*!
  \param Func
*/
xbShort xbExpn::ProcessFunction( char * Func )
{
/* 1 - pop function from stack
   2 - verify function name and get no of parms needed 
   3 - verify no of parms >= remainder of stack
   4 - pop parms off stack
   5 - execute function
   6 - push result back on stack
*/


  char   *buf = 0;
  xbExpNode *p1, *p2, *p3, *WorkNode, *FuncNode;
  xbShort  ParmsNeeded,len;
  char   ptype = 0;  /* process type s=string, l=logical, d=double */
  xbDouble DoubResult = 0;
  xbLong   IntResult = 0;
  FuncNode = (xbExpNode *) Pop();

  ParmsNeeded = GetFuncInfo( Func, 1 );

  if( ParmsNeeded == -1 ) {
    return XB_INVALID_FUNCTION;
  }
  else {
    ParmsNeeded = 0;
    if( FuncNode->Sibling1 ) ParmsNeeded++;
    if( FuncNode->Sibling2 ) ParmsNeeded++;
    if( FuncNode->Sibling3 ) ParmsNeeded++;
  }

  if( ParmsNeeded > GetStackDepth())
    return XB_INSUFFICIENT_PARMS;

  p1 = p2 = p3 = NULL;
  if( ParmsNeeded > 2 ) p3 = (xbExpNode *) Pop(); 
  if( ParmsNeeded > 1 ) p2 = (xbExpNode *) Pop(); 
  if( ParmsNeeded > 0 ) p1 = (xbExpNode *) Pop(); 
  memset( WorkBuf, 0x00, WorkBufMaxLen+1);

  if( strncmp( Func, "ABS", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = ABS( GetDoub( p1 ));
  }
  else if( strncmp( Func, "ASC", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = ASC( p1->StringResult );
  }
  else if( strncmp( Func, "AT", 2 ) == 0 ) {  
    ptype = 'd';
    DoubResult = AT( p1->StringResult, p2->StringResult );
  }
  else if( strncmp( Func, "CDOW", 4 ) == 0 ) {  
    ptype = 's';
    buf = CDOW( p1->StringResult );
  }
  else if( strncmp( Func, "CHR", 3 ) == 0 ) {  
    ptype = 's';
    buf = CHR( GetInt( p1 ));
  }
  else if( strncmp( Func, "CMONTH", 6 ) == 0 ) {  
    ptype = 's';
    buf = CMONTH( p1->StringResult );
  }
  else if( strncmp( Func, "CTOD", 4 ) == 0 ) {  
    ptype = 's';
    buf = CTOD( p1->StringResult );
  }
  else if( strncmp( Func, "DATE", 4 ) == 0 ) {  
    ptype = 's';
    buf = DATE();
  }
  else if( strncmp( Func, "DAY", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = DAY( p1->StringResult );
  }
  else if( strncmp( Func, "DESCEND", 7 ) == 0 && p1->ExpressionType == 'C' ) {  
    ptype = 's';
    buf = DESCEND( p1->StringResult.c_str() );
  }
  else if( strncmp( Func, "DESCEND", 7 ) == 0 && p1->ExpressionType == 'N' ) {  
    ptype = 'd';
    DoubResult = DESCEND( GetDoub( p1 ));
  }
  else if( strncmp( Func, "DESCEND", 7 ) == 0 && p1->ExpressionType == 'D' ) {  
    xbDate d( p1->StringResult );
    ptype = 'd';
    DoubResult = DESCEND( d );
  }
  else if( strncmp( Func, "DOW", 3 ) == 0 ) {
    ptype = 'd';
    DoubResult = DOW( p1->StringResult );
  }
  else if( strncmp( Func, "DTOC", 4 ) == 0 ) {  
    ptype = 's';
    buf = DTOC( p1->StringResult );
  }
  else if( strncmp( Func, "DTOS", 4 ) == 0 ) {  
    ptype = 's';
    buf = DTOS( p1->StringResult );
  }
  else if( strncmp( Func, "EXP", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = EXP( GetDoub( p1 ));
  }
  else if( strncmp( Func, "IIF", 3 ) == 0 ){
    ptype = 's';
    buf = IIF( p1->IntResult, p2->StringResult, p3->StringResult );
  }
  else if( strncmp( Func, "INT", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = INT( GetDoub( p1 ));
  }
  else if( strncmp( Func, "ISALPHA", 7 ) == 0 ) {  
    ptype = 'l';
    IntResult = ISALPHA( p1->StringResult );
  }
  else if( strncmp( Func, "ISLOWER", 7 ) == 0 ) {  
    ptype = 'l';
    IntResult = ISLOWER( p1->StringResult );
  }
  else if( strncmp( Func, "ISUPPER", 7 ) == 0 ) {  
    ptype = 'l';
    IntResult = ISUPPER( p1->StringResult );
  }
  else if( strncmp( Func, "LEN", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = LEN( p1->StringResult );
  }
  else if( strncmp( Func, "LEFT", 4 ) == 0 ) {  
    ptype = 's';
    buf = LEFT( p1->StringResult, INT( p2->DoubResult ));
  }
  else if( strncmp( Func, "LTRIM", 5 ) == 0 ) {  
    ptype = 's';
    buf = LTRIM( p1->StringResult );
  }  
  else if( strncmp( Func, "LOG", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = LOG( GetDoub( p1 ));
  }  
  else if( strncmp( Func, "LOWER", 5 ) == 0 ) {  
    ptype = 's';
    buf = LOWER( p1->StringResult );
  }  
  else if( strncmp( Func, "MAX", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = MAX( GetDoub( p1 ), GetDoub( p2 ));
  }  
  else if( strncmp( Func, "MIN", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = MIN( GetDoub( p1 ), GetDoub( p2 ));
  }  
  else if( strncmp( Func, "MONTH", 5 ) == 0 ) {  
    ptype = 'd';
    DoubResult = MONTH( p1->StringResult );
  } 

  else if( strncmp( Func, "RECNO", 5 ) == 0 )
  {
    ptype = 'd';
    DoubResult = RECNO( FuncNode->dbf );
  }

  else if( strncmp( Func, "REPLICATE", 9 ) == 0 ) {
    ptype = 's';
    buf = REPLICATE( p1->StringResult, GetInt( p2 ));
  }
  else if( strncmp( Func, "RIGHT", 5 ) == 0 ) {
    ptype = 's';
    buf = RIGHT( p1->StringResult, GetInt( p2 ));
  }
  else if( strncmp( Func, "RTRIM", 5 ) == 0 ) {  
    ptype = 's';
    buf = RTRIM( p1->StringResult );
  }  
  else if( strncmp( Func, "SPACE", 5 ) == 0 ) {  
    ptype = 's';
    buf = SPACE( INT( GetDoub( p1 )));
  }
  else if( strncmp( Func, "SQRT", 4 ) == 0 ) {  
    ptype = 'd';
    DoubResult = SQRT( GetDoub( p1 ));
  }
  else if( strncmp( Func, "STRZERO", 7 ) == 0 && ParmsNeeded == 1 ) {
    ptype = 's';
    buf = STRZERO( p1->StringResult );
  }   
  else if( strncmp( Func, "STRZERO", 7 ) == 0 && ParmsNeeded == 2 ) {
    ptype = 's';
    buf = STRZERO( p1->StringResult, GetInt( p2 ));
  }   
  else if( strncmp( Func, "STRZERO", 7 ) == 0 && ParmsNeeded == 3 ) {
    ptype = 's';
    buf = STRZERO( p1->StringResult, GetInt( p2 ), GetInt( p3 ));
  }   

  else if( strncmp( Func, "STR", 3 ) == 0 && p3 ) {
    ptype = 's';
    if(p1->ExpressionType == 'N')
      buf = STR( p1->DoubResult, GetInt( p2 ), GetInt( p3 ));
    else
      buf = STR( p1->StringResult, GetInt( p2 ), GetInt( p3 ));
  }   

  else if( strncmp( Func, "STR", 3 ) == 0 && p2 ) {
    ptype = 's';
    buf = STR( p1->StringResult, GetInt( p2 ));
  }

  else if( strncmp( Func, "STR", 3 ) == 0 && p1 ) {
    ptype = 's';
    buf = STR( p1->StringResult );
  }
   
  else if( strncmp( Func, "SUBSTR", 6 ) == 0 ) {
    ptype = 's';
    buf = SUBSTR( p1->StringResult, GetInt( p2 ), GetInt( p3 )); 
  }
  else if( strncmp( Func, "TRIM", 4 ) == 0 ) {  
    ptype = 's';
    buf = TRIM( p1->StringResult );
  }  
  else if( strncmp( Func, "UPPER", 5 ) == 0 ) {  
    ptype = 's';
    buf = UPPER( p1->StringResult );
  }  
  else if( strncmp( Func, "VAL", 3 ) == 0 ) {  
    ptype = 'd';
    DoubResult = VAL( p1->StringResult );
  }  
  else if( strncmp( Func, "YEAR", 4 ) == 0 ) {  
    ptype = 'd';
    DoubResult = YEAR( p1->StringResult );
  }  
  if( p1 && !p1->InTree ) delete p1;
  if( p2 && !p2->InTree ) delete p2;
  if( p3 && !p3->InTree ) delete p3;
  if( !FuncNode->InTree ) delete FuncNode;
  if( buf ){
    len = strlen( buf );
    WorkNode = new xbExpNode;
    if( !WorkNode )
      return XB_NO_MEMORY;
    WorkNode->ResultLen = len + 1;
    
  } else {    
    len = 0;
    WorkNode = new xbExpNode;
    if( !WorkNode )
      return XB_NO_MEMORY;
    WorkNode->ResultLen = 0;
  }

  switch( ptype ){
   case 's':                               /* string or char result */
    WorkNode->DataLen = len;
    WorkNode->ExpressionType = 'C';
    WorkNode->Type = 's';
    WorkNode->StringResult = buf;
    break;
   case 'd':                               /* numeric result */
    WorkNode->DataLen = 0;
    WorkNode->ExpressionType = 'N';
    WorkNode->Type = 'd';
    WorkNode->DoubResult = DoubResult;
    break;
   case 'l':                               /* logical result */
    WorkNode->DataLen = 0;
    WorkNode->ExpressionType = 'L';
    WorkNode->Type = 'l';
    WorkNode->IntResult = IntResult;
    break;
   default:
    std::cout << "\nInternal error. " << ptype;
    break;
  }
  Push(WorkNode);
  return XB_NO_ERROR;
}
/*************************************************************************/
//! Short description.
/*!
*/
xbString & xbExpn::GetStringResult()
{
  xbString *s = 0;
  xbExpNode *e;
  if( GetStackDepth() < 1 ) return *s;
  e = (xbExpNode *) Pop();
  s = &e->StringResult;
  Push(e);
  return *s;
}
/*************************************************************************/
//! Short description.
/*!
*/
xbLong xbExpn::GetIntResult()
{
  xbLong l;
  xbExpNode * e;
  if( GetStackDepth() < 1 ) return 0L;
  e = (xbExpNode *) Pop();
  l = e->IntResult;
  Push(e);
  return l;
}
/*************************************************************************/
//! Short description.
/*!
*/
xbDouble xbExpn::GetDoubleResult()
{
  xbDouble d;
  xbExpNode * e;
  if( GetStackDepth() < 1 ) return (xbDouble) 0;
  e = (xbExpNode *) Pop();
  d = e->DoubResult;
  Push(e);
  return d;
}
/*************************************************************************/
//! Short description.
/*!
  \param p
*/
xbDouble xbExpn::GetDoub( xbExpNode * p )
{
  if( p->Type == 'd' )
    return p->DoubResult;
  else if( p->Type == 'N' || p->Type == 's' )
    return( strtod( p->StringResult, NULL ));
  else if( p->Type == 'D' )
    return( p->dbf->GetDoubleField( p->FieldNo ));
  else
    return 0;
}
/*************************************************************************/
//! Short description.
/*!
  \param p
*/
xbLong xbExpn::GetInt( xbExpNode *p )
{
  if( p->Type == 'l' || p->Type == 'i' )
    return p->IntResult;
  else if( p->Type == 'N' || p->Type == 's' )
    return atoi( p->StringResult );
  else if( p->Type == 'D' )
    return p->dbf->GetLongField( p->FieldNo );
  else
    return 0L;
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
xbDouble xbExpn::ABS( xbDouble d )
{
  if( d < (xbDouble) 0 )
    return d * -1;
  else
    return d;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
xbLong xbExpn::ASC( const char * String )
{
  return *String;
}
/*************************************************************************/
//! Short description.
/*!
  \param s1
  \param s2
*/
xbLong xbExpn::AT( const char * s1, const char *s2 )
{
  /* looks for s1 in s2 */
  xbLong cnt;
  const char *p;
  if( strlen( s1 ) > strlen( s2 )) return 0;
  if(( p = strstr( s2, s1 )) == NULL )
  return 0;
  cnt = 1;
  while( s2++ != p ) cnt++;
  return cnt;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
char * xbExpn::CDOW( const char * Date8 )
{
  static char buf[10];
  xbDate d;
  xbShort len,i;
  strcpy( buf, d.FormatDate( "DDDD", Date8 )); 
  len = strlen( buf );
  for( i = len; i < 9; i++ ) buf[i] = 0x20;
  buf[9] = 0x00;
  return buf;
}
/*************************************************************************/
//! Short description.
/*!
  \param l
*/
char * xbExpn::CHR( xbLong l )
{
  static char buf[2];
  xbShort i;
  i = (xbShort) l;
  buf[0] = i;
  buf[1] = 0x00;
  return buf;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
char * xbExpn::CMONTH( const char * Date8 )
{
  static char buf[10];
  xbShort len,i;
  xbDate d;
  strcpy( buf, d.FormatDate( "MMMM", Date8 ));
  len = strlen( buf );
  for( i = len; i < 9; i++ ) buf[i] = 0x20;
  buf[9] = 0x00;
  return buf;
}
/*************************************************************************/
//! Short description.
/*!
  \param indate
*/
char * xbExpn::CTOD( const char * indate )
{
  xbDate d;  
  strcpy( WorkBuf, d.FormatCTODdate( indate ));
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
xbLong xbExpn::DAY( const char * Date8 )
{
  xbDate d;
  return d.DayOf( XB_FMT_MONTH, Date8 );
}
/*************************************************************************/
//! Short description.
/*!
  \param date
*/
xbLong xbExpn::DESCEND( const xbDate & date )
{
  return 2415021 + date.JulianDays( "29991231" ) - date.JulianDays();
}
/*************************************************************************/
//! Short description.
/*!
  \param num
*/
xbDouble xbExpn::DESCEND( xbDouble d )
{
  return d * -1;
}
/*************************************************************************/
//! Short description.
/*!
  \param str
*/
char * xbExpn::DESCEND( const char * str )
{
  xbShort i;
  xbShort len = strlen( str );

  for( i = 0; i < len; i++ )
    WorkBuf[i] = 255 - str[i];
  WorkBuf[i] = 0x00; 

  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
xbLong xbExpn::DOW( const char * Date8 )
{
  xbDate d;
  return d.DayOf( XB_FMT_WEEK, Date8 );
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
char * xbExpn::DTOC( const char * Date8 )
{
  xbDate d;
  strcpy( WorkBuf, d.FormatDate( xbase->GetDefaultDateFormat(), Date8 ));
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
char * xbExpn::DTOS( const char * Date8 )
{
  xbDate d;
  strcpy( WorkBuf, d.FormatDate( "YYYYMMDD", Date8 ));
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
xbDouble xbExpn::EXP( xbDouble d )
{
  return exp( d );
}
/*************************************************************************/
//! Short description.
/*!
  \param ifCondition
  \param trueRslt
  \param falseRslt
*/
char * xbExpn::IIF( xbShort ifCondition, 
     const char * trueRslt, const char * falseRslt )
{
  if( ifCondition )
    strcpy( WorkBuf, trueRslt );
  else
    strcpy( WorkBuf, falseRslt );

  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
xbLong xbExpn::INT( xbDouble d )
{
  return (xbLong) d;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
xbLong xbExpn::ISALPHA( const char * String )
{
  if( isalpha(*String) ) return 1;
  else return 0;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
xbLong xbExpn::ISLOWER( const char * String )
{
  if( islower(*String) ) return 1;
  else return 0;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
xbLong xbExpn::ISUPPER( const char * String )
{
  if( isupper(*String) ) return 1;
  else return 0;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
xbLong xbExpn::LEN( const char * String )
{
  xbLong len;
  len = strlen( String );
  len--;
  while( len >= 0 && String[len] == 0x20 ) len--;
  return ++len;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param Len
*/
char * xbExpn::LEFT( const char * String, xbShort Len )
{
  xbShort i;
  for( i = 0; i < Len && i < 100; i++ )
    WorkBuf[i] = String[i];
  WorkBuf[i] = 0x00;
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
/* This method removes any leading spaces from String */
char * xbExpn::LTRIM( const char *String) {
  WorkBuf[0] = 0x00;
  if (!String)
    return WorkBuf;

  xbShort i;
  i = 0;
  while( *String && *String == 0x20 ) String++;
  while( *String && i < WorkBufMaxLen ){
    WorkBuf[i++] = *String;
    String++;
  }
  WorkBuf[i] = 0x00;
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
xbDouble xbExpn::LOG( xbDouble d )
{
  return log( d );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
char *xbExpn::LOWER( const char *String ) 
{
  WorkBuf[0] = 0x00;
  if (!String)
    return WorkBuf;
  xbShort i = 0;
  while( *String && i < WorkBufMaxLen) {
    WorkBuf[i++] = tolower( *String );
    String++;
  }
  WorkBuf[i] = 0x00;
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param d1
  \param d2
*/
xbDouble xbExpn::MAX( xbDouble d1, xbDouble d2 )
{
  if( d1 > d2 ) 
    return d1;
  else
    return d2;
}
/*************************************************************************/
//! Short description.
/*!
  \param d1
  \param d2
*/
xbDouble xbExpn::MIN( xbDouble d1, xbDouble d2 )
{
  if( d1 < d2 ) 
    return d1;
  else
    return d2;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
xbLong xbExpn::MONTH( const char * Date8 )
{
  xbDate d;
  return d.MonthOf( Date8 );
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
xbLong xbExpn::RECNO( xbDbf * d ) {
  return d->GetCurRecNo();
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param Cnt
*/
char * xbExpn::REPLICATE( const char * String, xbShort Cnt )
{
  xbShort len, i;
  len = strlen( String );
  if(( len * Cnt ) > 100 ) return NULL;
  memset( WorkBuf, 0x00, len+1 );
  for( i = 0; i < Cnt; i++ )
    strcat( WorkBuf, String );
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \paran cnt
*/
char * xbExpn::RIGHT( const char * String, xbShort cnt )
{
  xbShort len;
  strcpy( WorkBuf, String );
  len = strlen( String );
  if( len < cnt ) return WorkBuf;
  len = LEN( String );
  if( len < cnt ) return WorkBuf;
  strcpy( WorkBuf, String + len - cnt );
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
char * xbExpn::RTRIM( const char * String )
{
  return TRIM( String );
}
/*************************************************************************/
//! Short description.
/*!
  \param Cnt
*/
char * xbExpn::SPACE( xbShort Cnt )
{ 
  if( Cnt > 100 ) return NULL;
  memset( WorkBuf, 0x20, Cnt );
  WorkBuf[Cnt] = 0x00;
  return WorkBuf;
} 
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
xbDouble xbExpn::SQRT( xbDouble d )
{
  return sqrt( d );
}
/*************************************************************************/
//! Short description.
/*!
  \param d
  \param length
  \param numDecimals
*/
char * xbExpn::STR(xbDouble d, xbUShort length, xbShort numDecimals) {
  // sanity check for length arg
  if (length > WorkBufMaxLen) 
  {
  // maybe should generate an error here instead ?
    length = WorkBufMaxLen;
  }

  // check the length required
  sprintf(WorkBuf, "%.*f", numDecimals, d);

  if ((xbUShort) strlen(WorkBuf) > length) {
    memset(WorkBuf, '*', length);
    WorkBuf[length] = 0x00;
  } else
    sprintf( WorkBuf, "%*.*f", length, numDecimals, d );

  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param d
  \param length
*/
char * xbExpn::STR( xbDouble d, xbShort length )
{
  return STR( d, length, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
char * xbExpn::STR( xbDouble d )
{
  return STR( d, 10, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param length
  \param
*/
char * xbExpn::STR( const char * String, xbShort length, xbShort dec )
{
  xbShort len, i;
  double d;
  d = strtod( String, NULL );
  return STR( d, length, dec );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param length
*/
char * xbExpn::STR( const char *String, xbShort length )
{
  return STR( String, length, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
char * xbExpn::STR( const char * String )
{
  return STR( String, 10, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param d
  \param length
  \param 
*/
char * xbExpn::STRZERO( xbDouble d, xbShort length, xbShort )
{
  xbShort len,i;
  sprintf(WorkBuf, "%*.*g", length, length, d);
//  gcvt( d, length, WorkBuf );
  len = strlen( WorkBuf );
  if( len > length )
    strcpy( WorkBuf, "**********" );
  else if( len < length )
  {
    for( i = len; i < length; i++ )
      WorkBuf[i] = 0x30;
    WorkBuf[i] = 0x00;
  }
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param d
  \param length
*/
char * xbExpn::STRZERO( xbDouble d, xbShort length )
{
  return STRZERO( d, length, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param d
*/
char * xbExpn::STRZERO( xbDouble d )
{
  return STRZERO( d, 10, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param length
  \param
*/
char * xbExpn::STRZERO( const char * String, xbShort length, xbShort )
{
  xbShort i, len ;
  while( *String == ' ' ) String++;
  len = strlen(String);
  for( i = 0; i < abs( length-len); i++ )
    WorkBuf[i] = 0x30;
  WorkBuf[i] = 0x00;
  strcat( WorkBuf, String );
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param length
*/
char * xbExpn::STRZERO( const char * String, xbShort length )
{
  return STRZERO( String, length, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
char * xbExpn::STRZERO( const char * String )
{
  return STRZERO( String, 10, 0 );
}
/*************************************************************************/
//! Short description.
/*!
  \param String
  \param StartPos
  \param Len
*/
char * xbExpn::SUBSTR( const char * String, xbShort StartPos, xbShort Len )
{
  xbShort i;
  if( StartPos < 1 ) return NULL;
  String += (StartPos - 1);
  for( i = 0; i < Len; i++ )
    WorkBuf[i] = *String++;
  WorkBuf[i] = 0x00;
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
*/
char * xbExpn::DATE()
{
  xbDate d;
  strcpy( WorkBuf, d.Sysdate());
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
char * xbExpn::TRIM( const char * String )
{
  WorkBuf[0] = 0x00;
  if( !String ) 
    return WorkBuf;
  char *sp;
  xbShort len;
  len = strlen( String );
  if( len < WorkBufMaxLen ) {
    strcpy( WorkBuf, String );
  }
  else {
    strncpy( WorkBuf, String, WorkBufMaxLen );
    WorkBuf[ WorkBufMaxLen ] = 0x00;
    len = WorkBufMaxLen;
  }
  sp = WorkBuf + len - 1;
  while( *sp == 0x20 && sp >= WorkBuf ) {
    *sp = 0x00;
    sp--;
  }
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
char *xbExpn::UPPER( const char *String )
{
  WorkBuf[0] = 0x00;
  if (!String)
    return WorkBuf;
  xbShort i;
  i = 0;
  while(*String && i < WorkBufMaxLen) {
    WorkBuf[i++] = toupper(*String);
    String++;
  }
  WorkBuf[i] = 0x00; 
  return WorkBuf;
}
/*************************************************************************/
//! Short description.
/*!
  \param String
*/
xbLong xbExpn::VAL( const char * String )
{
  if( String )
    return (xbLong) *String;
  else
    return 0;
}
/*************************************************************************/
//! Short description.
/*!
  \param Date8
*/
xbLong xbExpn::YEAR( const char * Date8 ){
  xbDate d;
  return d.YearOf( Date8 );
}
/*************************************************************************/
#endif     // XB_EXPRESSIONS
