• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

C/C++ 64-bit wstring unicode console example

Started by Patrice Terrier, February 18, 2013, 05:26:25 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Patrice Terrier

Here is a short 64-bit (VS2010) console application, trying to mimic a few of the PowerBASIC built-in string functions.

I have even used the trailing $ string character at the end of the PB's like function names  ;D

// Test.cpp : define the enter point for console application.
#include "stdafx.h"
//
#include <windows.h>   // Search along the path.
#include <iostream>

#include <string.h>
#include <algorithm>
using namespace std;

const wchar_t   *$NULL  = L"";
const wchar_t   *$Dot   = L".";
const wchar_t   *$Comma = L",";

long LongVAL(IN wstring sNum) {
    long value = 0;
    value = _wtol(sNum.c_str());
    return value;
}

double FloatVAL(IN wstring sNum) {
    double value = 0;
    value = _wtof(sNum.c_str());
    return value;
}

LONG_PTR INSTR(IN long nIndex, IN wstring sMain, IN wstring sSearch) {
    LONG_PTR nRet = -1; // Not found
    LONG_PTR nLength = sMain.length();
    if (nLength && (sSearch.length())) {
        if (nIndex < 0) {
            nRet = sMain.find_last_of(sSearch, nLength + nIndex + 1); }
        else {
            nRet = sMain.find_first_of(sSearch, nIndex);
        }
    }
    return nRet;
}

wstring zGetCTLText(IN HWND hCtrl) {
    WCHAR buf[4096];
    GetWindowText(hCtrl, buf, 4096);
    return wstring(buf);
}

wstring UCASE$(IN wstring sBuf) {
    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), ::toupper);
    return sBuf;
}

wstring LCASE$(IN wstring sBuf) {
    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), ::tolower);
    return sBuf;
}

wstring LTRIM$(IN wstring sBuf, IN wstring sChar) {
    wstring sResult = sBuf;
    LONG_PTR nLength = sBuf.length();
    if (nLength && (sChar.length())) {
        long K = 0;
        while (K < nLength) {
            // This is the sChar ANY search version
            if (std::wstring::npos != sChar.find(sBuf.substr(K, 1))) {
                ++K; }
            else {
                break;
            }
        }
        sResult = sBuf.substr(K, nLength);
    }
    return sResult;
}

wstring RTRIM$(IN wstring sBuf, IN wstring sChar) {
    wstring sResult = sBuf;
    LONG_PTR nLength = sBuf.length();
    if (nLength && (sChar.length())) {
        while (nLength > 0) {
            // This is the sChar ANY search version
            if (std::wstring::npos != sChar.find(sBuf.substr(nLength - 1, 1))) {
                --nLength; }
            else {
                break;
            }
        }
        sResult = sBuf.substr(0, nLength);
    }
    return sResult;
}

wstring PARSE$(IN wstring sMain, IN wstring sDelim, IN long nIndex) {
    wstring sResult = $NULL;
    LONG_PTR nLength = sDelim.length();
    if (nLength == 0) { sDelim = $Comma; ++nLength; } // Use comma "," as default delimiter
    sMain = RTRIM$(sMain, sDelim); sMain += sDelim;
    if (sMain.length() && nLength) {
        LONG_PTR prev_pos = 0, pos = 0, nCount = 0;
        while( (pos = sMain.find(sDelim, pos)) != std::wstring::npos ) {
            wstring substring(sMain.substr(prev_pos, pos - prev_pos));
            ++nCount;
            if (nCount == nIndex) { sResult = substring; break; }
            prev_pos = ++pos;
        }
    }
    return sResult;
}

wstring TRIM$(IN wstring sBuf, IN wstring sChar) {
    return LTRIM$(RTRIM$(sBuf, sChar), sChar);
}

