string.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,411 行 · 第 1/2 页

C
1,411
字号
//
//
// String class: string.c                             version: 0.9
//
// author: Uwe Steinmueller, SIEMENS NIXDORF Informationssysteme AG Munich
//         email: uwe.steinmueller@sniap.mchp.sni.de
//
// start: 28.08.92
//
// this source code is fully copyrighted but it is free in use for
// standardization purposes (X3J16 and ISO WG 21)
//

#include <gstring.h>
#include <iostream.h>
#include <assert.h>
#include <ctype.h>

#ifdef __TCPLUSPLUS__
#define     NORM_ADR(x)   ((char huge*)(x))
#else
#define     NORM_ADR(x)   (x)
#endif /* __TCPLUSPLUS__ */


//
//  overlapping copies, would be supplied with ANSI C memmove()
//  but this is not on all systems available
//

static  void *MemMove(void* s, const void* t, size_t len)
{
    char* target = (char*)s;
    char* p, *tt;

    if(s == t || len == 0)  // nothing to copy
        ;
    else if(len == 1)
        *target = *(char*)t;
    else if(s < t) {
        memcpy(s, t, len);
    }
    else {
        p = target + len - 1;
        tt = (char*)t + len - 1;
        for(; target <= p; p--, tt--)
            *p = *tt;
    }
    return s;
}

inline void
checkOverflow(size_t lower, size_t upper, const char *msg)
{
    if(upper < lower)
/* #####  E029: (col 17) symbol 'strError' has not been declared  */
        strError(msg, "LengthError");
}

//
// private member functions
//

/* #####  E241: (col 14) 'class String' has not been declared  */
void String::doReplace(size_t pos, size_t n, const char* cb, size_t len)
{
/* #####  E029: (col 22) symbol 'length' has not been declared  */
    size_t thisLen = length();
    size_t newlen;

    //
    // preconditions
    //

    assert(pos <= thisLen);   // if pos == thisLen it's like an append
    assert(cb != 0);
    assert(n <= (thisLen - pos));

    //
    // operations
    //

    newlen = len + (thisLen - n);
    checkOverflow(len, newlen, "String::doReplace");

    if(newlen == 0) {
/* #####  E029: (col 15) symbol 'refDec' has not been declared  */
        refDec();
/* #####  E029: (col 9) symbol 'srep' has not been declared  */
        srep = 0;
        return;
    }

    // prevent against hacks like: s.insert(1, s.cStr() + 2)
    //

/* #####  E029: (col 34) symbol 'srep' has not been declared  */
    if(srep && NORM_ADR(srep->str) <= NORM_ADR(cb)
            && NORM_ADR(cb) <= NORM_ADR(srep->str + thisLen)) {
/* #####  E029: (col 25) symbol 'String' has not been declared  */
        replace(pos, n, String(cb, len));
        return;
    }

/* #####  E029: (col 8) symbol 'needClone' has not been declared  */
    if(needClone(newlen)) {
/* #####  E241: (col 17) 'class String' has not been declared  */
/* #####  E006: (col 31) syntax error; probable cause: missing ';'  */
        String::StringRep *ps = StringRep::getNew(pos, newlen, srep->str);

        if(thisLen > 0)     // copy tail
/* #####  E029: (col 20) symbol 'ps' has not been declared  */
            memcpy(ps->str + pos + len, srep->str + pos + n,
                                      thisLen - (pos + n));
/* #####  E029: (col 9) symbol 'refDec' has not been declared  */
        refDec();
        srep = ps;
    }
    else {
        char* ptarget = srep->str;      // srep != 0

        if(n != len)  // move in place
            MemMove(ptarget + pos + len, ptarget + pos + n,
                thisLen - (pos + n));
    }
    if(len > 0)
        memcpy(srep->str + pos, cb, len);
    srep->setLen(newlen);
    assert(newlen == length());
}



/* #####  E241: (col 21) 'class String' has not been declared  */
const char* String::getStr() const
/* #####  E412: (col 1) only member functions can be declared 'const' or 'volatile'  */
{
    const char  *p;

/* #####  E029: (col 8) symbol 'srep' has not been declared  */
    if(srep == 0)
        p = "";
    else
        p = srep->str;
    return p;
}

//
//  private constructor
//

/* #####  E241: (col 9) 'class String' has not been declared  */
String::String(const char* cb1, size_t n1, const char* cb2, size_t n2)
{
    assert(cb1 != 0 && cb2 != 0);

    //
    // operations
    //

    size_t newlen = n1 + n2;

    checkOverflow(n1, newlen, "operator+");   // unsigned overflow

    if(newlen == 0) {
/* #####  E029: (col 14) symbol 'srep' has not been declared  */
        srep = 0;
    }
    else {
/* #####  E241: (col 27) 'class StringRep' has not been declared  */
/* #####  E029: (col 27) symbol 'getNew' has not been declared  */
        srep = StringRep::getNew(n1, newlen, cb1);
/* #####  E133: (col 16) too many errors: compilation aborted  */
        memcpy(srep->str + n1, cb2, n2);
        srep->setLen(newlen);
    }

    //
    // post conditions
    //

    assert(newlen == 0 || srep != 0);
    assert(length() == newlen);
    assert(memcmp(getStr(), cb1, n1) == 0);
    assert(memcmp(getStr() + n1, cb2, n2) == 0);
}



