Category : C++ Source Code
Archive   : STRX.ZIP
Filename : STR.CPP
Output of file : STR.CPP contained in archive : STRX.ZIP
// str.cpp : str class implementation
// Author : Roy S. Woll
//
// Copyright (c) 1993 by Roy S. Woll
// You may distribute this source freely as long as you leave all files
// in their original form, including the copyright notice as is.
//
//
// Version 2.2 5/12/93
// Fixed substr assignment problem. --> str = substr
// Add member function read, lowercase,
// uppercase, and variations of pad and strip.
//
// Version 2.11 3/17/93
// Friend operator ">>" changed to use str's buffer if > 256.
// Assign operator optimized to not copy referenced data.
// Fix - Remove member function now transfers only necessary characters
//
// Version 2.00 12/5/92
// Support searching/replacing, regular expressions, case sensitivity
//
// Fixed the following bugs.
// 1. Fixed size strings
// 2. Concatenating a substr
//
// Changed member functions pad/strip to modify instance, and introduced
// friend functions pad/strip.
//
// Version 1.00 10/20/92
//
#include
#include
#include
#include
#include
#include "str.h"
#include "dynstream.h"
int strnicmp(const char * s1, const char * s2, unsigned n);
int stricmp(const char * s1, const char * s2);
char * strlwr(char *);
char * strupr(char *);
inline int min(int x, int y){if (x
// Define macro used to adjust internal debugging counters for object
#ifdef DEBUG_STR
#define STR_SUB_COUNTERS(count) count--;
#define STR_ADD_COUNTERS(count) count++;Total##count++;
#else
#define STR_SUB_COUNTERS(count)
#define STR_ADD_COUNTERS(count)
#endif
static str::strdata NullData = {0, 0, 1, 0, 1, ""};
// Create and map to new buffer, and if previous buffer exists,
// transfer to new buffer.
// Delete old buffer if unreferenced.
char * str::getNewBuffer(int newbufsize){
return getNewBuffer(length(), newbufsize);
};
char * str::getNewBuffer(int len, int newbufsize)
{
if (data==&NullData){
if (memsize_incr) newbufsize = max(newbufsize, memsize_init);
else newbufsize = memsize_init;
}
else {
if (!memsize_incr) return NULL;
if ((newbufsize>data->cursize) || (!newbufsize) )
newbufsize = max(newbufsize, data->cursize + memsize_incr);
else newbufsize = max(newbufsize, memsize_init);
}
if (!newbufsize) newbufsize = memsize_incr; // don't allow 0 size
strdata * newdata;
init(newdata, newbufsize, 0);
setNewBuffer(newdata, newbufsize, len);
return data->buf;
};
// Map to new buffer and if previous buffer exists, transfer to new buffer
void str::setNewBuffer(strdata * newdata,
int newbufsize, int len){
newdata->curlength = data->curlength;
newdata->strChange = data->strChange;
if (data->mystream) {
// Use existing stream
newdata->mystream = data->mystream;
// update existing stream to map to new buffer
newdata->mystream->rdbuf()->setNewBuffer(newdata->buf, newbufsize);
// update stream length next time stream is called for previous data
if (!data->strChange){
data->strChange = 1;
data->curlength = data->mystream->rdbuf()->out_waiting();
};
// force previous data to have unitialized stream
data->mystream = NULL;
};
memcpy(newdata->buf, data->buf, len);
if (!(--data->refcount)) {
delete data;
STR_SUB_COUNTERS(AllocationCount)
}
data = newdata;
};
void str::init(strdata*& adata, int cursize,
int curlength)
{
STR_ADD_COUNTERS(AllocationCount)
if (!cursize) cursize=STR_DEFAULT_MEMINCR;
adata =
(strdata *) new char [(cursize+1)+
sizeof(strdata)-strdata::STR_DEBUG_BUFSIZE];
if (!adata){
cout << "Failed to allocate memory (" << cursize << ")" << endl;
assert(adata);
};
adata->cursize=cursize;
adata->curlength=curlength;
adata->refcount=1;
adata->mystream=NULL;
adata->strChange=1;
};
// Construct an empty str
str::str (void):
data(&NullData),
memsize_init(0), memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
data->refcount++;
};
// Construct an empty str
str::str (int p_bufsize, int p_incr):
data(&NullData),
memsize_init(p_bufsize), memsize_incr(p_incr),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
data->refcount++;
};
// Construct a str containing substr, char *
str::str (const char * s1, const char * s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1=(s1 ? strlen(s1) : 0);
int len2=(s2 ? strlen(s2) : 0);
init(data, len1+len2, len1+len2);
memcpy(data->buf, s1, len1);
memcpy(data->buf+len1, s2, len2);
};
// Construct a str containing char *, substr
str::str (const char * s1, const substr& s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1=(s1 ? strlen(s1) : 0);
int len2=s2.length();
init(data, len1+len2, len1+len2);
memcpy(data->buf, s1, len1);
memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
};
// Construct a str containing two char *
str::str (const substr& s1, const char * s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1= s1.length();
int len2= (s2 ? strlen(s2) : 0);
init(data, len1+len2, len1+len2);
memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
memcpy(data->buf+len1, s2, len2);
};
// Construct a str containing two substr
str::str (const substr& s1, const substr& s2):
memsize_init(0),memsize_incr(STR_DEFAULT_MEMINCR),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
int len1= s1.length();
int len2= s2.length();
init(data, len1+len2, len1+len2);
memcpy(data->buf, &s1.mystr->data->buf[s1.posReplace], len1);
memcpy(data->buf+len1, &s2.mystr->data->buf[s2.posReplace], len2);
};
// Construct a str containing char *
str::str (const char * s, int p_bufsize, int p_incr):
memsize_init(p_bufsize),memsize_incr(p_incr),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
if (!s) return;
int curlength, cursize;
if (memsize_incr==0) { // not allowed to expand
curlength = min(strlen(s), memsize_init);
cursize = memsize_init;
}
else {
curlength=strlen(s);
cursize = max(curlength, memsize_init);
};
init(data, cursize, curlength);
memcpy(data->buf, s, curlength);
};
// Construct a str containing str
str::str (const str& s, int p_bufsize, int p_incr):
memsize_init(p_bufsize),memsize_incr(p_incr),
flags(defaultFlags)
{
STR_ADD_COUNTERS(ObjectCount)
if (memsize_incr) {
data = s.data;
data->refcount++;
}
else {
int curlength = min(s.length(), memsize_init);
init(data, memsize_init, curlength);
memcpy(data->buf, s, curlength);
};
};
// Return a ostream that maps to the same buffer as the str
ostream& str::stream(int pos){
return stream().seekp(pos);
};
// Return a ostream that maps to the same buffer as the str
ostream& str::stream(void){
//
// check if need to allocate more memory
//
int allocsize=0;
if (data==&NullData) allocsize = memsize_init; // first time allocating
else if (length()>=size()) allocsize = size()+memsize_incr;
_checkMemAllocation(allocsize);
//
// Create stream if it doesn't exist
// otherwise tell dynstream about me in case it needs to extend buf
//
if (!data->mystream) data->mystream = new dynstream(this);
else data->mystream->rdbuf()->set_str(this);
//
// update stream length if length has been changed by str operators.
// Not done every time in case stream operation was the last operation
// to change the length.
//
if (data->strChange) {
data->mystream->rdbuf()->set_len(data->curlength);
data->strChange=0;
};
return *data->mystream;
};
int str::length(void) const{
if ((!data->strChange) && (data->mystream))
setlength(data->mystream->rdbuf()->out_waiting());
return data->curlength;
};
str::~str (void){
STR_SUB_COUNTERS(ObjectCount)
if (!(--data->refcount)){
STR_SUB_COUNTERS(AllocationCount)
delete data->mystream;
delete data;
};
};
//
// return (const char *)
//
str::operator const char * () const{
data->buf[length()] = 0;
return data->buf;
};
const char * str::operator()(int index) const
{
return (*this)() + index;
}
char& str::operator[](int position) // array indexing
{
if (data->refcount>1) getNewBuffer(data->cursize);
#ifndef SMART_STR_USER
//
// Force string to be null-terminated in case user
// uses the "&" operator to pass a pointer (ie. &mystr[3])
//
if (!data->strChange) return *(char *)(*this)(position);
#endif
return data->buf[position];
}
int str::size(void) const{
return data->cursize;
};
//
// str member = operators
//
str & str::_assign(const char * s, int len)
{
// Get new buffer if necessary, but don't transfer contents.
// This is handled specially, so as to remove the unnecessary transfer.
if ((data->refcount>1) || (size()
if (!memsize_incr) len = min(len, size());
memcpy(data->buf, s, len);
setlength(len);
return *this;
};
str& str::operator = (const str& s){
if (this == &s) return *this; // assignment to self
if (data == s.data) return *this; // assignment to self
if (!memsize_incr) return _assign(s, s.length());
dynstream * prevStream=NULL;
if (!(--data->refcount)) { // deallocate old pointer
STR_SUB_COUNTERS(AllocationCount)
//
// try to reuse this stream
//
prevStream = data->mystream;
if (s.data){
if (s.data->mystream) {
delete data->mystream;
prevStream = NULL;
}
}
delete data;
};
data = s.data;
data->refcount++;
//
// Map my stream to point to an existing stream using buffer data->buf
//
if (prevStream) {
data->mystream = prevStream; // what about previous mystream?
//
// update s stream to map to new this stream
//
data->mystream->rdbuf()->setNewBuffer(data->buf, size());
//
// update stream length next time stream is called for previous data
//
data->strChange = 1;
}
return *this;
};
str& str::operator = (const substr& s){
int len = s.mystr->length() - s.posReplace;
if (len>=0) len = min(s.numReplace, len);
return _assign((*s.mystr)(s.posReplace), len);
};
str& str::operator = (const char * s){
return _assign(s, strlen(s));
};
str& str::assign(const char * s, int len){
return _assign(s, min(strlen(s), len));
};
str& str::operator = (const char s){
return _assign(&s, 1);
};
str & str::_concat(const char * s, int len)
{
int mylen = length();
_checkMemAllocation(mylen + len);
if (!memsize_incr) len = min(len, size()-mylen);
memcpy(data->buf + mylen, s, len); //concat
setlength(mylen+len);
return *this;
};
//
// str member += operators
//
str & str::operator += (const str& s){
if (!length()) return *this=s;
return _concat(s, s.length());
};
str & str::operator += (const substr& s){
return _concat(&s.mystr->data->buf[s.posReplace], s.length());
};
str & str::operator += (const char * s){
return _concat(s, strlen(s));
};
str & str::operator += (const char s){
return _concat(&s, 1);
};
//
// str member << operators
//
str& str::operator << (const str& s) { return *this+=s;};
str& str::operator << (const substr& s) { return *this+=s;};
str& str::operator << (const char * s) { return *this+=s;};
str& str::operator << (const char s) { return *this+=s;};
str& str::operator << (const int s){
stream() << s;
return *this;
};
//
// str member + operators
//
str str::operator+(const _SUBSTR & b) const{ return str(*this,b); };
str str::operator+(const str&b) const{ return str(*this,b); };
str str::operator+(const char * b) const{ return str(*this,b); };
str str::operator+(const char b) const{
char buf[2];
buf[0]=b;
buf[1]=0;
return str(*this,buf);
};
//
// istream/ostream friend functions
//
istream& operator >> (istream& stream, str & s){
if (s.memsize_init>256){ // Use str's current data buffer
s = " "; // Gets new buffer if neccessary (ie. reference)
stream.getline(s.data->buf, s.size());
s.setlength(stream.gcount());
if (s[s.length()]==10) // retrieve to end of line
s.setlength(s.length()-1);
}
else {
char buf[256];
stream.getline(buf, 256);
if (buf[stream.gcount()-1]==10) // retrieve to end of line
buf[stream.gcount()-1]=0;
s = buf;
};
return stream;
};
istream& str::read(istream& stream, int count)
{
*this = " "; // Gets new buffer if neccessary (ie. reference)
stream.read(data->buf, min(size(), count));
setlength(stream.gcount());
return stream;
};
ostream& operator << (ostream& stream, const str & s){
return stream << s();
};
str& str::lowercase()
{
_checkMemAllocation();
strlwr(data->buf);
return *this;
}
str& str::uppercase()
{
_checkMemAllocation();
strupr(data->buf);
return *this;
}
//
// uppercase/lowercase friend functions
//
str uppercase(const char * s) {
str newstr(s);
strupr((char *)newstr());
return newstr;
};
str lowercase(const char * s) {
str newstr(s);
strlwr((char *)newstr());
return newstr;
};
//
// pad/strip
//
str& str::padRight(int padsize, char padchar)
{
return pad(padsize, right, padchar);
}
str& str::padLeft(int padsize, char padchar)
{
return pad(padsize, left, padchar);
}
str& str::padBoth(int padsize, char padchar)
{
return pad(padsize, both, padchar);
}
str& str::pad(int padsize, PadStripT t, char padchar){
int len = length();
if (len
_checkMemAllocation(padsize);
if (!memsize_incr) padsize = min(padsize, size());
if (t == right)
memset(&data->buf[len], padchar, padsize-len);
else if (t == both){
int len1 = (padsize-len)/2;
int len2 = (padsize-len+1)/2;
memmove(&data->buf[len1], &data->buf, len);
memset(&data->buf[0], padchar, len1);
memset(&data->buf[len+len1], padchar, len2);
}
else{
int len1 = (padsize-len);
memmove(&data->buf[len1], &data->buf, len);
memset(&data->buf[0], padchar, len1);
}
setlength(padsize);
};
return *this;
}
str& str::stripTrailing(const char * stripchars)
{
return strip(trailing, stripchars);
}
str& str::stripLeading(const char * stripchars)
{
return strip(leading, stripchars);
}
str& str::stripBoth(const char * stripchars)
{
return strip(both, stripchars);
}
str& str::strip(PadStripT t, char stripchar){
int len = length();
int start = 0;
int end = len-1;
if (end<0) return *this;
if ((t == leading) || (t==both)){
for (; start<=end; start++)
if (data->buf[start] != stripchar) break;
};
if ((t == trailing) || (t==both)){
if (data->buf[end] == stripchar) {
for (; end >= start; end--){
if (data->buf[end] != stripchar) break;
};
};
};
if ((end-start+1)
_checkMemAllocation();
if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
setlength(end-start+1);
};
return *this;
};
str& str::strip(PadStripT t, const char * stripchars){
int len = length();
int start = 0;
int end = len-1;
if (end<0) return *this;
if ((t == leading) || (t==both)){
int pos = strspn((*this)(), stripchars);
if (pos>0) start += pos;
};
if ((t == trailing) || (t==both)){
if (strchr(stripchars, data->buf[end])){
for (; end>=start; end--){
if (!strchr(stripchars, data->buf[end])) break;
}
}
};
if ((end-start+1)
_checkMemAllocation();
if (start) memmove(&data->buf[0], &data->buf[start], end-start+1);
setlength(end-start+1);
};
return *this;
};
str pad(str s, int padsize, str::PadStripT t, char padchar){
return s.pad(padsize, t, padchar);
};
str strip(str s, str::PadStripT t, const char * stripchars){
return s.strip(t, stripchars);
};
str strip(str s, str::PadStripT t, char stripchar){
return s.strip(t, stripchar);
};
//
// insert/remove
//
int str::insert(int pos, char ch){
char tempstr[2];
tempstr[0] = ch;
tempstr[1] = 0;
return insert(pos, tempstr);
}
int str::insert(int pos, const char * insertStr){
int len = length();
int afterPos = len+1-pos; // number of characters following pos
if (afterPos<0) return 0; // out of range
int insertLen = strlen(insertStr);
_checkMemAllocation( len+insertLen );
if (!memsize_incr) insertLen = min(insertLen, size()-len);
if (insertLen){
if (afterPos)
memmove(&data->buf[pos + insertLen], &data->buf[pos], afterPos);
memmove(&data->buf[pos], insertStr, insertLen);
setlength(len+insertLen);
return 1;
}
else return 0;
};
void str::remove(int pos, int numdel){
int len = length();
if (pos>=len) return;
_checkMemAllocation();
numdel = min(numdel, len-pos);
memmove(&data->buf[pos], &data->buf[pos+numdel], len-(numdel+pos));
setlength(len-numdel);
};
//
// substr member operators/functions
//
_SUBSTR::substr(const str * data, int AposReplace, int AnumReplace):
mystr((str *)data), posReplace(AposReplace), numReplace(AnumReplace){};
_SUBSTR str::operator()(int pos, int numreplace)
{
return substr(this, pos, numreplace);
}
const _SUBSTR str::operator()(int pos, int numreplace) const
{
return substr(this, pos, numreplace);
}
int _SUBSTR::length(void) const{
return min(numReplace, max(0, mystr->length()-posReplace) );
};
str & _SUBSTR::operator = (const char * s){
if (posReplace<0) return *this->mystr;
if (strlen(s)==length()){
mystr->_checkMemAllocation();
memcpy(&mystr->data->buf[posReplace], s, length());
}
else {
mystr->remove(posReplace, numReplace);
mystr->insert(posReplace, s);
};
return *this->mystr;
};
str & _SUBSTR::operator = (const substr& s){
return *this = *s.mystr;
};
str _SUBSTR::operator+(const char * s) const{
return str(*this, s);
};
str _SUBSTR::operator+(const substr& s) const{
return str(*this, s);
};
int _SUBSTR::compare(const char * s) const{
return mystr->strncmp((*this->mystr)(posReplace), s, numReplace);
};
int _SUBSTR::compare(const substr& s) const{
int len = min(numReplace, s.numReplace);
return mystr->strncmp((*this->mystr)(posReplace), (*s.mystr)(s.posReplace), len);
};
int _SUBSTR::operator==(const char *s) const{ return compare(s)==0; };
int _SUBSTR::operator<=(const char *s) const{ return compare(s)<=0; };
int _SUBSTR::operator>=(const char *s) const{ return compare(s)>=0; };
int _SUBSTR::operator!=(const char *s) const{ return compare(s)!=0; };
int _SUBSTR::operator< (const char *s) const{ return compare(s)< 0; };
int _SUBSTR::operator> (const char *s) const{ return compare(s)> 0; };
int _SUBSTR::operator==(const substr& s) const{ return compare(s)==0; };
int _SUBSTR::operator<=(const substr& s) const{ return compare(s)<=0; };
int _SUBSTR::operator>=(const substr& s) const{ return compare(s)>=0; };
int _SUBSTR::operator!=(const substr& s) const{ return compare(s)!=0; };
int _SUBSTR::operator< (const substr& s) const{ return compare(s)< 0; };
int _SUBSTR::operator> (const substr& s) const{ return compare(s)> 0; };
_SUBSTR::operator str() const{
str temp;
temp.assign((*(mystr))(posReplace), numReplace);
return temp;
};
int str::_checkMemAllocation(int requiredLen){
if ((data->refcount<=1) && (size()>=requiredLen)) return 1;
return (getNewBuffer(max(size(), requiredLen))!=NULL);
};
//
// Case sensitivity member functions
//
int str::caseSensitive(void) const { return !(flags & ICASE); }
void str::setCaseSensitive(int val)
{
if (val) flags &= !ICASE;
else flags |= ICASE;
}
void str::setdefaultCaseSensitive(int val)
{
if (val) defaultFlags &= !ICASE;
else defaultFlags |= ICASE;
}
//
// Friend/Global str relational operators
//
str operator + (const char *a, const str&b) { return str(a,b); };
str operator + (const char *a, const _SUBSTR&b){ return str(a,b); };
int compare(const char * a, const str & b) {return ( b.strcmp(a, b) );};
int compare(const str& a, const str & b) {return ( a.strcmp(a, b) );};
int compare(const str& a, const char * b) {return ( a.strcmp(a, b) );};
int operator ==(const char *a, const str&b){return (compare(a,b) == 0); };
int operator >=(const char *a, const str&b){return (compare(a,b) >= 0); };
int operator <=(const char *a, const str&b){return (compare(a,b) <= 0); };
int operator !=(const char *a, const str&b){return (compare(a,b) != 0); };
int operator > (const char *a, const str&b){return (compare(a,b) > 0); };
int operator < (const char *a, const str&b){return (compare(a,b) < 0);};
int operator ==(const char *a, const _SUBSTR &b){ return b==a; };
int operator >=(const char *a, const _SUBSTR &b){ return b<=a; };
int operator <=(const char *a, const _SUBSTR &b){ return b>=a; };
int operator !=(const char *a, const _SUBSTR &b){ return b!=a; };
int operator > (const char *a, const _SUBSTR &b){ return b int operator < (const char *a, const _SUBSTR &b){ return b>a; };
//
// Member str relational operators
//
int str::operator==(const char *b) const{ return (compare(*this,b) == 0); };
int str::operator<=(const char *b) const{ return (compare(*this,b) <= 0); };
int str::operator>=(const char *b) const{ return (compare(*this,b) >= 0); };
int str::operator!=(const char *b) const{ return (compare(*this,b) != 0); };
int str::operator> (const char *b) const{ return (compare(*this,b) > 0); };
int str::operator< (const char *b) const{ return (compare(*this,b) < 0); };
int str::operator==(const str &b) const{ return (compare(*this,b) == 0); };
int str::operator<=(const str &b) const{ return (compare(*this,b) <= 0); };
int str::operator>=(const str &b) const{ return (compare(*this,b) >= 0); };
int str::operator!=(const str &b) const{ return (compare(*this,b) != 0); };
int str::operator> (const str &b) const{ return (compare(*this,b) > 0); };
int str::operator< (const str &b) const{ return (compare(*this,b) < 0); };
int str::strncmp(const char * s1, const char * s2, int n) const{
if (caseSensitive()) return ::strncmp(s1,s2,n);
else return ::strnicmp(s1,s2,n);
};
int str::strcmp(const char * s1, const char * s2) const{
if (caseSensitive()) return ::strcmp(s1,s2);
else return ::stricmp(s1,s2);
};
int str::defaultFlags = 0;
#ifdef DEBUG_STR
int str::dynstreamCount=0;
int str::ObjectCount=0;
int str::AllocationCount=0;
int str::TotalObjectCount=0;
int str::TotalAllocationCount=0;
#endif
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/