int _tmain(int argc, _TCHAR* argv[])
{
    HWND hWnd = GetForegroundWindow();
    wstring sCaption = zGetCTLText(hWnd);
    wstring sUseOption;
    wstring sLastItem;
    sCaption += L"<one,two,three,four,Option>";
    LONG_PTR n = sCaption.length();
    LONG_PTR so = INSTR(-1, sCaption, L"<");
    if (so > -1) {

        sUseOption = RTRIM$(UCASE$(sCaption.substr(so + 1)), L">");
        wcout << sUseOption.c_str() << endl; // output to console

        sCaption = sCaption.substr(0, so);
        wcout << sCaption.c_str() << endl; // output to console

        sLastItem = PARSE$(sUseOption, $NULL, 5);
        wcout << sLastItem.c_str() << endl; // output to console
    }

    wcout << endl;
    system("pause");  // Halts execution; shows the "Press any key to continue..." prompt

    return 0;
}


Also, note the way i am using braces to come closer to the PB's IF / END IF construction.

"wcout" is the wstring way to send output to the consolde, and "endl" adds a CRLF to move to next line.
system("pause"), is handy to see what has been redirected to the console before the program close.
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

#1
Patrice,
  I just couldn't resist :)

  If you change

    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), toupper);

To

    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), ::toupper);

It will also compile with MinGWTDM64


James

I use the Win7.1 SDK only. No Visual Studio.

bc9 source:


$CPPHDR
$NOMAIN

$ONEXIT "VC.BAT $FILE$ -m64 con"

$HEADER
  #include <string>
  #include <algorithm>
$HEADER
'==============================================================================
'CONST stdwstr=std::wstring
'==============================================================================
Function pt_INSTR(nIndex As long, sMain As wstring, sSearch As wstring) As long
    Raw As long nRet = (-1)
    Raw As long nLength = sMain.length()
    If (nLength ANDALSO (sSearch.length())) Then
        If nIndex < 0 Then
            nRet = sMain.find_last_of(sSearch, nLength + nIndex + 1)
        Else
            nRet = sMain.find_first_of(sSearch, nIndex)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function zGetCTLText(hCtrl As HWND) As wstring
    Raw As WCHAR buf[4096]
    GetWindowText(hCtrl,buf,4096)
    Function = buf
End Function
'==============================================================================
Function pt_UCASE(sBuf As wstring) As wstring
    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), toupper)
    Function = sBuf
End Function
'==============================================================================
Function pt_LTRIM(sBuf As wstring,sChar As wstring) As wstring
    Raw As wstring sResult = sBuf
    Raw As long nLength = sBuf.length()
    If (nLength ANDALSO (sChar.length())) Then
        Local K As long
        While K < nLength
            ' This is the sChar ANY search version
            If (std::wstring::npos <> sChar.find(sBuf.substr(K,1))) Then
                ++K
            Else
                break   
            End If
        Wend
        sResult = sBuf.substr(K,nLength)
    End If
    Function = sResult
End Function
'==============================================================================
Function pt_RTRIM(sBuf AS wstring, sChar As wstring) As wstring
    Raw As wstring sResult = sBuf
    Raw As long nLength = sBuf.length()
    If (nLength ANDALSO (sChar.length())) Then
        while (nLength > 0)
            if (std::wstring::npos <> sChar.find(sBuf.substr(nLength - 1, 1))) Then
                --nLength
            Else
                break   
            End If   
        Wend
        sResult = sBuf.substr(0, nLength)   
    End If
    Function = sResult
End Function
'==============================================================================
Function pt_PARSE( sMain As wstring, sDelim AS wstring, nIndex As long) As wstring
    Raw As wstring sResult = L""
    Raw As long nLength = sDelim.length()
    If nLength = 0 Then
        sDelim = L","
        ++nLength
    End If
    sMain = pt_RTRIM(sMain,sDelim)
    sMain += sDelim
    If (sMain.length() ANDALSO nLength) Then
        Local As long prev_pos, ppos, nCount
'needed a bit of a rewrite
        ppos = sMain.find(sDelim, ppos)
        While ppos  <> std::wstring::npos
            wstring substring(sMain.substr(prev_pos, ppos - prev_pos))
            ++nCount
            If nCount = nIndex Then
                sResult = substring
                break
            End If
            prev_pos = ++ppos
            ppos = sMain.find(sDelim, ppos)
        Wend