//
//  constructors
//

String::String(const char* cb, size_t n)
{

    //
    // preconditions
    //

    if(cb == 0)
        strError("String::String", "InvalidArgument");

    //
    // operations
    //

    if(n == NPOS)
        n = strlen(cb);

    if(n == 0) {
        srep = 0;
    }
    else {
        srep = StringRep::getNew(n, 0, cb);
    }

    //
    // post conditions
    //

    assert(n == 0 || srep != 0);
    assert(length() == n);
    assert(memcmp(cStr(), cb, length()) == 0);
}

String::String(char  c, size_t rep)
{
    //
    // preconditions
    //

    if(rep == NPOS)
        strError("String::String", "OutOfRange");

    //
    // operations
    //

    if(rep == 0) {
        srep = 0;
    }
    else {
        srep = StringRep::getNew(rep);
        memset(srep->str, c, rep);
    }

    //
    // post conditions
    //

    assert(rep == 0 || srep != 0);
    assert(length() == rep);
#ifndef NDEBUG
    for(int i = 0; i < rep; i++)
        assert(getAt(i) == c);
#endif /* NDEBUG */
}


char String::getAt(size_t pos) const
{
    //
    // preconditions
    //

    if(pos >= length())
        strError("String::getAt", "OutOfRange");

    //
    // operations
    //

    return getAtRaw(pos);
}


void String::putAt(size_t pos, char c)
{
    size_t thisLen = length();

    //
    // preconditions
    //

    if(pos > thisLen)
        strError("String::putAt", "OutOfRange");

    //
    // operations
    //

    if(pos == thisLen)
        append(&c, 1);
    else                    // thisLen > 0 => srep != 0
        putAtRaw(pos, c);
}


//
// assignment operators
//
String& String::operator=(const String& s)
{
    //
    // operations
    //

    ((String&)s).refInc();    // casting away constness, as we change not
                              // the value of the string
    refDec();
    srep = s.srep;

    //
    // post conditions
    //

    assert(length() == s.length());
    assert(memcmp(cStr(), s.cStr(), length()) == 0);

    return *this;
}


String& String::operator=(char c)
{
    //
    // operations
    //

    assign(c, 1);

    return *this;
}

String& String::assign(char c, size_t rep)
{
    // could be implemented more efficiently
    //
    operator=(String(c, rep));

    //
    // post conditions
    //

    assert(length() == rep);
#ifndef NDEBUG
    for(int i = 0; i < rep; i++)
        assert(getAt(i) == c);
#endif /* NDEBUG */

    return *this;
}


String& String::assign(const char* cb, size_t n)
{
    //
    // preconditions
    //

    if(cb == 0)
        strError("String::assign", "InvalidArgument");

    //
    // operations
    //

    if(n == NPOS)
        n = strlen(cb);

    if(n == 0) {
        refDec();
        srep = 0;
    }
    else {
        if(needClone(n)) {
            String::StringRep* rep = StringRep::getNew(n, 0, cb);
            refDec();
            srep = rep;
        }
        else {
            srep->setLen(n);
            memcpy(srep->str, cb, n);
        }
    }

    //
    // post conditions
    //

    assert(length() == n);
    assert(memcmp(cStr(), cb, length()) == 0);

    return *this;
}

//
//  appending operators
//
String& String::operator+=(const String& s)
{
    size_t sLen;
    KEEPOLD;

    //
    // operations
    //

    if(this == &s)              // append to self
        return operator+=(String(s));
    sLen = s.length();
    if(sLen > 0)
        doReplace(length(), 0, s.srep->str, sLen);

    //
    // post conditions
    //

    assert((OLD.length() + s.length()) == length());
    assert(memcmp(cStr() + OLD.length(), s.cStr(), s.length()) == 0);

    return *this;
}

String& String::operator+=(const char *cs)
{
    KEEPOLD;
#ifndef NDEBUG
    char *pOLD = 0;
    if(cs != 0) {
        pOLD = new char[strlen(cs) + 1];
        assert(pOLD != 0);
        strcpy(pOLD, cs);
    }
#endif

    //
    // preconditions
    //

    if(cs == 0)
        strError("String::operator+=", "InvalidArgument");

    //
    // operations
    //

    doReplace(length(), 0, cs, strlen(cs));

    //
    // post conditions
    //

#ifndef NDEBUG
    //
    // this asertion is so complicated
    // because of hacks like: s += s.cStr();
    //
    assert((OLD.length() + strlen(pOLD)) == length());
    assert(memcmp(cStr() + OLD.length(), pOLD, strlen(pOLD)) == 0);
    delete [] pOLD;
#endif

    return *this;
}

