Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Example 2 - Three ways to do replace

Show three different functions to perform text replacement including "replaceWithCallback" which is a unique P6R feature.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory> // nothrow
#include "p6rgx.h"
using namespace P6R;
P6DECLARE_CID( p6WRegex );
namespace {
//
// Simple p6IDataStream implementation which outputs
// data to stdout (via printf). This implementation
// is not thread-safe, but is adequate for this
// example.
//
class CConsoleStream : public P6R::p6IDataStream
{
public:
//
// Standard [p6]COM queryInterface() method.
//
P6COMMETHOD queryInterface( const P6R::IID &iid, P6R::P6VOID **ppIface )
{
if (!ppIface) return eAccessFault;
*ppIface = NULL;
if(iid == IID_p6ICom) *ppIface = static_cast<p6IDataStream*>(this);
else if(iid == IID_p6IDataStream) *ppIface = static_cast<p6IDataStream*>(this);
else return eNoInterface;
reinterpret_cast<p6ICom*>(*ppIface)->addref();
return eOk;
}
//
// Standard [p6]COM addref() method.
//
{
return m_cRef++;
}
//
// Standard [p6]COM release() method.
//
{
P6INT32 tmp = 0;
if(0 == (tmp = (--m_cRef))) { delete this; }
return tmp;
}
//
// beginStream() method prepares the stream for use.
//
P6COMMETHOD beginStream()
{
return eOk;
}
//
// processStream() is call to pass data to the data stream.
// This method then performs it's stream specific
// operations on the data (in this case, writing it out
// to stdout).
//
// Since printf() requires an ASCIIZ string (NULL terminated string),
// this method first copies the data into a buffer and NULL
// terminates, then passes that to printf().
//
P6COMMETHOD processStream( const P6R::P6VOID* pData, P6R::P6UINT32 cData )
{
//
// Free the buffer if we do not have enough room
//
if (m_cBuffer && cData+1 > m_cBuffer)
{
free( m_pBuffer );
m_pBuffer = NULL;
m_cBuffer = 0;
}
//
// Allocate the buffer if not already allocated
//
if (!m_pBuffer)
{
m_pBuffer = (P6CHAR*) malloc(cData+1);
m_cBuffer = cData;
}
//
// Output the data to the console
//
if (m_pBuffer)
{
memcpy( m_pBuffer, pData, cData );
m_pBuffer[cData] = '\0';
printf( m_pBuffer );
}
return eOk;
}
//
// endStream() is called to notify the stream that there is
// no more data to be processed. In this simple case there is
// nothing to do.
//
P6COMMETHOD endStream() { return eOk; }
//
// This method creates a new uninitialized instance
// of our component and returns a pointer to the
// requested interface.
//
static P6R::P6ERR createInstance( P6R::p6ICom *pOuter, const P6R::IID &iid, P6R::P6VOID **ppIface )
{
P6ERR err = eNoMemory;
CConsoleStream *pObj = NULL;
if(NULL != pOuter) return eNoAgregation;
if(NULL == ppIface) return eAccessFault;
*ppIface = NULL;
if (NULL != (pObj = new (std::nothrow) CConsoleStream() ))
{
pObj->addref();
err = pObj->queryInterface( iid, ppIface );
pObj->release();
}
return err;
}
CConsoleStream() : m_cRef(0), m_pBuffer(NULL), m_cBuffer(0) {;}
virtual ~CConsoleStream() { if (m_pBuffer) free(m_pBuffer); }
protected:
P6INT32 m_cRef; // Holds the components reference count
P6CHAR *m_pBuffer; // A pointer to our output buffer.
P6UINT32 m_cBuffer; // The current size in characters of our output buffer
};
P6UINT32 g_callbackNum; // -> what string do we return on the callback?
P6WCHAR g_callbackBuffer[100]; // -> fake what a real caller would send
// Each time we are called we return a different string, and after we hit our max we loop around
//
const P6WCHAR* replaceStringCallback( const P6WCHAR* matchedText, P6VOID* pCtx )
{
if ( 2 <= g_callbackNum ) g_callbackNum = 0;
switch( g_callbackNum ) {
case 0: // "HH -\1- HH"
g_callbackBuffer[0] = P6CHR('H');
g_callbackBuffer[1] = P6CHR('H');
g_callbackBuffer[2] = P6CHR(' ');
g_callbackBuffer[3] = P6CHR('-');
g_callbackBuffer[4] = P6CHR('\\');
g_callbackBuffer[5] = P6CHR('1');
g_callbackBuffer[6] = P6CHR('-');
g_callbackBuffer[7] = P6CHR(' ');
g_callbackBuffer[8] = P6CHR('H');
g_callbackBuffer[9] = P6CHR('H');
g_callbackBuffer[10] = P6CHR('\0');
break;
case 1: // "QQ -\2- QQ"
g_callbackBuffer[0] = P6CHR('Q');
g_callbackBuffer[1] = P6CHR('Q');
g_callbackBuffer[2] = P6CHR(' ');
g_callbackBuffer[3] = P6CHR('-');
g_callbackBuffer[4] = P6CHR('\\');
g_callbackBuffer[5] = P6CHR('1');
g_callbackBuffer[6] = P6CHR('-');
g_callbackBuffer[7] = P6CHR(' ');
g_callbackBuffer[8] = P6CHR('Q');
g_callbackBuffer[9] = P6CHR('Q');
g_callbackBuffer[10] = P6CHR('\0');
break;
default:
g_callbackNum++;
return NULL;
break;
}
g_callbackNum++;
return g_callbackBuffer;
}
// We have 3 ways to perform replace with a regex.
//
P6R::P6ERR runRegex( p6IDataStream *pStreamDebug )
{
P6CHAR szErr[64];
const P6WCHAR* pResult = NULL;
P6INT32 iResult = -1;
P6SIZE length = 0;
P6ERR err = eOk;
// [A] Get the components we need
if (P6FAILED( err = p6GetRuntimeIface( VALIDATECOMPTR( p6ISafeString, cpStr )))) return err;
if (P6FAILED( err = p6CreateInstance( NULL, CID_p6WRegex, VALIDATECOMPTR( p6IWRegex, cpWRegex )))) return err;
if (P6FAILED( err = cpWRegex->initialize( P6WREGEX_NOFLAGS, P6WREGEX_PERL ))) return err;
// [B] Allow the call back to define the replace text
// -> find a substring (a phone number) in a larger string
err = cpWRegex->compile( P6TEXT("\\d+\\.(\\d+)\\.\\d+"), P6MOD_NULL );
// -> the replacement string has a back reference, and is re-evaluated on each match
if (P6SUCCEEDED(err = cpWRegex->replaceWithCallback( P6TEXT("abcd4.2.03xxxxx123dc93.52.33ABC"), P6MOD_GLOBAL, (P6WREGEXREPLACECB)replaceStringCallback, NULL, cpMatch.addressofWithRelease() )))
{
if (cpMatch)
{
cpMatch->reset();
cpMatch->next( &pResult );
err = cpStr->wstrncmp( P6TEXT("abcdHH -2- HHxxxxx123dcQQ -52- QQABC"), pResult, 36, &iResult );
if (iResult != 0) printf( "replaceWithCallback - expected 0 but got %d\n", iResult );
err = cpStr->wstrlen( pResult, 10000, &length );
if (length != 36) printf( "replaceWithCallback - expected 36 but got %d\n", length );
}
}
P6WCHAR utilString[200];
P6SIZE utilSize = 0;
if(P6SUCCEEDED(err = cpWRegex->compile( P6TEXT("\\d+\\.\\d+\\.\\d+"), P6MOD_NULL )))
{
err = cpStr->wsetMem( utilString, 0, P6CHARCNT(utilString) );
// [C]
if (P6SUCCEEDED( err = cpWRegex->replace( P6TEXT("abcd4.2.03xxxxx123dc93.52.33ABC"), (P6MOD_FASTGREEDY | P6MOD_GLOBAL), P6TEXT("---"), utilString, 200, &utilSize )))
{
if (23 != utilSize) printf( "replace - expected 23 but got %d\n", utilSize );
err = cpStr->wstrncmp( P6TEXT("abcd---xxxxx123dc---ABC"), utilString, 23, &iResult );
if (iResult != 0) printf( "replace - expected 0 but got %d\n", iResult );
}
utilSize = 0;
iResult = -1;
err = cpStr->wsetMem( utilString, 0, P6CHARCNT(utilString) );
err = cpStr->wstrlcpy( utilString, P6CHARCNT(utilString), P6TEXT("abcd4.2.03xxxxx123dc93.52.33ABC"), &utilSize );
if (P6SUCCEEDED( err = cpWRegex->replaceInPlace( utilString, (P6MOD_FASTGREEDY | P6MOD_GLOBAL), P6TEXT("---"), &utilSize )))
{
if (23 != utilSize) printf( "replaceInPace - expected 23 but got %d\n", utilSize );
err = cpStr->wstrncmp( P6TEXT("abcd---xxxxx123dc---ABC"), utilString, 23, &iResult );
if (iResult != 0) printf( "replaceInPlace - expected 0 but got %d\n", iResult );
}
}
if (P6FAILED( err )) printf("example failed due to [ %s ]\n", p6ErrToStr(err,&szErr[0],P6CHARCNT(szErr)));
return err;
}
} // namespace
int main(int argc,char *argv[])
{
P6ERR err = eOk;
P6CHAR szTmp[32];
if ( P6SUCCEEDED(err = CConsoleStream::createInstance( NULL, VALIDATECOMPTR( p6IDataStream, cpDataStream ))))
{
if ( P6SUCCEEDED( err = p6InitializeLoader(cpDataStream,9,P6SCLF_NOFLAGS)))
{
err = runRegex( cpDataStream );
printf( "runRegex result: [ %s ]\n", p6ErrToStr(err, &szTmp[0], P6CHARCNT(szTmp)) );
}
else printf("ERROR: Failed to initialize the loader [ %x ]\n", err );
}
else printf( "ERROR: Failed to create CConsoleStream [ %x ]\n", err );
return err;
}