'original code       
'    $CCODE
'        while( (ppos = sMain.find(sDelim, ppos)) != std::wstring::npos ) {
'            wstring substring(sMain.substr(prev_pos, ppos - prev_pos));
'            ++nCount;
'            if (nCount == nIndex) { sResult = substring; break; }
'            prev_pos = ++ppos;
'        }
'   
'    $CCODE
    End If
    Function = sResult
End Function
'==============================================================================
Function pt_TRIM(sBuf As wstring, sChar As wstring) As wstring
    Function = pt_LTRIM(pt_RTRIM(sBuf,sChar),sChar)
End Function
'==============================================================================
Function main() As int
    Raw As HWND    hWnd = GetForegroundWindow()
    Raw As wstring sCaption = zGetCTLText(hWnd)
    Raw As wstring sUseOption, sLastItem
    sCaption += L"<one,two,three,four,Option>"
    wcout << sCaption << endl
    Raw As long n = sCaption.length()
    Raw As long so = pt_INSTR(-1, sCaption, L"<")
   
    If so > -1 Then
        sUseOption = pt_RTRIM(pt_UCASE(sCaption.substr(so+1)), L">")
        wcout << sUseOption.c_str() << endl ' output to console

        sCaption = sCaption.substr(0, so)
        wcout << sCaption.c_str() << endl ' output to console

        sLastItem = pt_PARSE(sUseOption, L"", 5)
        wcout << sLastItem.c_str() << endl ' output to console
       
    End If
    wcout << endl
   
    PAUSE
    Function = 0
End Function



And here is the translated c++ code


// *********************************************************************
// Created with bc9 - BASIC To C/C++ Translator (V) 9.1.2.1 (2013/02/16)
//                 BCX (c) 1999 - 2009 by Kevin Diggins
// *********************************************************************
//              Translated for compiling with a C++ Compiler
//                           On MS Windows
// *********************************************************************
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
// Additional lines may be needed
#if defined( __cplusplus )
  #include <iostream>
  #include <fstream>
  #include <sstream>
  #include <iomanip>
  typedef std::string stdstr;
  using namespace std;
#endif
#include <windows.h>    // Win32 Header File
#include <windowsx.h>   // Win32 Header File
#include <commctrl.h>   // Win32 Header File
#include <commdlg.h>    // Win32 Header File
#include <mmsystem.h>   // Win32 Header File
#include <shellapi.h>   // Win32 Header File
#include <shlobj.h>     // Win32 Header File
#include <richedit.h>   // Win32 Header File
#include <wchar.h>      // Win32 Header File
#include <objbase.h>    // Win32 Header File
#include <ocidl.h>      // Win32 Header File
#include <winuser.h>    // Win32 Header File
#include <olectl.h>     // Win32 Header File
#include <oaidl.h>      // Win32 Header File
#include <ole2.h>       // Win32 Header File
#include <oleauto.h>    // Win32 Header File
#include <winsock.h>    // Win32 Header File
#include <process.h>    // dos
#include <conio.h>      // dos
#include <direct.h>     // dos
#include <io.h>         // dos
#include <ctype.h>      // dos/linux
#include <fcntl.h>      // dos/linux
#include <math.h>       // dos/linux
#include <stdio.h>      // dos/linux
#include <string.h>     // dos/linux
#include <stddef.h>     // dos/linux
#include <stdlib.h>     // dos/linux
#include <setjmp.h>     // dos/linux
#include <time.h>       // dos/linux
#include <stdarg.h>     // dos/linux
#include <sys/types.h> 
#include <sys/stat.h>   


// ***************************************************
// Compiler Defines
// ***************************************************

// C++
#if defined( __cplusplus )
  #define overloaded
  #define C_EXPORT EXTERN_C __declspec(dllexport)
  #define C_IMPORT EXTERN_C __declspec(dllimport)
#else
  #define C_EXPORT __declspec(dllexport)
  #define C_IMPORT __declspec(dllimport)
#endif

// Open Watcom defs
#if defined( __WATCOM_CPLUSPLUS__ ) || defined( __TINYC__ )
  #define atanl atan
  #define sinl  sin
  #define cosl  cos
  #define tanl  tan
  #define asinl asin
  #define acosl acos
  #define log10l log10
  #define logl   log
  #define _fcloseall fcloseall
#endif

