home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
libg++-2.6-fsf.lha
/
libg++-2.6
/
libg++
/
src
/
String.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-18
|
28KB
|
1,314 lines
/*
Copyright (C) 1988 Free Software Foundation
written by Doug Lea (dl@rocky.oswego.edu)
This file is part of the GNU C++ Library. This library is free
software; you can redistribute it and/or modify it under the terms of
the GNU Library General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version. This 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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
String class implementation
*/
#ifdef __GNUG__
#pragma implementation
#endif
#include <String.h>
#include <std.h>
#include <ctype.h>
#include <limits.h>
#include <new.h>
#include <builtin.h>
// extern "C" {
#include <regex.h>
// }
void String::error(const char* msg) const
{
(*lib_error_handler)("String", msg);
}
String::operator const char*() const
{
return (const char*)chars();
}
// globals
StrRep _nilStrRep = { 0, 1, { 0 } }; // nil strings point here
String _nilString; // nil SubStrings point here
/*
the following inline fcts are specially designed to work
in support of String classes, and are not meant as generic replacements
for libc "str" functions.
inline copy fcts - I like left-to-right from->to arguments.
all versions assume that `to' argument is non-null
These are worth doing inline, rather than through calls because,
via procedural integration, adjacent copy calls can be smushed
together by the optimizer.
*/
// copy n bytes
inline static void ncopy(const char* from, char* to, int n)
{
if (from != to) while (--n >= 0) *to++ = *from++;
}
// copy n bytes, null-terminate
inline static void ncopy0(const char* from, char* to, int n)
{
if (from != to)
{
while (--n >= 0) *to++ = *from++;
*to = 0;
}
else
to[n] = 0;
}
// copy until null
inline static void scopy(const char* from, char* to)
{
if (from != 0) while((*to++ = *from++) != 0);
}
// copy right-to-left
inline static void revcopy(const char* from, char* to, short n)
{
if (from != 0) while (--n >= 0) *to-- = *from--;
}
inline static int slen(const char* t) // inline strlen
{
if (t == 0)
return 0;
else
{
const char* a = t;
while (*a++ != 0);
return a - 1 - t;
}
}
// minimum & maximum representable rep size
#define MAXStrRep_SIZE ((1 << (sizeof(short) * CHAR_BIT - 1)) - 1)
#define MINStrRep_SIZE 16
#ifndef MALLOC_MIN_OVERHEAD
#define MALLOC_MIN_OVERHEAD 4
#endif
// The basic allocation primitive:
// Always round request to something close to a power of two.
// This ensures a bit of padding, which often means that
// concatenations don't have to realloc. Plus it tends to
// be faster when lots of Strings are created and discarded,
// since just about any version of malloc (op new()) will
// be faster when it can reuse identically-sized chunks
inline static StrRep* Snew(int newsiz)
{
unsigned int siz = sizeof(StrRep) + newsiz + MALLOC_MIN_OVERHEAD;
unsigned int allocsiz = MINStrRep_SIZE;
while (allocsiz < siz) allocsiz <<= 1;
allocsiz -= MALLOC_MIN_OVERHEAD;
if (allocsiz >= MAXStrRep_SIZE)
(*lib_error_handler)("String", "Requested length out of range");
StrRep* rep = (StrRep *) new char[allocsiz];
rep->sz = allocsiz - sizeof(StrRep);
return rep;
}
// Do-something-while-allocating routines.
// We live with two ways to signify empty Sreps: either the
// null pointer (0) or a pointer to the nilStrRep.
// We always signify unknown source lengths (usually when fed a char*)
// via len == -1, in which case it is computed.
// allocate, copying src if nonull
StrRep* Salloc(StrRep* old, const char* src, int srclen, int newlen)
{
if (old == &_nilStrRep) old = 0;
if (srclen < 0) srclen = slen(src);
if (newlen < srclen) newlen = srclen;
StrRep* rep;
if (old == 0 || newlen > old->sz)
rep = Snew(newlen);
else
rep = old;
rep->len = newlen;
ncopy0(src, rep->s, srclen);
if (old != rep && old != 0) delete old;
return rep;
}
// reallocate: Given the initial allocation scheme, it will
// generally be faster in the long run to get new space & copy
// than to call realloc
StrRep* Sresize(StrRep* old, int newlen)
{
if (old == &_nilStrRep) old = 0;
StrRep* rep;
if (old == 0)
rep = Snew(newlen);
else if (newlen > old->sz)
{
rep = Snew(newlen);
ncopy0(old->s, rep->s, old->len);
delete old;
}
else
rep = old;
rep->len = newlen;
return rep;
}
// like allocate, but we know that src is a StrRep
StrRep* Scopy(StrRep* old, const StrRep* s)
{
if (old == &_nilStrRep) old = 0;
if (s == &_nilStrRep) s = 0;
if (old == s)
return (old == 0)? &_nilStrRep : old;
else if (s == 0)
{
old->s[0] = 0;
old->len = 0;
return old;
}
else
{
StrRep* rep;
int newlen = s->len;
if (old == 0 || newlen > old->sz)
{
if (old != 0) delete old;
rep = Snew(newlen);
}
else
rep = old;
rep->len = newlen;
ncopy0(s->s, rep->s, newlen);
return rep;
}
}
// allocate & concatenate
StrRep* Scat(StrRep* old, const char* s, int srclen, const char* t, int tlen)
{
if (old == &_nilStrRep) old = 0;
if (srclen < 0) srclen = slen(s);
if (tlen < 0) tlen = slen(t);
int newlen = srclen + tlen;
StrRep* rep;
if (old == 0 || newlen > old->sz ||
(t >= old->s && t < &(old->s[old->len]))) // beware of aliasing
rep = Snew(newlen);
else
rep = old;
rep->len = newlen;
ncopy(s, rep->s, srclen);
ncopy0(t, &(rep->s[srclen]), tlen);
if (old != rep && old != 0) delete old;
return rep;
}
// double-concatenate
StrRep* Scat(StrRep* old, const char* s, int srclen, const char* t, int tlen,
const char* u, int ulen)
{
if (old == &_nilStrRep) old = 0;
if (srclen < 0) srclen = slen(s);
if (tlen < 0) tlen = slen(t);
if (ulen < 0) ulen = slen(u);
int newlen = srclen + tlen + ulen;
StrRep* rep;
if (old == 0 || newlen > old->sz ||
(t >= old->s && t < &(old->s[old->len])) ||
(u >= old->s && u < &(old->s[old->len])))
rep = Snew(newlen);
else
rep = old;
rep->len = newlen;
ncopy(s, rep->s, srclen);
ncopy(t, &(rep->s[srclen]), tlen);
ncopy0(u, &(rep->s[srclen+tlen]), ulen);
if (old != rep && old != 0) delete old;
return rep;
}
// like cat, but we know that new stuff goes in the front of existing rep
StrRep* Sprepend(StrRep* old, const char* t, int tlen)
{
char* s;
int srclen;
if (old == &_nilStrRep || old == 0)
{
s = 0; old = 0; srclen = 0;
}
else
{
s = old->s; srclen = old->len;
}
if (tlen < 0) tlen = slen(t);
int newlen = srclen + tlen;
StrRep* rep;
if (old == 0 || newlen > old->sz ||
(t >= old->s && t < &(old->s[old->len])))
rep = Snew(newlen);
else
rep = old;
rep->len = newlen;
revcopy(&(s[srclen]), &(rep->s[newlen]), srclen+1);
ncopy(t, rep->s, tlen);
if (old != rep && old != 0) delete old;
return rep;
}
// string compare: first argument is known to be non-null
inline static int scmp(const char* a, const char* b)
{
if (b == 0)
return *a != 0;
else
{
signed char diff = 0;
while ((diff = *a - *b++) == 0 && *a++ != 0);
return diff;
}
}
inline static int ncmp(const char* a, int al, const char* b, int bl)
{
int n = (al <= bl)? al : bl;
signed char diff;
while (n-- > 0) if ((diff = *a++ - *b++) != 0) return diff;
return al - bl;
}
int fcompare(const String& x, const String& y)
{
const char* a = x.chars();
const char* b = y.chars();
int al = x.length();
int bl = y.length();
int n = (al <= bl)? al : bl;
signed char diff = 0;
while (n-- > 0)
{
char ac = *a++;
char bc = *b++;
if ((diff = ac - bc) != 0)
{
if (ac >= 'a' && ac <= 'z')
ac = ac - 'a' + 'A';
if (bc >= 'a' && bc <= 'z')
bc = bc - 'a' + 'A';
if ((diff = ac - bc