// // File: hzXbuf.cpp // // Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com) // // The HadronZoo C++ Class Library 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 3 of the License, or any later version. // // The HadronZoo C++ Class Library 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 the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses. //
#include <fstream> #include <iostream>
#include <stdarg.h>
#include "hzChars.h" #include "hzTextproc.h" #include "hzXbuf.h" #include "hzIpaddr.h" #include "hzEmaddr.h" #include "hzProcess.h"
using namespace std ;
/* ** Definitions */
#define XBLKSIZE 500
struct _xblk { // Category: Data // // Data container for hzXbuf
_xblk* m_pNext ; // next block in list uint16_t xize ; // bytes used uint16_t m_Resv ; // No longer used uchar m_Data[XBLKSIZE] ; // data area
void clear (void) { // Clear chain block content // // Arguments: None // Returns: None
m_pNext = 0 ; xize = 0 ; memset(m_Data, 0, XBLKSIZE) ; }
_xblk (void) { clear() ; }
void Next (_xblk* pz) { m_pNext = pz ; } _xblk* Next (void) { return m_pNext ; } } ;
/* ** Memory management regime for chains */
// static hzArray<_xblk*> s_AllChBlocks ; // All chain blocks
static hzLockRWD s_xbuf_mutex("hzXbuf mutex") ; // Protects the memory allocation static _xblk* s_xblk_free ; // Free list pointer
/* ** Section 1A: hzXbuf private functions */
_xblk* _xblk_alloc (void) { // Allocate a chain block. Either draw from a list of free blocks or create a new block // // Arguments: 1) id The chain id // // Returns: Pointer to a usable z-block
_hzfunc("_xblk_alloc") ;
_xblk* zp = 0 ; // Pointer to a real block (8 bytes)
s_xbuf_mutex.LockWrite() ;
if (s_xblk_free) { // Set allocation address to the freelist, set the freelist to the next in the list. zp = s_xblk_free ; s_xblk_free = zp->Next() ;
_hzGlobal_Memstats.m_numChainBF-- ; } else { // No free blocks so allocate a new one zp = new _xblk() ;
if (zp) _hzGlobal_Memstats.m_numChainBlks++ ; }
// Return the address s_xbuf_mutex.Unlock() ;
if (!zp) Fatal("No chain block allocated\n") ;
// Clear the free block's values to ready it for use zp->clear() ;
return zp ; }
int32_t hzXbuf::_compare (const hzXbuf& op) const { // Lexical compare // // Arguments: 1) op The other chain to which this chain is compared // // Returns: >0 If this chain is lexically greater than the supplied chain // <0 If this chain is lexically lesser than the suplied chain // 0 If the two chains are the same
_hzfunc("hzXbuf::_compare") ;
xbufIter a ; // Chain iterator this xbufIter b ; // Chain iterator supplied
int32_t res ; // Comparison result
for (a = *this, b = op ; !a.eof() && !b.eof() ; a++, b++) { if (*a != *b) break ; }
if (a.eof() && b.eof()) return 0 ;
if (a.eof()) res = *b ; else if (b.eof()) res = *a ; else res = *a - *b ;
return res ; }
/* ** Section 1B: hzXbuf public functions */
void hzXbuf::Clear (void) { // Clears all content held by the hzXbuf. // // Arguments: None // Returns: None
_hzfunc("hzXbuf::Clear") ;
_xbuf* cx ; // Temp pointer to control _xblk* zp ; // Block pointer uint32_t count ; // Number of blocks in chain
// Already no content - no action required. if (!mx) return ;
// If this chain is one of many pointing to the same contents, decrement the copy count and detach this chain from the contents. cx = mx ; mx = 0 ;
if (_hzGlobal_MT) { __sync_add_and_fetch((uint32_t*)&(cx->m_copy), -1) ;
if (cx->m_copy) return ; } else { cx->m_copy-- ;
if (cx->m_copy) return ; }
if (cx->m_Begin) { // Delete by returning all blocks to the free list. As the blocks are linked, we only need to set the next pointer in the last block to the free list and then set the free // list to the first block.
s_xbuf_mutex.LockWrite() ;
// Check for corruption if (!cx->m_End) hzexit(E_CORRUPT, "The internal begin/end blocks are %p and %p", cx->m_Begin, cx->m_End) ;
zp = (_xblk*) cx->m_End ; zp->Next(s_xblk_free) ; s_xblk_free = (_xblk*) cx->m_Begin ; cx->m_Begin = cx->m_End = 0 ; cx->m_nSize = 0 ;
count = cx->m_nSize / XBLKSIZE ; if (cx->m_nSize % XBLKSIZE) count++ ;
_hzGlobal_Memstats.m_numChainBF += count ;
s_xbuf_mutex.Unlock() ; }
delete cx ; }
hzXbuf::hzXbuf (void) { // Construct an empty hzXbuf instance. Increment the global count of currently allocated hzXbuf instances for memory use reporting purposes.
_hzGlobal_Memstats.m_numChain++ ; mx = 0 ; }
hzXbuf::hzXbuf (const hzXbuf& op) { // Copy constructor
if (op.mx) { if (_hzGlobal_MT) __sync_add_and_fetch(&(op.mx->m_copy), 1) ; else op.mx->m_copy++ ; }
mx = op.mx ; }
hzXbuf::~hzXbuf (void) { // Delete this hzXbuf instance. Decrement the global count of currently allocated hzXbuf instances for memory use reporting purposes.
_hzGlobal_Memstats.m_numChain-- ; Clear() ; delete mx ; }
hzXbuf::_xbuf::_xbuf (void) { // Allocate the hzXbuf Data Container
m_Begin = m_End = 0 ; m_nSize = 0 ; m_copy = 1 ; m_blox = 0 ; _hzGlobal_Memstats.m_numChainDC++ ; }
hzXbuf::_xbuf::~_xbuf (void) { _hzGlobal_Memstats.m_numChainDC-- ; }
uint32_t hzXbuf::Append (const void* vpStr, uint32_t nBytes) { // Appends the chain with the first nBytes nB (void*) buffer of given size. This operation makes no assumptions about buffer content and so the operation is // not null terminated. // // Arguments: 1) vpStr The buffer address as void* // 2) nBytes The number of bytes from the buffer to append to the chain // // Returns: Number of bytes added
_hzfunc("hzXbuf::Append(1)") ;
_xblk* curBlk ; // Working block pointer _xblk* newBlk ; // Working block pointer const char* i ; // Input iterator uint32_t nCan ; // Max number of bytes that can be written to current block uint32_t nWritten = 0 ; // Limiter
if (!nBytes) return nBytes ;
// If nothing in chain, create the first block if (!mx) mx = new _xbuf() ; if (!mx->m_Begin) mx->m_Begin = mx->m_End = _xblk_alloc() ;
curBlk = (_xblk*) mx->m_End ; if (!curBlk) Fatal("Chain %p has no end block\n", this) ;
i = (char*) vpStr ; for (; nWritten < nBytes ;) { if (curBlk->xize == XBLKSIZE) { // Out of space - make new block
newBlk = _xblk_alloc() ; if (!newBlk) Fatal("No allocation (case 2)\n") ; //newBlk->Prev((_xblk*) mx->m_End) ; curBlk->Next(newBlk) ; mx->m_End = newBlk ; curBlk = newBlk ; }
nCan = XBLKSIZE - curBlk->xize ;
if ((nWritten + nCan) > nBytes) nCan = nBytes - nWritten ;
// Add bytes to current block memcpy(curBlk->m_Data + curBlk->xize, i, nCan) ; curBlk->xize += nCan ; i += nCan ; mx->m_nSize += nCan ; nWritten += nCan ; }
return nWritten ; }
// End of hzXbuf Append functions
hzEcode hzXbuf::AddByte (const char C) { // Appends chain with a single byte. Takes the single arg as the char to append, returns either E_OK if successful but E_MEMORY // if not. The latter is a fatal condition. // // Arguments: 1) C Char to add // // Returns: E_OK
_hzfunc("hzXbuf::AddByte") ;
// Place char C on the end of the chain. Must detect physical end of // the current block and add new block
_xblk* curBlk ; // Working block pointer _xblk* newBlk ; // Working block pointer
if (!mx) mx = new _xbuf() ; if (!mx->m_Begin) mx->m_Begin = mx->m_End = _xblk_alloc() ;
curBlk = (_xblk*) mx->m_End ; if (!curBlk) Fatal("Chain %p has no end block\n", this) ;
if (curBlk->xize == XBLKSIZE) { // Out of space - make new block
newBlk = _xblk_alloc() ; if (!newBlk) Fatal("No allocation (case 2)\n") ;
//newBlk->Prev((_xblk*) mx->m_End) ; curBlk->Next(newBlk) ; mx->m_End = newBlk ;
curBlk = newBlk ; }
curBlk->m_Data[curBlk->xize] = C ; curBlk->xize++ ; mx->m_nSize++ ;
return E_OK ; }
hzXbuf& hzXbuf::operator= (const char* s) { // Makes this chain equal to the supplied char string operand. Any pre-existing contents are disregarded. // // Arguments: 1) s The supplied null terminated string // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator=(cstr)") ;
Clear() ; operator+=(s) ; return *this ; }
hzXbuf& hzXbuf::operator= (const hzString& S) { // Makes this chain equal to the supplied string operand. Any pre-existing contents are disregarded. // // Arguments: 1) S The supplied string // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator=(hzString)") ;
Clear() ; operator+=(S) ; return *this ; }
hzXbuf& hzXbuf::operator= (const hzXbuf& op) { // Makes this chain equal to the supplied chain operand. Any pre-existing contents are disregarded. // // Arguments: 1) op The supplied chain // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator=(hzXbuf)") ;
Clear() ;
if (op.mx) { if (_hzGlobal_MT) __sync_add_and_fetch((uint32_t*)&(op.mx->m_copy), 1) ; else op.mx->m_copy++ ; } mx = op.mx ;
return *this ; }
hzXbuf& hzXbuf::operator+= (const hzXbuf& op) { // Append this chain with the supplied chain. This is done as a series of memcpy calls. // // Arguments: 1) supp The supplied chain // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator+=(hzXbuf&)") ;
_xblk* curBlk ; // Block pointer for this chain _xblk* newBlk ; // Working block pointer _xblk* srcBlk ; // Block pointer for the operand chain uint32_t nCan ; // Available space on this chain's current (last) block uint32_t srcOset = 0 ; // Offset into source block
if (!op.mx) return *this ;
// If nothing in current chain, create the first block if (!mx) mx = new _xbuf() ; if (!mx->m_End) mx->m_Begin = mx->m_End = _xblk_alloc() ;
srcBlk = (_xblk*) op.mx->m_Begin ; curBlk = (_xblk*) mx->m_End ; if (!curBlk) Fatal("Chain %p has no end block\n", this) ;
for (;;) { if (curBlk->xize == XBLKSIZE) { newBlk = _xblk_alloc() ; if (!newBlk) Fatal("No allocation (case 2)\n") ;
//newBlk->Prev((_xblk*) mx->m_End) ; curBlk->Next(newBlk) ; mx->m_End = newBlk ;
curBlk = newBlk ; }
nCan = XBLKSIZE - curBlk->xize ; if (nCan > (srcBlk->xize - srcOset)) nCan = (srcBlk->xize - srcOset) ;
memcpy(curBlk->m_Data + curBlk->xize, srcBlk->m_Data + srcOset, nCan) ; curBlk->xize += nCan ; srcOset += nCan ;
if (srcOset >= srcBlk->xize) { if (!srcBlk->Next()) break ; srcBlk = srcBlk->Next() ; srcOset = 0 ; } }
mx->m_nSize += op.mx->m_nSize ;
return *this ; }
hzXbuf& hzXbuf::operator+= (const hzString& s) { // Append chain with supplied string // // Arguments: 1) s The supplied string // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator+=(hzString&)") ;
//const char* i ; //uint32_t len ;
if (!this) hzexit(E_CORRUPT, "No instance") ;
//len = s.Length() ; //i = *s ;
if (!s) return *this ;
Append(*s, s.Length()) ; return *this ; }
hzXbuf& hzXbuf::operator+= (const uchar* s) { // Append the current chain with the supplied uchar string operand. // // Arguments: 1) s The null terminated string to add to the chain // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator+=(uchar*)") ;
_xblk* curBlk ; // Block pointer _xblk* newBlk ; // Working block pointer const uchar* i ; // Supplied string iterator
if (!s || !s[0]) return *this ;
// If nothing in chain, create the first block if (!mx) mx = new _xbuf() ; if (!mx->m_Begin) mx->m_Begin = mx->m_End = _xblk_alloc() ;
curBlk = (_xblk*) mx->m_End ; if (!curBlk) Fatal("Chain %p has no end block\n", this) ;
for (i = s ; *i ; i++) { if (curBlk->xize == XBLKSIZE) { // Out of space - make new block
newBlk = _xblk_alloc() ; if (!newBlk) Fatal("No allocation (case 2)\n") ;
//newBlk->Prev((_xblk*) mx->m_End) ; curBlk->Next(newBlk) ; mx->m_End = newBlk ;
curBlk = newBlk ; }
curBlk->m_Data[curBlk->xize] = *i ; curBlk->xize++ ; mx->m_nSize++ ; }
return *this ; }
hzXbuf& hzXbuf::operator+= (const hzChain& Z) { // Append the current xbuf with the supplied hzChain // // Arguments: 1) s The null terminated string to add to the chain // // Returns: Reference to this chain
_hzfunc("hzXbuf::operator+=(hzChain)") ;
_xblk* curBlk ; // Block pointer _xblk* newBlk ; // Working block pointer chIter zi ; // Chain iterator
if (!Z.Size()) return *this ;
// If nothing in chain, create the first block if (!mx) mx = new _xbuf() ; if (!mx->m_Begin) mx->m_Begin = mx->m_End = _xblk_alloc() ;
curBlk = (_xblk*) mx->m_End ; if (!curBlk) Fatal("Chain %p has no end block\n", this) ;
for (zi = Z ; !zi.eof() ; zi++) { if (curBlk->xize == XBLKSIZE) { // Out of space - make new block
newBlk = _xblk_alloc() ; if (!newBlk) Fatal("No allocation (case 2)\n") ;
//newBlk->Prev((_xblk*) mx->m_End) ; curBlk->Next(newBlk) ; mx->m_End = newBlk ;
curBlk = newBlk ; }
curBlk->m_Data[curBlk->xize] = *zi ; curBlk->xize++ ; mx->m_nSize++ ; }
return *this ; }
/* ** Section 2: hzXbuf Iterator functions */
uchar hzXbuf::Iter::current (void) const { // Return the value of the uchar currently pointed to by the iterator // // Arguments: None // // Returns: >0 The current character of the chain iterator // 0 If the chain iterator is at the end of the chan or the chain is empty
_hzfunc("hzXbuf::Iter::current") ;
_xblk* zp ; // Block pointer
if (!m_block) return m_cDefault ;
zp = (_xblk*) m_block ; return zp->m_Data[m_nOset] ; }
uchar hzXbuf::Iter::operator= (const uchar c) { // Return the value of the char currently pointed to by the iterator // // Arguments: None // // Returns: >0 The current character of the chain iterator // 0 If the chain iterator is at the end of the chan or the chain is empty
_hzfunc("hzXbuf::Iter::operator=") ;
_xblk* zp ; // Block pointer
if (!m_block) return m_cDefault ;
zp = (_xblk*) m_block ; if (!zp) Fatal("Cannot access block %d\n", m_block) ;
if (!zp->Next() && m_nOset == zp->xize) return m_cDefault ;
if (m_nOset >= zp->xize) Fatal("Have block %p next %p oset %d size %d\n", m_block, zp->Next(), m_nOset, zp->xize) ;
zp->m_Data[m_nOset] = c ; return zp->m_Data[m_nOset] ; }
uchar hzXbuf::Iter::operator* (void) const { // Return the value of the uchar currently pointed to by the iterator // // Arguments: None // // Returns: >0 The current character of the chain iterator // 0 If the chain iterator is at the end of the chan or the chain is empty
_hzfunc("hzXbuf::Iter::operator*") ;
_xblk* zp ; // Block pointer
if (!m_block) return m_cDefault ;
zp = (_xblk*) m_block ; if (!zp) Fatal("Cannot access block %d\n", m_block) ;
if (!zp->Next() && m_nOset == zp->xize) return m_cDefault ;
if (m_nOset >= zp->xize) Fatal("Have block %p next %p oset %d size %d\n", m_block, zp->Next(), m_nOset, zp->xize) ;
return zp->m_Data[m_nOset] ; }
bool hzXbuf::Iter::eof (void) const { // Rteurns true if the iterator is at EOF. Returns false otherwise. // // Arguments: None // // Returns: True If the iterator is at EOF // False If the iterator is still valid
_hzfunc("hzXbuf::Iter::eof") ;
_xblk* zp ; // Block pointer
if (!m_block) return true ;
zp = (_xblk*) m_block ; if (!zp) Fatal("Cannot access block %d\n", m_block) ;
if (zp->Next()) return false ; return m_nOset < zp->xize ? false : true ; }
bool hzXbuf::Iter::Equal (const uchar c) const { // Determines if the supplied uchar (arg 1) is the same as the current uchar in the chain iterator. // // - The comparison is case-sensitive. // - Returns true/false // // Arguments: 1) c The test character // // Returns: True If the supplied uchar is equal to that of the current iterator uchar // False Otherwise
_hzfunc("hzXbuf::Iter::Equal(uchar)") ;
_xblk* zp ; // Block pointer
if (!m_block) return false ;
zp = (_xblk*) m_block ; if (!zp) Fatal("Cannot access block %d\n", m_block) ;
return zp->m_Data[m_nOset] == c ? true : false ; }
bool hzXbuf::Iter::Equal (const uchar* s) const { // Determine if the supplied uchar sequence (arg 1) matches that at the current point in the chain iterator, return true if it does, false // otherwise. The comparison is case-sensitive and the function does not alter (advance or retard) the iterator. // // Arguments: 1) s The test uchar string // // Returns: True If the supplied cstr matches that found at the current iterator position // False Otherwise
_hzfunc("hzXbuf::Iter::Equal(uchar*)") ; _xblk* zp ; // Chain block pointer const uchar* i = s ; // Test string iterator uint32_t nOset ; // Offset within block
// Dismiss the case where the iterator is null if (!m_block) return s && s[0] ? false : true ;
zp = (_xblk*) m_block ; if (!zp) Fatal("Cannot access block %d\n", m_block) ;
// Dismiss the case where the operand is null if (!i) return zp->m_Data[nOset] ? false : true ;
// Test for equality for (nOset = m_nOset ; *i ; i++) { if (!zp) return false ;
if (*i != zp->m_Data[nOset]) return false ;
nOset++ ; if (nOset >= zp->xize) { nOset = 0 ; zp = zp->Next() ; } }
return true ; }
bool hzXbuf::Iter::Equiv (const uchar* s) const { // Determines if the supplied char sequence (arg 1) is found at the current char in the chain iterator. Note this function does not advance // the iterator. The comparison is case-insensitive. // // Arguments: 1) s The test uchar string // // Returns: True If the supplied cstr matches that found at the current iterator position // False Otherwise
_hzfunc("hzXbuf::Iter::Equiv") ; _xblk* zp ; // Chain block pointer const uchar* i = s ; // Test string iterator uint32_t nOset ; // Offset within block
// Dismiss the case where the iterator is null if (!m_block) return s && s[0] ? false : true ;
zp = (_xblk*) m_block ; if (!zp) Fatal("Cannot access block %d\n", m_block) ;
// Dismiss the case where the operand is null if (!i) return zp->m_Data[nOset] ? false : true ;
for (nOset = m_nOset ; *i ; i++) { if (!zp) return false ;
if (_tolower(*i) != _tolower(zp->m_Data[nOset])) return false ;
nOset++ ; if (nOset >= zp->xize) { nOset = 0 ; zp = zp->Next() ; } }
return true ; }
uint32_t hzXbuf::Iter::Advance (uint32_t nInc) { // Increments the current chain iterator by the requested length. Will set the iterator to the end of the chain if the requested // increment is too great. // // Arguments: 1) nInc Number of bytes to advance // // Returns: Number of bytes advanced
_hzfunc("hzXbuf::Iter::Advance") ;
_xblk* zp ; // Chain block pointer uint32_t nCan ; // Advance possibible within current block uint32_t nAdv = 0 ; // Number of chars actully advanced
if (nInc < 0) return 0 ;
zp = (_xblk*) m_block ; if (!zp) return 0 ;
for (; nAdv < nInc ;) { nCan = zp->xize - m_nOset ; if ((nCan + nAdv) > nInc) nCan = nInc - nAdv ;
m_nOset += nCan ; nAdv += nCan ;
if (m_nOset == zp->xize) { if (!zp->Next()) break ; m_nOset = 0 ; m_block = zp = zp->Next() ; } }
return nAdv ; }
hzXbuf::Iter& hzXbuf::Iter::operator++ (void) { // Increments the current chain iterator if it can be incremented ie is not at the end of the chain. Note that the void argument means this // is the 'post evaluation version' called when the code is 'iter++' rather than '++iter'. // // Arguments: None // Returns: Reference to this chain iterator
_hzfunc("hzXbuf::Iter::operator++") ;
_xblk* zp ; // Chain block pointer
if (m_block) { zp = (_xblk*) m_block ;
if (zp->m_Data[m_nOset] == CHAR_NL) { m_nCol = 0 ; m_nLine++ ; }
if (zp->m_Data[m_nOset] == CHAR_TAB) m_nCol += (4-(m_nCol%4)) ; else m_nCol++ ;
if (m_nOset < zp->xize) m_nOset++ ;
if (m_nOset >= zp->xize) { if (zp->Next()) { m_block = zp->Next() ; m_nOset = 0 ; } } }
return *this ; }
hzXbuf::Iter& hzXbuf::Iter::operator++ (int) { // Increments the current chain iterator if it can be incremented ie is not at the end of the chain. Note that the void argument means this // is the 'pre evaluation version' called when the code is '++iter' rather than 'iter++'. // // Arguments: Nominal int argument. No actual argument. // Returns: Reference to this chain iterator
_hzfunc("hzXbuf::Iter::operator++") ;
_xblk* zp ; // Chain block pointer
if (m_block) { zp = (_xblk*) m_block ;
if (zp->m_Data[m_nOset] == CHAR_NL) { m_nCol = 0 ; m_nLine++ ; }
if (zp->m_Data[m_nOset] == CHAR_TAB) m_nCol += (4-(m_nCol%4)) ; else m_nCol++ ;
if (m_nOset < zp->xize) m_nOset++ ;
if (m_nOset >= zp->xize) { if (zp->Next()) { m_block = zp->Next() ; m_nOset = 0 ; } } }
return *this ; }
hzXbuf::Iter& hzXbuf::Iter::operator+= (uint32_t nInc) { // Increments the current chain iterator by the requested length. Will set the iterator to the end of the chain if the requested increment is too great. // // Arguments: 1) nInc The number of bytes to increment the chain iterator by // // Returns: Reference to this chain iterator
_hzfunc("hzXbuf::Iter::operator+=") ;
_xblk* zp ; // Chain block pointer
zp = (_xblk*) m_block ;
for (; zp && nInc > 0 ;) { if (zp->m_Data[m_nOset] == CHAR_NL) { m_nCol = 0 ; m_nLine++ ; }
if (zp->m_Data[m_nOset] == CHAR_TAB) m_nCol += (4-(m_nCol%4)) ; else m_nCol++ ;
if (m_nOset < zp->xize) m_nOset++ ;
if (m_nOset >= zp->xize) { if (zp->Next()) { m_nOset = 0 ; m_block = zp = zp->Next() ; } } nInc-- ; }
return *this ; }
uchar hzXbuf::Iter::operator[] (uint32_t nOset) const { // Returns the value of the character pointed to by the iterator plus the supplied offset. The offsets should preferably be small for reasons of efficiency // as the method winds through the requested number of places each time. The envisiaged use is in tokenization or encoding where the percent sign followed // by a percent sign is a percent but a percent sign followed by two hexidecimal characters is an 8-bit ASCII character. It is a convient means of a look // ahead only. // // Arguments: 1) nOset Look ahead offset // // Returns: >0 The character at the relative position // 0 If the current position plus the offset exeeds the chain length.
_hzfunc("hzXbuf::Iter::operator[]") ;
hzXbuf::Iter ci ; // Chain iterator
ci = *this ; ci += nOset ; return *ci ; }
hzXbuf::Iter& hzXbuf::Iter::Skipwhite (void) { // Advance interator to next non-whitespace char. Unless the iterator is currently pointing at a whitespace char, it does nothing. // // Arguments: None // Returns: Reference to this iterator instance
_hzfunc("hzXbuf::Iter::Skipwhite") ;
_xblk* zp ; // Chain block pointer
zp = (_xblk*) m_block ;
if (zp && m_nOset < zp->xize) { for (; zp && IsWhite(zp->m_Data[m_nOset]) ;) { if (zp->m_Data[m_nOset] == CHAR_NL) { m_nCol = 0 ; m_nLine++ ; }
if (zp->m_Data[m_nOset] == CHAR_TAB) m_nCol += (4-(m_nCol%4)) ; else m_nCol++ ;
m_nOset++ ; if (m_nOset >= zp->xize) { if (zp->Next()) { m_block = zp->Next() ; m_nOset = 0 ; zp = zp->Next() ; } } } }
return *this ; }
uint32_t hzXbuf::Iter::Write (void* pBuf, uint32_t maxBytes) { // Write out to the supplied buffer, from the current position, upto maxBytes. Do not increment the iterator. // // Arguments: 1) pBuf The output buffer // 2) maxBytes The maximum number to write (size of buffer) // // Returns: Number of bytes written to the buffer
_hzfunc("hzXbuf::Iter::Write") ;
_xblk* zp ; // Working block pointer uchar* i ; // Input iterator uint32_t nOset ; // Current offset uint32_t nAvail ; // Max number of bytes that can be written from current block uint32_t nWritten = 0 ; // Limiter
if (maxBytes < 0) return -1 ;
zp = (_xblk*) m_block ; if (!zp) return -1 ; nOset = m_nOset ;
i = (uchar*) pBuf ; for (; nWritten < maxBytes ;) { if (nOset == zp->xize) { // At end of current block, move to next zp = zp->Next() ; if (!zp) break ; nOset = 0 ; }
nAvail = zp->xize - nOset ;
if ((nWritten + nAvail) > maxBytes) nAvail = maxBytes - nWritten ;
// Add bytes to current block memcpy(i, zp->m_Data + nOset, nAvail) ; nOset += nAvail ; i += nAvail ; nWritten += nAvail ; }
return nWritten ; }