// Borland C++ 5.5.1 defs - bcc32.exe
#if defined( __BCPLUSPLUS__ )
  // ===== Borland Libraries ==========
  #include <dos.h>
  #pragma comment(lib,"import32.lib")
  #pragma comment(lib,"cw32.lib")
  // ==================================
#endif

// Microsoft VC++
#ifndef DECLSPEC_UUID
  #if (_MSC_VER >= 1100) && defined ( __cplusplus )
    #define DECLSPEC_UUID(x)    __declspec(uuid(x))
  #else
    #define DECLSPEC_UUID(x)
  #endif
#endif

// *************************************************
// Tiny C support for LinkRes2Exe
#ifdef __TINYC__
  int dummy __attribute__ ((section(".rsrc")));
#endif
// *************************************************

// ***************************************************

#include <string>
#include <algorithm>


// *************************************************
// Instruct Linker to Search Object/Import Libraries
// *************************************************
#if !defined( __LCC__ )
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"comctl32.lib")
#pragma comment(lib,"advapi32.lib")
#pragma comment(lib,"winspool.lib")
#pragma comment(lib,"shell32.lib")
#pragma comment(lib,"ole32.lib")
#pragma comment(lib,"oleaut32.lib")
#pragma comment(lib,"uuid.lib")
#pragma comment(lib,"odbc32.lib")
#pragma comment(lib,"odbccp32.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"comdlg32.lib")
#pragma comment(lib,"imagehlp.lib")
#pragma comment(lib,"version.lib")
#else
#pragma lib <winspool.lib>
#pragma lib <shell32.lib>
#pragma lib <ole32.lib>
#pragma lib <oleaut32.lib>
#pragma lib <uuid.lib>
#pragma lib <odbc32.lib>
#pragma lib <odbccp32.lib>
#pragma lib <winmm.lib>
#pragma lib <imagehlp.lib>
#pragma lib <version.lib>
#endif
// *************************************************
// End of Object/Import Libraries To Search
// *************************************************

// *************************************************
//        User's GLOBAL ENUM blocks
// *************************************************

// *************************************************
//            System Defined Constants
// *************************************************

#define CCPTR const char*
#define cSizeOfDefaultString 2048

// *************************************************
//            User Defined Constants
// *************************************************


// *************************************************
//               Standard Prototypes
// *************************************************

void    Pause (void);
// *************************************************
//          User Defined Types And Unions
// *************************************************


// *************************************************
//            User Global Variables
// *************************************************

static PCHAR   *g_argv;
static int     g_argc;


// *************************************************
//               Standard Macros
// *************************************************

#define AndAlso &&


// *************************************************
//               User Prototypes
// *************************************************

long    pt_INSTR (long,wstring,wstring);
wstring zGetCTLText (HWND);
wstring pt_UCASE (wstring);
wstring pt_LTRIM (wstring,wstring);
wstring pt_RTRIM (wstring,wstring);
wstring pt_PARSE (wstring,wstring,long);
wstring pt_TRIM (wstring,wstring);
int     main (void);

// *************************************************
//            User Global Initialized Arrays
// *************************************************



// *************************************************
//                 Runtime Functions
// *************************************************

void Pause(void)
{
  printf("\n%s\n","Press any key to continue . . .");
  _getch();
}



// ************************************
//       User Subs and Functions
// ************************************

long pt_INSTR (long nIndex,wstring  sMain,wstring  sSearch)
{
  long     nRet=(-1);
  long     nLength=sMain.length();
  if((nLength  AndAlso (sSearch.length())))
    {
      if(nIndex<0 )
        {
          nRet= sMain.find_last_of( sSearch, nLength+ nIndex+ 1);
        }
      else
        {
          nRet= sMain.find_first_of( sSearch, nIndex);
        }
    }
  return nRet;
}


wstring zGetCTLText (HWND hCtrl)
{
  WCHAR    buf[4096];
  GetWindowText(hCtrl,buf,4096);
  return buf;
}


wstring pt_UCASE (wstring  sBuf)
{
  std::transform(sBuf.begin(),sBuf.end(),sBuf.begin(),::toupper);
  return sBuf;
}