String& String::operator+=(char c)
{
    KEEPOLD;

    //
    // operations
    //

    doReplace(length(), 0, &c, 1);

    //
    // post conditions
    //

    assert((OLD.length() + 1) == length());
    assert(getAt(OLD.length()) == c);

    return *this;
}

String& String::append(const char* cb, size_t n)
{
    KEEPOLD;

    //
    // preconditions
    //

    if(cb == 0)
        strError("String::append", "InvalidArgument");

    //
    // operations
    //

    if(n == NPOS)
        n = strlen(cb);

    if(n > 0)
        doReplace(length(), 0, cb, n);

    //
    // post conditions
    //

    assert((OLD.length() + n) == length());
    assert(memcmp(cStr() + OLD.length(), cb, n) == 0);

    return *this;
}


String& String::append(char c, size_t rep)
{
    KEEPOLD;

    //
    // preconditions
    //

    if(rep == NPOS)
        strError("String::append", "OutOfRange");

    //
    // operations
    //

    if(rep == 1)
        doReplace(length(), 0, &c, 1);
    else if(rep > 0)
        operator+=(String(c, rep));

    //
    // post conditions
    //

    assert((OLD.length() + rep) == length());
#ifndef NDEBUG
    for(int i = 0; i < rep; i++) {
        int j = i + OLD.length();
        assert(getAt(j) == c);
    }
#endif /* NDEBUG */

    return *this;
}

int String::compare(const char* cb, size_t n) const
{
    size_t  thisLen  = length();
    int  res;

    //
    // preconditions
    //

    if(cb == 0)
        strError("String::compare", "InvalidArgument");

    //
    // operations
    //

    if(n == NPOS)
        n = strlen(cb);

    res = memcmp(getStr(), cb, thisLen > n ? n : thisLen);
    if(res == 0 && n != thisLen) {
        if(thisLen > n)
            res = 1;
        else
            res = -1;
    }
    return res;
}

//
//  search member functions
//
int String::find(const String& s, size_t& fpos, size_t pos) const
{
    return find(s.getStr(), fpos, pos, s.length());
}

int String::rfind(const String& s, size_t& fpos, size_t pos) const
{
    return rfind(s.getStr(), fpos, pos, s.length());
}

int String::find(const char* cb, size_t& fpos, size_t pos, size_t n) const
{
    size_t thisLen  = length();

    //
    // preconditions
    //

    if(cb == 0)
        strError("String::find", "InvalidArgument");

    //
    // operations
    //

    fpos = NPOS;                            //  not found fpos


    if(pos >= thisLen)
        return 0;

    if(n == NPOS)
        n = strlen(cb);

    if(thisLen == 0 || n > (thisLen - pos))    // not found empty or too long
        return 0;
    if(n == 0) {                             // empty string is always found
        fpos = pos;
        return 1;
    }
    // pointers are valid because thisLen > 0

    char *pStart  = srep->str + pos;
    char *pEnd    = srep->str + thisLen - n;

    for(; pStart <= pEnd; pos++, pStart++) {
        if(*pStart != *cb)
            continue;
        if(memcmp(pStart, cb, n) == 0) {
            fpos = pos;
            return 1;
        }
    }
    return 0;
}

int String::rfind(const char* cb, size_t& fpos, size_t pos, size_t n) const
{
    size_t thisLen  = length();

    //
    // preconditions
    //

    if(cb == 0)
        strError("String::rfind", "InvalidArgument");

    //
    // operations
    //

    fpos = NPOS;                            //  not found fpos

    if(n == NPOS)
        n = strlen(cb);

    if(thisLen == 0 || n > thisLen)            // not found empty or too long
        return 0;

    if(pos >= thisLen)
        pos = thisLen - 1;

    if(n == 0) {                             // empty string is always found
        fpos = pos;
        return 1;
    }
    if((thisLen - n) < pos)
        pos = thisLen - n;

    // pointers are valid because thisLen > 0

    char *pStart  = srep->str + pos;
    char *pBegin  = srep->str;

    for(; pStart >= pBegin; pos--, pStart--) {
        if(*pStart != *cb)
            continue;
        if(memcmp(pStart, cb, n) == 0) {
            fpos = pos;
            return 1;
        }
    }
    return 0;
}

int String::find(char c, size_t& fpos, size_t pos) const
{
    size_t thisLen = length();

    //
    // operations
    //

    fpos = NPOS;

    if(pos >= thisLen || thisLen == 0)
        return 0;

    // pointers are valid because thisLen > 0

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?