//
// File: hzEmaddr.cpp
// Purpose: Implimentation of the hzEmaddr (email address) class.
//
// 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 <iostream>
#include <stdarg.h>
#include "hzChars.h"
#include "hzTextproc.h"
#include "hzProcess.h"
#include "hzSSR.h"
/*
** Variables
*/
global hzSet<hzDomain> _hzGlobal_setDomains ; // Repository of domain names
global hzSet<hzEmaddr> _hzGlobal_setEmaddrs ; // Repository of email addresses
global hzSSR g_ssrInet ; // Small string regime reserved for hzEmaddr, hzDomain and hzUrl
/*
** Definitions
*/
struct _ema_space
{
// Internal structure for email address stringspace. Note there is no constructor as string spaces are allocated by Alloc() from superblocks.
uchar m_copy ; // Copy counter
uchar m_lhs ; // Length left of the '@'
uchar m_rhs ; // Length right of the '@'
char m_data[5] ; // First part of data
} ;
#define EMA_FACTOR 4 // This is added to the email string size to accomodate the copy count and the size of the strings to the left and right of the @,
// the @ itself and the null terminator.
/*
** Global constants
*/
global const hzEmaddr _hz_null_hzEmaddr ; // Null email address
/*
** hzEmaddr public methods
*/
void hzEmaddr::Clear (void)
{
// Clear the contents
//
// Arguments: None
// Returns: None
_hzfunc("hzEmaddr::Clear") ;
_ema_space* pCtrl ; // This email address space
uint32_t nLen ; // Length
hzEcode rc = E_OK ; // Return code
if (m_addr)
{
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
hzexit(E_CORRUPT, "Illegal string address %u:%u", (m_addr&0x7fff0000)>>16, m_addr&0xffff) ;
if (pCtrl->m_copy == 0)
{ threadLog("Deletion in progress address %u:%u\n", (m_addr&0x7fff0000)>>16, m_addr&0xffff) ; m_addr = 0 ; return ; }
if (pCtrl->m_copy == 0xff)
{
//hzerr(E_CORRUPT, "Invalid email addr (cpy %u lhs %u rhs %u) address %u:%u", pCtrl->m_copy, pCtrl->m_lhs, pCtrl->m_rhs, (m_addr&0x7fff0000)>>16, m_addr&0xffff) ;
threadLog("CORRUPT: Invalid email addr (cpy %u lhs %u rhs %u) address %u:%u\n", pCtrl->m_copy, pCtrl->m_lhs, pCtrl->m_rhs, (m_addr&0x7fff0000)>>16, m_addr&0xffff) ;
m_addr = 0 ;
return ;
}
if (pCtrl->m_copy && pCtrl->m_copy < 100)
{
if (_hzGlobal_MT)
__sync_add_and_fetch(&(pCtrl->m_copy), -1) ;
else
pCtrl->m_copy-- ;
if (pCtrl->m_copy == 0)
{
// threadLog("Freeing emaddr (cpy %u lhs %u rhs %u) address %u:%u [%s]\n",
// pCtrl->m_copy, pCtrl->m_lhs, pCtrl->m_rhs, (m_addr&0x7fff0000)>>16, m_addr&0xffff, pCtrl->m_data) ;
//pCtrl->m_copy = 0xff ;
nLen = pCtrl->m_lhs + pCtrl->m_rhs + 1 ;
rc = g_ssrInet.Free(m_addr, nLen + EMA_FACTOR) ;
}
}
m_addr = 0 ;
}
if (rc != E_OK)
threadLog("Email address %s not deleted\n", pCtrl->m_data) ;
}
uint32_t hzEmaddr::Length (void) const
{
// Return length in bytes of the whole email address
_hzfunc("hzEmaddr::Length") ;
_ema_space* pCtrl ; // This email address space
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{ threadLog("Ivalid string space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return pCtrl->m_lhs + pCtrl->m_rhs + 1 ;
}
uint32_t hzEmaddr::Copies (void) const
{
// Return number of copies for diagnostics
_hzfunc("hzEmaddr::Copies") ;
_ema_space* pCtrl ; // This email address space
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{ threadLog("Ivalid string space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return pCtrl->m_copy ;
}
bool hzEmaddr::_inc_copy (void) const
{
_ema_space* pCtrl ; // This string's control area
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{
threadLog("_inc_copy - invalid address %u:%u\n", (m_addr&0xffff0000)>>16, (m_addr&0xffff)) ;
return false ;
}
if (pCtrl->m_copy == 0xff)
{
threadLog("_inc_copy - item deleted (%u:%u)\n", (m_addr&0xffff0000)>>16, (m_addr&0xffff)) ;
return false ;
}
if (pCtrl->m_copy < 100)
pCtrl->m_copy++ ;
return true ;
}
void hzEmaddr::_dec_copy (void) const
{
_ema_space* pCtrl ; // This string's control area
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (pCtrl->m_copy == 1)
threadLog("WARNING: EMA _dec_copy would zero copy count\n") ;
else
pCtrl->m_copy-- ;
}
bool hzEmaddr::valid (void) const
{
_ema_space* pCtrl ; // This string's control area
_ssrFLE* pSlot ; // Item cast to _ssrFLE (to self point on free and to check it is not already free)
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
pSlot = (_ssrFLE*) pCtrl ;
if (!pCtrl->m_copy || pCtrl->m_copy == 0xff)
return false ;
return true ;
}
uint32_t hzEmaddr::LhsLen (void) const
{
// Return length in bytes of the first part email address
_hzfunc("hzEmaddr::LhsLen") ;
_ema_space* pCtrl ; // This email address space
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{ threadLog("Ivalid string space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return pCtrl->m_lhs ;
}
uint32_t hzEmaddr::DomLen (void) const
{
// Return length in bytes of the domain part of the email address
_hzfunc("hzEmaddr::DomLen") ;
_ema_space* pCtrl ; // This email address space
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{ threadLog("Ivalid string space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return pCtrl->m_rhs ;
}
const char* hzEmaddr::GetDomain (void) const
{
// Return domain name as null terminated string
_hzfunc("hzEmaddr::GetDomain") ;
_ema_space* pCtrl ; // This email address space
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{ threadLog("Ivalid string space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return pCtrl->m_data + pCtrl->m_lhs + 1 ;
}
const char* hzEmaddr::GetAddress (void) const
{
// Return whole email address as null terminated string
_hzfunc("hzEmaddr::GetAddress") ;
_ema_space* pCtrl ; // This email address space
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
if (!pCtrl)
{ threadLog("Ivalid string space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return pCtrl->m_data ;
}
hzEmaddr& hzEmaddr::operator= (const char* cpStr)
{
// Assign the hzEmaddr to an email address held in a character string
//
// Argument: cpStr A null terminated string assumed to be an email address
//
// Returns: Reference to this email adress instance in all cases.
//
// Note: This function will record an E_FORMAT error if the supplied cstr did not amount to an email address
_hzfunc("hzEmaddr::operator=(cstr)") ;
_ema_space* destCtl ; // This email address space
const char* i ; // Email iterator
char* j ; // Email iterator
uint32_t nLhs = 0 ; // LHS part of email address
uint32_t nRhs = 0 ; // RHS part of email address
Clear() ;
if (!cpStr || !cpStr[0])
return *this ;
if (!IsEmaddr(cpStr))
{
hzerr(E_FORMAT, "Cannot assign %s", cpStr) ;
return *this ;
}
for (i = cpStr ; *i && *i != '@' ; nLhs++, i++) ;
if (*i == '@')
for (i++ ; *i ; nRhs++, i++) ;
if (nLhs < 1 || nLhs > 192 || nRhs < 1 || nRhs > 63)
{
hzerr(E_FORMAT, "Cannot assign %s", cpStr) ;
return *this ;
}
m_addr = g_ssrInet.Alloc(nLhs + nRhs + 1 + EMA_FACTOR) ;
if (!m_addr)
hzexit(E_MEMORY, "Cannot assign %s", cpStr) ;
destCtl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
// Assign the value
destCtl->m_copy = 1 ;
destCtl->m_lhs = nLhs & 0xff ;
destCtl->m_rhs = nRhs & 0xff ;
for (j = destCtl->m_data, i = cpStr ; *i ; *j++ = _tolower(*i++)) ;
*j = 0 ;
return *this ;
}
hzEmaddr& hzEmaddr::operator= (const hzString& S)
{
// Assign the hzEmaddr to an email address held in a hzString instance
//
// Argument: S A string assumed to be an email address
//
// Returns: Reference to this email adress instance in all cases.
//
// Note: This function will record an E_FORMAT error if the supplied cstr did not amount to an email address
_hzfunc("hzEmaddr::operator=(hzStr)") ;
Clear() ;
return operator=(*S) ;
}
hzEmaddr& hzEmaddr::operator= (const hzChain::Iter& ci)
{
// Determines if the supplied iterator is at the start of a valid email address and if it is, assignes this as the value to the calling instance.
//
// Argument: ci Chain iterator
//
// Returns: Reference to this email address instance. This will be empty if the input did not amount to an email address
_hzfunc("hzEmaddr::operator=(chIter)") ;
hzChain::Iter xi ; // External chain iterator
_ema_space* pCtrl ; // This email address space
char* i ; // For populating string
int32_t at = 0 ; // The @ has been encountered (later used as a counter)
uchar nLhs = 0 ; // Chars before the @
uchar nRhs = 0 ; // Chars after the @
uchar nPeriod = 0 ; // No of periods on RHS
char lCh = 0 ; // Last char processed
Clear() ;
if (ci.eof())
return *this ;
// Process the string and set char incidence aggregates
for (xi = ci ; !xi.eof() && *xi > CHAR_SPACE ; lCh = *xi, xi++)
{
if (*xi == CHAR_AT)
{
if (at)
return *this ;
if (!lCh || lCh == CHAR_PERIOD)
return *this ;
at = 1 ;
continue ;
}
if (*xi == CHAR_PERIOD)
{
if (!lCh || lCh == CHAR_PERIOD || lCh == CHAR_AT)
return *this ;
if (at)
{ nRhs++ ; nPeriod++ ; }
else
nLhs++ ;
continue ;
}
if (at)
{
if (IsUrlnorm(*xi))
{
nRhs++ ;
if (nRhs > 63)
return *this ;
continue ;
}
}
else
{
if (IsUrlnorm(*xi) || *xi=='!' || *xi=='#' || *xi=='$' || *xi=='%' || *xi=='&' || *xi=='\'' || *xi=='*' || *xi=='+'
|| *xi=='/' || *xi=='=' || *xi=='?' || *xi=='^' || *xi=='`' || *xi=='{' || *xi=='|' || *xi=='}' || *xi=='~' || *xi=='.')
{
nLhs++ ;
if (nLhs > 192)
return *this ;
continue ;
}
}
break ;
}
if (lCh == CHAR_PERIOD || !at || !nPeriod || !nLhs || nRhs < 2)
{
hzerr(E_FORMAT, "Cannot assign") ;
return *this ;
}
if (lCh == CHAR_PERIOD) return *this ;
if (!at) return *this ;
if (!nPeriod) return *this ;
if (!nLhs || nRhs < 2) return *this ;
//m_cpBuf = new uchar[nLhs + nRhs + 5] ;
m_addr = g_ssrInet.Alloc(nLhs + nRhs + 1 + EMA_FACTOR) ;
if (!m_addr)
hzexit(E_MEMORY, "Cannot assign %d bytes", nLhs + nRhs + 5) ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
i = (char*) pCtrl->m_data ;
for (xi = ci, at = 0 ; at < (nLhs + nRhs + 1) ; at++, xi++)
i[at] = _tolower(*xi) ;
i[at] = 0 ;
pCtrl->m_copy = 1 ;
pCtrl->m_lhs = nLhs ;
pCtrl->m_rhs = nRhs ;
return *this ;
}
hzEmaddr& hzEmaddr::operator= (const hzEmaddr& E)
{
// Assign the hzEmaddr to an email address held in another hzEmaddr instance
//
// Arguments: 1) E The supplied email address as a hzEmail instance
//
// Returns: Reference to this hzEmail instance
// It this internal pointer and that of the operand already point to the same space in memory, do nothing
_hzfunc("hzEmaddr::operator=") ;
_ema_space* pSupp ; // Supplied email address space
if (m_addr == E.m_addr)
return *this ;
Clear() ;
if (E.m_addr)
{
// Increment copy count
pSupp = (_ema_space*) g_ssrInet.Xlate(E.m_addr) ;
if (!pSupp)
{
threadLog("Invalid src emaddr - addr is %u:%u\n", (E.m_addr & 0xffff0000) >> 16, E.m_addr & 0xffff) ;
return *this ;
}
if (pSupp->m_copy == 0xff)
{
threadLog("Trying to assign to a deleted emaddr <%s>\n", pSupp->m_data) ;
m_addr = 0 ;
return *this ;
}
if (pSupp->m_copy < 100)
{
if (_hzGlobal_MT)
//__sync_add_and_fetch(&(suppCtl->m_copy), 1) ;
pSupp->m_copy++ ;
else
pSupp->m_copy++ ;
}
m_addr = E.m_addr ;
}
return *this ;
}
/*
** Compare operators
*/
static int32_t _lhscompare (const char* a, const char* b)
{
// Compare only upto the @ in what is assumend to be two email addresses
//
// Arguments: 1) a First email address
// 2) b Second email address
//
// Returns: -1 If the LHS of a < LHS of b
// +1 If the LHS of a > LHS of b
// 0 If the LHS of a = LSH of b
_hzfunc(__func__) ;
for (; *a && *a != '@' && *a == *b ; a++, b++) ;
if (*a == '@' || *a == 0)
{
if (*b == '@' || *b == 0)
return 0 ;
return -1 ;
}
if (*b == '@' || *b == 0)
return 1 ;
return *a > *b ? 1 : -1 ;
}
bool hzEmaddr::operator== (const hzEmaddr& E) const
{
// Test for equality between this hzEmaddr and an operand instance
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is equal to the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator==") ;
_ema_space* pCtrl ; // This email address space
_ema_space* suppCtl ; // Supplied email address space
int32_t res ; // Comparison result
if (m_addr == E.m_addr) return true ;
if (m_addr && E.m_addr == 0) return false ;
if (E.m_addr && m_addr == 0) return false ;
// Compare domains first then LHS
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
suppCtl = (_ema_space*) g_ssrInet.Xlate(E.m_addr) ;
// Compare domains
res = strcmp(pCtrl->m_data + pCtrl->m_lhs + 1, suppCtl->m_data + suppCtl->m_lhs + 1) ;
if (res)
return false ;
// Compare LHS
res = _lhscompare((char*) pCtrl->m_data, (char*) suppCtl->m_data) ;
if (res)
return true ;
return false ;
}
bool hzEmaddr::operator< (const hzEmaddr& E) const
{
// Return true if this hzEmaddr instance is lexically less than the operand. Note that comparison is first done on the domain part (the RHS
// of the @) and then done on the address part (the LHS of the @)
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is lexically less than the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator<") ;
int32_t res ; // Comparison result
// Are this and the operand connected?
if (m_addr == E.m_addr) return false ;
if (m_addr && E.m_addr == 0) return false ;
if (E.m_addr && m_addr == 0) return true ;
// Compare domains first
res = strcmp(GetDomain(), E.GetDomain()) ;
if (res < 0)
return true ;
if (res > 0)
return false ;
// Domains are equal so compare LHS
res = _lhscompare(GetAddress(), *E) ;
return res < 0 ? true : false ;
}
bool hzEmaddr::operator<= (const hzEmaddr& E) const
{
// Return true if this hzEmaddr instance is lexically less than or equal to the operand. Note that comparison is first done on the domain
// part (the RHS of the @) and then done on the address part (the LHS of the @)
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is lexically less than or equal to the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator<=") ;
int32_t res ; // Comparison result
// Are this and the operand connected?
if (m_addr == E.m_addr) return true ;
if (m_addr && E.m_addr == 0) return false ;
if (E.m_addr && m_addr == 0) return true ;
// Compare domains first
res = strcmp(GetDomain(), E.GetDomain()) ;
if (res < 0)
return true ;
if (res > 0)
return false ;
// Domains are equal so compare LHS
res = _lhscompare(GetAddress(), E) ;
return res <= 0 ? true : false ;
}
bool hzEmaddr::operator> (const hzEmaddr& E) const
{
// Return true if this hzEmaddr instance is lexically greater than the operand. Note that comparison is first done on the domain
// part (the RHS of the @) and then done on the address part (the LHS of the @)
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is lexically greater than the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator>") ;
int32_t res ; // Comparison result
// Are this and the operand connected?
if (m_addr == E.m_addr) return false ;
if (m_addr && E.m_addr == 0) return true ;
if (E.m_addr && m_addr == 0) return false ;
// Compare domains first
res = strcmp(GetDomain(), E.GetDomain()) ;
if (res > 0)
return true ;
if (res < 0)
return false ;
// Domains are equal so compare LHS
res = _lhscompare(GetAddress(), E) ;
return res > 0 ? true : false ;
}
bool hzEmaddr::operator>= (const hzEmaddr& E) const
{
// Return true if this hzEmaddr instance is lexically greater than or equal to the operand. Note that comparison is first done on the domain
// part (the RHS of the @) and then done on the address part (the LHS of the @)
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is lexically greater than or equal to the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator>=") ;
int32_t res ; // Comparison result
// Are this and the operand connected?
if (m_addr == E.m_addr) return true ;
if (m_addr && E.m_addr == 0) return true ;
if (E.m_addr && m_addr == 0) return false ;
// Compare domains first
res = strcmp(GetDomain(), E.GetDomain()) ;
if (res > 0)
return true ;
if (res < 0)
return false ;
// Domains are equal so compare LHS
res = _lhscompare(GetAddress(), E) ;
return res >= 0 ? true : false ;
}
bool hzEmaddr::operator== (const hzString& S) const
{
// Test for equality between this hzEmaddr and an email address held in a hzString
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is lexically equal to the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator==") ;
_ema_space* pCtrl ; // This email address space
if (!S && !m_addr) return true ;
if (!S) return false ;
if (!m_addr) return false ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) pCtrl->m_data, *S) == 0 ? true : false ;
}
bool hzEmaddr::operator!= (const hzString& S) const
{
// Test for inequality between this hzEmaddr and an email address held in a hzString
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is not lexically equal to the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator!=") ;
_ema_space* pCtrl ; // This email address space
if (!S && !m_addr) return false ;
if (!S) return true ;
if (!m_addr) return true ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) pCtrl->m_data, *S) == 0 ? false : true ;
}
bool hzEmaddr::operator== (const char* cpStr) const
{
// Test for equality between this hzEmaddr and an email address held in a character string
//
// Arguments: 1) E Test email address
//
// Returns: True If this addesss is lexically equal to the supplied test email address
// False Otherwise
_hzfunc("hzEmaddr::operator==") ;
_ema_space* pCtrl ; // This email address space
if ((!cpStr || !cpStr[0]) && !m_addr)
return true ;
if (!cpStr || !cpStr[0])
return false ;
if (!m_addr)
return false ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) pCtrl->m_data, cpStr) == 0 ? true : false ;
}
bool hzEmaddr::operator!= (const char* cpStr) const
{
// Test for inequality between this hzEmaddr and an email address held in a character string
//
// Arguments: 1) E Test email address
//
// Returns: True If this email addesss is not lexically equal to the supplied
// False If this email address has the same value as the supplied
_hzfunc("hzEmaddr::operator!=") ;
_ema_space* pCtrl ; // This email address space
if ((!cpStr || !cpStr[0]) && !m_addr)
return false ;
if (!cpStr || !cpStr[0])
return true ;
if (!m_addr)
return true ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) pCtrl->m_data, cpStr) == 0 ? false:true ;
}
const char* hzEmaddr::operator* (void) const
{
// Returns the URL data (a null terminated string)
//
// Arguments: None
// Returns: Content as null terminated string
_hzfunc("hzEmaddr::operator*") ;
_ema_space* pCtrl ; // This string's control area
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
return pCtrl->m_data ;
}
hzEmaddr::operator const char* (void) const
{
// Returns the string data (a null terminated string)
//
// Arguments: None
// Returns: Content as null terminated string
_hzfunc("hzEmaddr::operator const char*") ;
_ema_space* pCtrl ; // This string's control area
if (!m_addr)
return 0 ;
pCtrl = (_ema_space*) g_ssrInet.Xlate(m_addr) ;
return pCtrl->m_data ;
}
/*
** Stream operator
*/
std::ostream& operator<< (std::ostream& os, const hzEmaddr& obj)
{
// Category: Data Output
//
// Friend function to hzEmaddr class to stream out the email address.
//
// Arguments: 1) os Reference to output stream
// 2) ema Const reference to an email address
//
// Returns: Reference to the supplied output stream
_hzfunc("operator<<(ostream,hzEmaddr)") ;
os << *obj ;
return os ;
}
bool IsEmaddr (const char* cpStr)
{
// Category: Text Processing
//
// Tests if a supplied string (or text at a hzChain iterator) is of the form of an email address. To qualify, there must be a single occurence
// of '@' both preceeded and followed by strings of non-zero length whose characters are members of a set of permitted characters (see below).
// There also must be at least one period in the string following the @. Additionally the length of the whole must not exceed 255.
//
// The first instance of a whitespace character (<= space) terminates the test. If the string up to but not including the whitespace character
// or null terminator, then the test is passed, otherwise it fails.
//
// Permitted chars on the LHS of the '@' are: [a-z], [A-Z], [0-9], [!, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, }, ~] and the period (.)
// if it is not the last character in the string.
//
// Permitted chars on the LHS of the '@' are: [a-z], [A-Z], [0-9] and the period (.) or minus sign (-) if they are not the last character in the
// string.
//
// Arguments: 1) cpStr The char pointer to be tested
//
// Returns: True If the supplied cstr sets the email address
// False Otherwise
_hzfunc("IsEmaddr") ;
const char* i ; // Source string iterator
uint32_t nLhs = 0 ; // Count to the left of the @
uint32_t nRhs = 0 ; // Count to the right of the @
bool bPeriod = false ; // Confirmed period
if (!cpStr || !cpStr[0])
return false ;
// Count chars upto the @
for (i = cpStr ; *i > CHAR_SPACE ; i++)
{
if (*i == CHAR_AT)
break ;
if ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z') || (*i >= '0' && *i <= '9')
|| *i=='!' || *i=='#' || *i=='$' || *i=='%' || *i=='&' || *i=='\'' || *i=='*' || *i=='+' || *i=='-'
|| *i=='/' || *i=='=' || *i=='?' || *i=='^' || *i=='_' || *i=='`' || *i=='{' || *i=='|' || *i=='}' || *i=='~'
|| (*i=='.' && i[1] > ' ' && i[1] != '@' && nLhs))
{
nLhs++ ;
if (nLhs > 63)
return false ;
continue ;
}
break ;
}
if (*i != CHAR_AT || !nLhs)
return false ;
// Count chars beyond @
for (i++ ; *i > CHAR_SPACE ; i++)
{
if (*i == CHAR_AT)
return false ;
if (*i == CHAR_PERIOD && i[1] && i[1] != CHAR_PERIOD)
{ bPeriod = true ; continue ; }
if ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z') || (*i >= '0' && *i <= '9')
|| (*i=='-' && i[1] > ' ' && nRhs)
|| (*i=='.' && i[1] > ' ' && nRhs))
{
nRhs++ ;
if (nRhs > 192)
return false ;
continue ;
}
break ;
}
if (bPeriod && nLhs && nRhs > 2)
return true ;
return false ;
}
bool AtEmaddr (hzEmaddr& ema, uint32_t& nLen, hzChain::Iter& ci)
{
// Category: Text Processing
//
// If the supplied iterator is at the start of a valid email address, then the supplied email address instance will be populated with this
// address as the value and the supplied length will be set.
//
// Arguments: 1) ema Reference to an email address, populated by this function
// 2) nLen Reference to an integer set to the email length
// 3) ci Input chain iterator
//
// Returns: True If the supplied cstr sets the email address
// False Otherwise
_hzfunc("AtEmaddr") ;
ema.Clear() ;
ema = ci ;
if (!ema)
return false ;
nLen = ema.Length() ;
return true ;
}
/*
** Diagnostics
*/
hzEcode IntegEmaddrSet (bool bVerbose)
{
// Runs through the _hzGlobal_setEmaddrs, looking for invalid entires
_hzfunc(__func__) ;
hzLogger* pLog ; // Log file
_ema_space* pCtrl ; // This string's control area
//_ssrFLE* pSlot ; // Item cast to _ssrFLE (to self point on free and to check it is not already free)
hzEmaddr ema ; // Email address
uint32_t n ; // Iterator
uint32_t addr ; // Internal address
uint32_t nFail ; // Number of invalid addresses
uint32_t nPass ; // Number of invalid addresses
pLog = GetThreadLogger() ;
for (n = nPass = nFail = 0 ; n < _hzGlobal_setEmaddrs.Count() ; n++)
{
ema = _hzGlobal_setEmaddrs.GetObj(n) ;
addr = ema._int_addr() ;
if (!addr)
{ nFail++ ; continue ; }
pCtrl = (_ema_space*) g_ssrInet.Xlate(addr) ;
//pSlot = (_ssrFLE*) pCtrl ;
if (!pCtrl->m_copy || pCtrl->m_copy == 0xff || !pCtrl->m_lhs || !pCtrl->m_rhs)
nFail++ ;
else
{
if (bVerbose)
pLog->Out("%u:%u: copy %u -> %s\n", (addr&0xffff0000) >> 16, addr&0xffff, pCtrl->m_copy, pCtrl->m_data) ;
nPass++ ;
}
}
pLog->Log("Total email population %u. No OK %u Failed %u\n", _hzGlobal_setEmaddrs.Count(), nPass, nFail) ;
return E_OK ;
}
void InetIntegrityReport (hzChain& report)
{
_hzfunc(__func__) ;
g_ssrInet.Report(report) ;
}