wstring pt_LTRIM (wstring  sBuf,wstring  sChar)
{
  wstring  sResult=sBuf;
  long     nLength=sBuf.length();
  if((nLength  AndAlso (sChar.length())))
    {
      long     K={0};
      while(K<nLength)
        {
          if((std::wstring::npos!=sChar.find(sBuf.substr(K,1))))
            {
              ++K;
            }
          else
            {
              break;
            }
        }

      sResult= sBuf.substr( K, nLength);
    }
  return sResult;
}


wstring pt_RTRIM (wstring  sBuf,wstring  sChar)
{
  wstring  sResult=sBuf;
  long     nLength=sBuf.length();
  if((nLength  AndAlso (sChar.length())))
    {
      while((nLength>0))
        {
          if((std::wstring::npos!=sChar.find(sBuf.substr(nLength-1,1))))
            {
              --nLength;
            }
          else
            {
              break;
            }
        }

      sResult= sBuf.substr( 0, nLength);
    }
  return sResult;
}


wstring pt_PARSE (wstring  sMain,wstring  sDelim,long nIndex)
{
  wstring  sResult=L"";
  long     nLength=sDelim.length();
  if(nLength==0 )
    {
      sDelim= L",";
      ++nLength;
    }
  sMain= pt_RTRIM( sMain, sDelim);
  sMain+=sDelim;
  if((sMain.length() AndAlso  nLength))
    {
      long     prev_pos={0};
      long     ppos={0};
      long     nCount={0};
      ppos= sMain.find( sDelim, ppos);
      while(ppos!=std::wstring::npos)
        {
          wstring substring(sMain.substr(prev_pos,ppos-prev_pos));
          ++nCount;
          if(nCount==nIndex )
            {
              sResult= substring;
              break;
            }
          prev_pos=++ ppos;
          ppos= sMain.find( sDelim, ppos);
        }

    }
  return sResult;
}


wstring pt_TRIM (wstring  sBuf,wstring  sChar)
{
  return pt_LTRIM(pt_RTRIM(sBuf,sChar),sChar);
}


int main ()
{
  HWND     hWnd=GetForegroundWindow();
  wstring  sCaption=zGetCTLText(hWnd);
  wstring  sUseOption;
  wstring  sLastItem;
  sCaption+=L"<one,two,three,four,Option>";
  wcout<<sCaption<<endl;
  long     n=sCaption.length();
  long     so=pt_INSTR(-1,sCaption,L"<");
  if(so>-1 )
    {
      sUseOption= pt_RTRIM( pt_UCASE( sCaption.substr( so+ 1)), L">");
      wcout<<sUseOption.c_str()<<endl;
      sCaption= sCaption.substr( 0, so);
      wcout<<sCaption.c_str()<<endl;
      sLastItem= pt_PARSE( sUseOption, L"", 5);
      wcout<<sLastItem.c_str()<<endl;
    }
  wcout<<endl;
  Pause();
  return 0;

}




Patrice Terrier

#2
I have updated the first post of this thread to use LONG_PTR instead of long, to avoid potential loss of data in 64-bit.
I have also added new constant: $NULL, $Dot, $Comma
and two VAL replacements: longVAL and FloatVAL

There are so many things to think about when switching from 32 to 64-bit, including new API declarations like
GetWindowLongPtr and SetWindowLongPtr instead of GetWindowLong and GetWindowLong,
especially because long are keeping their 4-byte size even in 64-bit.

LONG_PTR has a value of 4-byte in 32-bit and 8-byte in 64-bit, thus they must be used if you want to be able to compile the same code for either 32/64-bit platforms.

???
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Frederick J. Harris

Quote
There are so many things to think about when switching from 32 to 64-bit, including new API declarations like
GetWindowLongPtr and SetWindowLongPtr instead of GetWindowLong and GetWindowLong,
especially because long are keeping their 4-byte size even in 64-bit.

But by and large, it seems pretty easy to do.  I think the GetWindowLongPtr() / SetWindowLongPtr() situation are rather singular exceptions to the rule that the Api functions themselves haven't changed much - at least from the application coder's perspective.  So the issue to get 32 bit code working in 64 bit mode seems to involve nothing more than changing all the GetWindowLongs/SetWindowLongs, then changing the variable types that have anything to do with pointers, HWNDS, etc.  All in all, while I was working on it, I got the impression that there were some smart people involved in dealing with this rather complex situation so as to make it as painless as possible for folks like us.

Charles Pegge


Quote
some smart people involved in dealing with this rather complex situation so as to make it as painless as possible for folks like us.

The 64 bit Windows DLLs  are still called Kernel32.dll User32.dll etc, though they are stored in a separate folder from the 32 bit system. Windows has to have a complete set of dlls for each system, with the same nomenclature for compatibility.

On the CPU side, the default operand size is still 32 bits. To get the full 64bit register width, a prefix code (REX) has to be used. The REX code is also used to access the extra 8 registers. In other respects, the opcodes are identical except for a few legacy encodings, from the Pentium's ancient 8086 lineage.

Charles


Frederick J. Harris

Wasn't aware of that Charles.  Hadn't even given it a thought.

Recently I got a copy of Jeffrey Richter's book "Windows Via C/C++", as I always heard that was a good book on advanced Windows internals.  Interestingly, in it he mentioned that Microsoft was actually running out of room in its 2.1 gigabytes segment to fit everything in its OS!  I didn't realize that. 

Charles Pegge


Working in plain C, I found the ellipsis (...) construct very useful when dealing with multiple params:

Code (c) Select

//gcc CharPrint.c


#include <stdio.h>


void CharPrint(char* t, ...)
{
char**pt=&t;
int i=0;
while (1)
{
  if (pt[i]==0) return;
  printf("%s", pt[i] );
  i++;
}
}

int main()
{
char space[]=" ";
char comma[]=",";
char pling[]="!";
char cr   []="\n";
CharPrint("Hello",space,"World",comma,space,"Hello",space,"Sky",pling,cr,NULL);
//Hello World, Hello Sky!
}


As long as pointers are always used, there should be no problem 64 bit compiling.

Charles

James C. Fuller

Patrice,
  Are you using WSTRING/WSTRINGZ in you PowerBasic implementation or STRING/STRINGZ?

James

Patrice Terrier

#8
I am still using STRING and ASCIIZ, because WinLIFT/GDImage are still compiled with PB 9.05 to produce smaller production code.
(saving 20000 bytes)  :)

And i keep using LIB instead of IMPORT for the purpose of compatibility.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

Patrice,
  I asked because I am a bit confused at the moment in which direction you are going?
I believe you said you were going to translate your PB code to both 32 and 64 bit c++ so you only had one source base?

By using c++ wstring it appears you are restricting users to those using c++ only?

James


Patrice Terrier

James

I am using VS2010 Pro, and so far i can compile the same code either in 32 or 64-bit.
What i avoid is to use MFC and ATL, in order to get rid of the C++ runtime, and produce smaller and faster code size.

However my ultimate target shall be the Microsoft community (C, C++, C#), that is the largest in the programming world.

...


Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

Patrice,
  Would you be willing to share all the pb string functions you converted to c++? I started  for std::string a couple years ago but never finished.

James

Patrice Terrier

#12
Here are those i have done to ease the translation between PB and C/C++.

Note: I made the choice to use only wstring (wide char).

const wchar_t   *$NULL              = L"";
const wchar_t   *$Dot               = L".";

long INSTR(IN long nIndex, IN wstring sMain, IN wstring sSearch) {
    LONG_PTR nRet = -1; // Not found
    LONG_PTR nLength = sMain.length();
    if (nLength && (sSearch.length())) {
        if (nIndex < 0) {
            nRet = sMain.find_last_of(sSearch, nLength + nIndex + 1); }
        else {
            nRet = sMain.find_first_of(sSearch, nIndex);
        }
    }
    return (long) nRet;
}

long LongVAL(IN wstring sNum) { // dllexport
    long value = 0;
    value = _wtol(sNum.c_str());
    return value;
}

double FloatVAL(IN wstring sNum) { // dllexport
    double value = 0;
    value = _wtof(sNum.c_str());
    return value;
}

wstring UCASE$(IN wstring sBuf) { // dllexport
    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), ::toupper);
    return sBuf;
}

wstring LCASE$(IN wstring sBuf) {
    std::transform(sBuf.begin(), sBuf.end(), sBuf.begin(), ::tolower);
    return sBuf;
}

wstring LTRIM$(IN wstring sBuf, IN wstring sChar) { // dllexport
    wstring sResult = sBuf;
    LONG_PTR nLength = sBuf.length();
    if (nLength && (sChar.length())) {
        //sChar = sChar.substr(0, 1);
        long K = 0;
        while (K < nLength) {
            // if (*sBuf.substr(K, 1).c_str() == *sChar.c_str()) {
            // This is the sChar ANY search version
            if (std::wstring::npos != sChar.find(sBuf.substr(K, 1))) {
                ++K; }
            else {
                break;
            }
        }
        sResult = sBuf.substr(K, nLength);
    }
    return sResult;
}

wstring RTRIM$(IN wstring sBuf, IN wstring sChar) { // dllexport
    wstring sResult = sBuf;
    LONG_PTR nLength = sBuf.length();
    if (nLength && (sChar.length())) {
        //sChar = sChar.substr(0, 1);
        while (nLength > 0) {
            // if (*sBuf.substr(nLength - 1, 1).c_str() == *sChar.c_str()) {
            // This is the sChar ANY search version
            if (std::wstring::npos != sChar.find(sBuf.substr(nLength - 1, 1))) {
                --nLength; }
            else {
                break;
            }
        }
        sResult = sBuf.substr(0, nLength);
    }
    return sResult;
}

wstring PARSE$(IN wstring sMain, IN wstring sDelim, IN long nIndex) {
    wstring sResult = $NULL;
    LONG_PTR nLength = sDelim.length();
    if (nLength == 0) { sDelim = L","; ++nLength; } // Use comma "," as default delimiter
    sMain = RTRIM$(sMain, sDelim); sMain += sDelim;
    if (sMain.length() && nLength) {
        LONG_PTR prev_pos = 0, pos = 0, nCount = 0;
        while( (pos = sMain.find(sDelim, pos)) != std::wstring::npos ) {
            wstring substring(sMain.substr(prev_pos, pos - prev_pos));
            ++nCount;
            if (nCount == nIndex) { sResult = substring; break; }
            prev_pos = ++pos;
        }
    }
    return sResult;
}

wstring TRIM$(IN wstring sBuf, IN wstring sChar) { // dllexport
    return LTRIM$(RTRIM$(sBuf, sChar), sChar);
}

wstring LEFT$(IN wstring sBuf, IN long nLeft) { // dllexport
    wstring sResult = $NULL;
    LONG_PTR nLength = max(min(sBuf.length(), nLeft), 0);
    if (nLength) {
        sResult = sBuf.substr(0, nLength);
    }
    return sResult;
}

wstring RIGHT$(IN wstring sBuf, IN long nRight) { // dllexport
    wstring sResult = $NULL;
    LONG_PTR nLength = sBuf.length();
    if (nLength) { sResult = sBuf.substr(nLength - nRight, nRight); }
    return sResult;
}

wstring MID$(IN wstring sBuf, IN long nStart, IN long nMid = 0) { // dllexport
    wstring sResult = $NULL;
    long nLength = (long) sBuf.length();
    if (nMid == 0) { nMid = nLength - nStart + 1; }
    if (nLength) { sResult = sBuf.substr(nStart - 1, nMid); }
    return sResult;
}



Added:
Here is how to convert a wstring to WCHAR pointer to use with low level API calls.
(WCHAR*)MYwstring.c_str()
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

Note: wstring MID$(IN wstring sBuf, IN long nStart, IN long nMid = 0)

IN long nMid = 0, means this last parameter is optional with a default value of 0 (in this case 0, means take everything until the end of wstring, like in PB).
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

#14
Patrice,
  Thank you.
From my research I don't think the local variables are neccessary.
Doesn't this do the the same thing?


wstring MID$(IN wstring sBuf, IN long nStart, IN long nMid = 0) { // dllexport
    if (nStart > sBuf.length() || nStart < 1)  return "";
    if (nMid == 0) { nMid = (sBuf.length() - nStart) + 1; }
    return sBuf.substr(nStart - 1, nMid);
}