+// This may look like C code, but it is really -*- C++ -*-
+/*
+Copyright (C) 1988 Free Software Foundation
+ written by Doug Lea (dl@rocky.oswego.edu)
+
+This file is part of GNU CC.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY. No author or distributor
+accepts responsibility to anyone for the consequences of using it
+or for whether it serves any particular purpose or works at all,
+unless he says so in writing. Refer to the GNU CC General Public
+License for full details.
+
+Everyone is granted permission to copy, modify and redistribute
+GNU CC, but only under the conditions described in the
+GNU CC General Public License. A copy of this license is
+supposed to have been given to you along with GNU CC so you
+can know your rights and responsibilities. It should be in a
+file named COPYING. Among other things, the copyright notice
+and this notice must be preserved on all copies.
+*/
+
+#if defined(SHORT_NAMES) || defined(VMS)
+#define re_compile_pattern recmppat
+#define re_pattern_buffer repatbuf
+#define re_registers reregs
+#endif
+
+#ifndef _String_h
+#ifdef __GNUG__
+#pragma once
+#pragma interface
+#endif
+#define _String_h 1
+
+#include <stream.h>
+#include <Regex.h>
+
+struct StrRep // internal String representations
+{
+ unsigned short len; // string length
+ unsigned short sz; // allocated space
+ char s[1]; // the string starts here
+ // (at least 1 char for trailing null)
+ // allocated & expanded via non-public fcts
+};
+
+// primitive ops on StrReps -- nearly all String fns go through these.
+
+StrRep* Salloc(StrRep*, const char*, int, int);
+StrRep* Scopy(StrRep*, StrRep*);
+StrRep* Sresize(StrRep*, int);
+StrRep* Scat(StrRep*, const char*, int, const char*, int);
+StrRep* Scat(StrRep*, const char*, int,const char*,int, const char*,int);
+StrRep* Sprepend(StrRep*, const char*, int);
+StrRep* Sreverse(StrRep*, StrRep*);
+StrRep* Supcase(StrRep*, StrRep*);
+StrRep* Sdowncase(StrRep*, StrRep*);
+StrRep* Scapitalize(StrRep*, StrRep*);
+
+// These classes need to be defined in the order given
+
+class String;
+class SubString;
+
+class SubString
+{
+ friend class String;
+protected:
+
+ String& S; // The String I'm a substring of
+ unsigned short pos; // starting position in S's rep
+ unsigned short len; // length of substring
+
+ void assign(StrRep*, const char*, int = -1);
+ SubString(String& x, int p, int l);
+ SubString(const SubString& x);
+
+public:
+
+// Note there are no public constructors. SubStrings are always
+// created via String operations
+
+ ~SubString();
+
+ void operator = (const String& y);
+ void operator = (const SubString& y);
+ void operator = (const char* t);
+ void operator = (char c);
+
+// return 1 if target appears anywhere in SubString; else 0
+
+ int contains(char c) const;
+ int contains(const String& y) const;
+ int contains(const SubString& y) const;
+ int contains(const char* t) const;
+ int contains(const Regex& r) const;
+
+// return 1 if target matches entire SubString
+
+ int matches(const Regex& r) const;
+
+// IO
+
+ friend ostream& operator<<(ostream& s, const SubString& x);
+
+// status
+
+ int length() const;
+ int empty() const;
+ const char* chars() const;
+
+ int OK() const;
+
+};
+
+
+class String
+{
+ friend class SubString;
+
+protected:
+ StrRep* rep; // Strings are pointers to their representations
+
+// some helper functions
+
+ int search(int, int, const char*, int = -1) const;
+ int search(int, int, char) const;
+ int match(int, int, int, const char*, int = -1) const;
+ int _gsub(const char*, int, const char* ,int);
+ int _gsub(const Regex&, const char*, int);
+ SubString _substr(int, int);
+
+public:
+
+// constructors & assignment
+
+ String();
+ String(const String& x);
+ String(const SubString& x);
+ String(const char* t);
+ String(const char* t, int len);
+ String(char c);
+
+ ~String();
+
+ void operator = (const String& y);
+ void operator = (const char* y);
+ void operator = (char c);
+ void operator = (const SubString& y);
+
+// concatenation
+
+ void operator += (const String& y);
+ void operator += (const SubString& y);
+ void operator += (const char* t);
+ void operator += (char c);
+
+ void prepend(const String& y);
+ void prepend(const SubString& y);
+ void prepend(const char* t);
+ void prepend(char c);
+
+
+// procedural versions:
+// concatenate first 2 args, store result in last arg
+
+ friend void cat(const String&, const String&, String&);
+ friend void cat(const String&, const SubString&, String&);
+ friend void cat(const String&, const char*, String&);
+ friend void cat(const String&, char, String&);
+
+ friend void cat(const SubString&, const String&, String&);
+ friend void cat(const SubString&, const SubString&, String&);
+ friend void cat(const SubString&, const char*, String&);
+ friend void cat(const SubString&, char, String&);
+
+ friend void cat(const char*, const String&, String&);
+ friend void cat(const char*, const SubString&, String&);
+ friend void cat(const char*, const char*, String&);
+ friend void cat(const char*, char, String&);
+
+// double concatenation, by request. (yes, there are too many versions,
+// but if one is supported, then the others should be too...)
+// Concatenate first 3 args, store in last arg
+
+ friend void cat(const String&,const String&, const String&,String&);
+ friend void cat(const String&,const String&,const SubString&,String&);
+ friend void cat(const String&,const String&, const char*, String&);
+ friend void cat(const String&,const String&, char, String&);
+ friend void cat(const String&,const SubString&,const String&,String&);
+ friend void cat(const String&,const SubString&,const SubString&,String&);
+ friend void cat(const String&,const SubString&, const char*, String&);
+ friend void cat(const String&,const SubString&, char, String&);
+ friend void cat(const String&,const char*, const String&, String&);
+ friend void cat(const String&,const char*, const SubString&, String&);
+ friend void cat(const String&,const char*, const char*, String&);
+ friend void cat(const String&,const char*, char, String&);
+
+ friend void cat(const char*, const String&, const String&,String&);
+ friend void cat(const char*,const String&,const SubString&,String&);
+ friend void cat(const char*,const String&, const char*, String&);
+ friend void cat(const char*,const String&, char, String&);
+ friend void cat(const char*,const SubString&,const String&,String&);
+ friend void cat(const char*,const SubString&,const SubString&,String&);
+ friend void cat(const char*,const SubString&, const char*, String&);
+ friend void cat(const char*,const SubString&, char, String&);
+ friend void cat(const char*,const char*, const String&, String&);
+ friend void cat(const char*,const char*, const SubString&, String&);
+ friend void cat(const char*,const char*, const char*, String&);
+ friend void cat(const char*,const char*, char, String&);
+
+
+// searching & matching
+
+// return position of target in string or -1 for failure
+
+ int index(char c, int startpos = 0) const;
+ int index(const String& y, int startpos = 0) const;
+ int index(const SubString& y, int startpos = 0) const;
+ int index(const char* t, int startpos = 0) const;
+ int index(const Regex& r, int startpos = 0) const;
+
+// return 1 if target appears anyhere in String; else 0
+
+ int contains(char c) const;
+ int contains(const String& y) const;
+ int contains(const SubString& y) const;
+ int contains(const char* t) const;
+ int contains(const Regex& r) const;
+
+// return 1 if target appears anywhere after position pos
+// (or before, if pos is negative) in String; else 0
+
+ int contains(char c, int pos) const;
+ int contains(const String& y, int pos) const;
+ int contains(const SubString& y, int pos) const;
+ int contains(const char* t, int pos) const;
+ int contains(const Regex& r, int pos) const;
+
+// return 1 if target appears at position pos in String; else 0
+
+ int matches(char c, int pos = 0) const;
+ int matches(const String& y, int pos = 0) const;
+ int matches(const SubString& y, int pos = 0) const;
+ int matches(const char* t, int pos = 0) const;
+ int matches(const Regex& r, int pos = 0) const;
+
+// return number of occurences of target in String
+
+ int freq(char c) const;
+ int freq(const String& y) const;
+ int freq(const SubString& y) const;
+ int freq(const char* t) const;
+
+// SubString extraction
+
+// Note that you can't take a substring of a const String, since
+// this leaves open the possiblility of indirectly modifying the
+// String through the SubString
+
+ SubString at(int pos, int len);
+ SubString operator () (int pos, int len); // synonym for at
+
+ SubString at(const String& x, int startpos = 0);
+ SubString at(const SubString& x, int startpos = 0);
+ SubString at(const char* t, int startpos = 0);
+ SubString at(char c, int startpos = 0);
+ SubString at(const Regex& r, int startpos = 0);
+
+ SubString before(int pos);
+ SubString before(const String& x, int startpos = 0);
+ SubString before(const SubString& x, int startpos = 0);
+ SubString before(const char* t, int startpos = 0);
+ SubString before(char c, int startpos = 0);
+ SubString before(const Regex& r, int startpos = 0);
+
+ SubString through(int pos);
+ SubString through(const String& x, int startpos = 0);
+ SubString through(const SubString& x, int startpos = 0);
+ SubString through(const char* t, int startpos = 0);
+ SubString through(char c, int startpos = 0);
+ SubString through(const Regex& r, int startpos = 0);
+
+ SubString from(int pos);
+ SubString from(const String& x, int startpos = 0);
+ SubString from(const SubString& x, int startpos = 0);
+ SubString from(const char* t, int startpos = 0);
+ SubString from(char c, int startpos = 0);
+ SubString from(const Regex& r, int startpos = 0);
+
+ SubString after(int pos);
+ SubString after(const String& x, int startpos = 0);
+ SubString after(const SubString& x, int startpos = 0);
+ SubString after(const char* t, int startpos = 0);
+ SubString after(char c, int startpos = 0);
+ SubString after(const Regex& r, int startpos = 0);
+
+
+// deletion
+
+// delete len chars starting at pos
+ void del(int pos, int len);
+
+// delete the first occurrence of target after startpos
+
+ void del(const String& y, int startpos = 0);
+ void del(const SubString& y, int startpos = 0);
+ void del(const char* t, int startpos = 0);
+ void del(char c, int startpos = 0);
+ void del(const Regex& r, int startpos = 0);
+
+// global substitution: substitute all occurrences of pat with repl
+
+ int gsub(const String& pat, const String& repl);
+ int gsub(const SubString& pat, const String& repl);
+ int gsub(const char* pat, const String& repl);
+ int gsub(const char* pat, const char* repl);
+ int gsub(const Regex& pat, const String& repl);
+
+// friends & utilities
+
+// split string into array res at separators; return number of elements
+
+ friend int split(const String& x, String res[], int maxn,
+ const String& sep);
+ friend int split(const String& x, String res[], int maxn,
+ const Regex& sep);
+
+ friend String common_prefix(const String& x, const String& y,
+ int startpos = 0);
+ friend String common_suffix(const String& x, const String& y,
+ int startpos = -1);
+ friend String replicate(char c, int n);
+ friend String replicate(const String& y, int n);
+ friend String join(String src[], int n, const String& sep);
+
+// simple builtin transformations
+
+ friend String reverse(const String& x);
+ friend String upcase(const String& x);
+ friend String downcase(const String& x);
+ friend String capitalize(const String& x);
+
+// in-place versions of above
+
+ void reverse();
+ void upcase();
+ void downcase();
+ void capitalize();
+
+// element extraction
+
+ char& operator [] (int i);
+ char elem(int i) const;
+ char firstchar() const;
+ char lastchar() const;
+
+// conversion
+
+ operator const char*() const;
+ const char* chars() const;
+
+
+// IO
+
+ friend ostream& operator<<(ostream& s, const String& x);
+ friend ostream& operator<<(ostream& s, const SubString& x);
+ friend istream& operator>>(istream& s, String& x);
+
+ friend int readline(istream& s, String& x,
+ char terminator = '\n',
+ int discard_terminator = 1);
+
+// status
+
+ int length() const;
+ int empty() const;
+
+// preallocate some space for String
+ void alloc(int newsize);
+
+// report current allocation (not length!)
+
+ int allocation() const;
+
+
+ volatile void error(const char* msg) const;
+
+ int OK() const;
+};
+
+typedef String StrTmp; // for backward compatibility
+
+// other externs
+
+int compare(const String& x, const String& y);
+int compare(const String& x, const SubString& y);
+int compare(const String& x, const char* y);
+int compare(const SubString& x, const String& y);
+int compare(const SubString& x, const SubString& y);
+int compare(const SubString& x, const char* y);
+int fcompare(const String& x, const String& y); // ignore case
+
+extern StrRep _nilStrRep;
+extern String _nilString;
+
+// other inlines
+
+String operator + (const String& x, const String& y);
+String operator + (const String& x, const SubString& y);
+String operator + (const String& x, const char* y);
+String operator + (const String& x, char y);
+String operator + (const SubString& x, const String& y);
+String operator + (const SubString& x, const SubString& y);
+String operator + (const SubString& x, const char* y);
+String operator + (const SubString& x, char y);
+String operator + (const char* x, const String& y);
+String operator + (const char* x, const SubString& y);
+
+int operator==(const String& x, const String& y);
+int operator!=(const String& x, const String& y);
+int operator> (const String& x, const String& y);
+int operator>=(const String& x, const String& y);
+int operator< (const String& x, const String& y);
+int operator<=(const String& x, const String& y);
+int operator==(const String& x, const SubString& y);
+int operator!=(const String& x, const SubString& y);
+int operator> (const String& x, const SubString& y);
+int operator>=(const String& x, const SubString& y);
+int operator< (const String& x, const SubString& y);
+int operator<=(const String& x, const SubString& y);
+int operator==(const String& x, const char* t);
+int operator!=(const String& x, const char* t);
+int operator> (const String& x, const char* t);
+int operator>=(const String& x, const char* t);
+int operator< (const String& x, const char* t);
+int operator<=(const String& x, const char* t);
+int operator==(const SubString& x, const String& y);
+int operator!=(const SubString& x, const String& y);
+int operator> (const SubString& x, const String& y);
+int operator>=(const SubString& x, const String& y);
+int operator< (const SubString& x, const String& y);
+int operator<=(const SubString& x, const String& y);
+int operator==(const SubString& x, const SubString& y);
+int operator!=(const SubString& x, const SubString& y);
+int operator> (const SubString& x, const SubString& y);
+int operator>=(const SubString& x, const SubString& y);
+int operator< (const SubString& x, const SubString& y);
+int operator<=(const SubString& x, const SubString& y);
+int operator==(const SubString& x, const char* t);
+int operator!=(const SubString& x, const char* t);
+int operator> (const SubString& x, const char* t);
+int operator>=(const SubString& x, const char* t);
+int operator< (const SubString& x, const char* t);
+int operator<=(const SubString& x, const char* t);
+
+#if defined(__OPTIMIZE__) || defined(USE_LIBGXX_INLINES)
+
+
+// status reports, needed before defining other things
+
+inline int String::length() const { return rep->len; }
+inline int String::empty() const { return rep->len == 0; }
+inline const char* String::chars() const { return &(rep->s[0]); }
+inline int String::allocation() const { return rep->sz; }
+inline void String::alloc(int newsize) { rep = Sresize(rep, newsize); }
+
+inline int SubString::length() const { return len; }
+inline int SubString::empty() const { return len == 0; }
+inline const char* SubString::chars() const { return &(S.rep->s[pos]); }
+
+
+// constructors
+
+inline String::String()
+ : rep(&_nilStrRep) {}
+inline String::String(const String& x)
+ : rep(Scopy(0, x.rep)) {}
+inline String::String(const char* t)
+ : rep(Salloc(0, t, -1, -1)) {}
+inline String::String(const char* t, int tlen)
+ : rep(Salloc(0, t, tlen, tlen)) {}
+inline String::String(const SubString& y)
+ : rep(Salloc(0, y.chars(), y.length(), y.length())) {}
+inline String::String(char c)
+ : rep(Salloc(0, &c, 1, 1)) {}
+
+inline String::~String() { if (rep != &_nilStrRep) delete rep; }
+
+inline SubString::SubString(const SubString& x)
+ :S(x.S), pos(x.pos), len(x.len) {}
+inline SubString::SubString(String& x, int first, int l)
+ :S(x), pos(first), len(l) {}
+
+inline SubString::~SubString() {}
+
+// assignment
+
+inline void String::operator = (const String& y)
+{
+ rep = Scopy(rep, y.rep);
+}
+
+inline void String::operator=(const char* t)
+{
+ rep = Salloc(rep, t, -1, -1);
+}
+
+inline void String::operator=(const SubString& y)
+{
+ rep = Salloc(rep, y.chars(), y.length(), y.length());
+}
+
+inline void String::operator=(char c)
+{
+ rep = Salloc(rep, &c, 1, 1);
+}
+
+
+inline void SubString::operator = (const char* ys)
+{
+ assign(0, ys);
+}
+
+inline void SubString::operator = (char ch)
+{
+ assign(0, &ch, 1);
+}
+
+inline void SubString::operator = (const String& y)
+{
+ assign(y.rep, y.chars(), y.length());
+}
+
+inline void SubString::operator = (const SubString& y)
+{
+ assign(y.S.rep, y.chars(), y.length());
+}
+
+// Zillions of cats...
+
+inline void cat(const String& x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const String& x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const String& x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), y, -1);
+}
+
+inline void cat(const String& x, char y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), &y, 1);
+}
+
+inline void cat(const SubString& x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const SubString& x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const SubString& x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), y, -1);
+}
+
+inline void cat(const SubString& x, char y, String& r)
+{
+ r.rep = Scat(r.rep, x.chars(), x.length(), &y, 1);
+}
+
+inline void cat(const char* x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, x, -1, y.chars(), y.length());
+}
+
+inline void cat(const char* x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, x, -1, y.chars(), y.length());
+}
+
+inline void cat(const char* x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, x, -1, y, -1);
+}
+
+inline void cat(const char* x, char y, String& r)
+{
+ r.rep = Scat(r.rep, x, -1, &y, 1);
+}
+
+inline void cat(const String& a, const String& x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const String& a, const String& x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const String& a, const String& x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), y, -1);
+}
+
+inline void cat(const String& a, const String& x, char y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), &y, 1);
+}
+
+inline void cat(const String& a, const SubString& x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const String& a, const SubString& x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const String& a, const SubString& x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), y, -1);
+}
+
+inline void cat(const String& a, const SubString& x, char y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x.chars(), x.length(), &y, 1);
+}
+
+inline void cat(const String& a, const char* x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x, -1, y.chars(), y.length());
+}
+
+inline void cat(const String& a, const char* x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x, -1, y.chars(), y.length());
+}
+
+inline void cat(const String& a, const char* x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x, -1, y, -1);
+}
+
+inline void cat(const String& a, const char* x, char y, String& r)
+{
+ r.rep = Scat(r.rep, a.chars(), a.length(), x, -1, &y, 1);
+}
+
+
+inline void cat(const char* a, const String& x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const char* a, const String& x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const char* a, const String& x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), y, -1);
+}
+
+inline void cat(const char* a, const String& x, char y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), &y, 1);
+}
+
+inline void cat(const char* a, const SubString& x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const char* a, const SubString& x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), y.chars(), y.length());
+}
+
+inline void cat(const char* a, const SubString& x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), y, -1);
+}
+
+inline void cat(const char* a, const SubString& x, char y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x.chars(), x.length(), &y, 1);
+}
+
+inline void cat(const char* a, const char* x, const String& y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x, -1, y.chars(), y.length());
+}
+
+inline void cat(const char* a, const char* x, const SubString& y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x, -1, y.chars(), y.length());
+}
+
+inline void cat(const char* a, const char* x, const char* y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x, -1, y, -1);
+}
+
+inline void cat(const char* a, const char* x, char y, String& r)
+{
+ r.rep = Scat(r.rep, a, -1, x, -1, &y, 1);
+}
+
+
+// operator versions
+
+inline void String::operator +=(const String& y)
+{
+ cat(*this, y, *this);
+}
+
+inline void String::operator +=(const SubString& y)
+{
+ cat(*this, y, *this);
+}
+
+inline void String::operator += (const char* y)
+{
+ cat(*this, y, *this);
+}
+
+inline void String:: operator +=(char y)
+{
+ cat(*this, y, *this);
+}
+
+// constructive concatenation
+
+#if defined(__GNUG__) && !defined(NO_NRV)
+
+inline String operator + (const String& x, const String& y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const String& x, const SubString& y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const String& x, const char* y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const String& x, char y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const SubString& x, const String& y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const SubString& x, const SubString& y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const SubString& x, const char* y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const SubString& x, char y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const char* x, const String& y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String operator + (const char* x, const SubString& y) return r;
+{
+ cat(x, y, r);
+}
+
+inline String reverse(const String& x) return r;
+{
+ r.rep = Sreverse(x.rep, r.rep);
+}
+
+inline String upcase(const String& x) return r;
+{
+ r.rep = Supcase(x.rep, r.rep);
+}
+
+inline String downcase(const String& x) return r;
+{
+ r.rep = Sdowncase(x.rep, r.rep);
+}
+
+inline String capitalize(const String& x) return r;
+{
+ r.rep = Scapitalize(x.rep, r.rep);
+}
+
+#else /* NO_NRV */
+
+inline String operator + (const String& x, const String& y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const String& x, const SubString& y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const String& x, const char* y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const String& x, char y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const SubString& x, const String& y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const SubString& x, const SubString& y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const SubString& x, const char* y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const SubString& x, char y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const char* x, const String& y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String operator + (const char* x, const SubString& y)
+{
+ String r; cat(x, y, r); return r;
+}
+
+inline String reverse(const String& x)
+{
+ String r; r.rep = Sreverse(x.rep, r.rep); return r;
+}
+
+inline String upcase(const String& x)
+{
+ String r; r.rep = Supcase(x.rep, r.rep); return r;
+}
+
+inline String downcase(const String& x)
+{
+ String r; r.rep = Sdowncase(x.rep, r.rep); return r;
+}
+
+inline String capitalize(const String& x)
+{
+ String r; r.rep = Scapitalize(x.rep, r.rep); return r;
+}
+
+#endif
+
+// prepend
+
+inline void String::prepend(const String& y)
+{
+ rep = Sprepend(rep, y.chars(), y.length());
+}
+
+inline void String::prepend(const char* y)
+{
+ rep = Sprepend(rep, y, -1);
+}
+
+inline void String::prepend(char y)
+{
+ rep = Sprepend(rep, &y, 1);
+}
+
+inline void String::prepend(const SubString& y)
+{
+ rep = Sprepend(rep, y.chars(), y.length());
+}
+
+// misc transformations
+
+
+inline void String::reverse()
+{
+ rep = Sreverse(rep, rep);
+}
+
+
+inline void String::upcase()
+{
+ rep = Supcase(rep, rep);
+}
+
+
+inline void String::downcase()
+{
+ rep = Sdowncase(rep, rep);
+}
+
+
+inline void String::capitalize()
+{
+ rep = Scapitalize(rep, rep);
+}
+
+// element extraction
+
+inline char& String::operator [] (int i)
+{
+ if (((unsigned)i) >= length()) error("invalid index");
+ return rep->s[i];
+}
+
+inline char String::elem (int i) const
+{
+ if (((unsigned)i) >= length()) error("invalid index");
+ return rep->s[i];
+}
+
+inline char String::firstchar() const
+{
+ return elem(0);
+}
+
+inline char String::lastchar() const
+{
+ return elem(length() - 1);
+}
+
+// searching
+
+inline int String::index(char c, int startpos) const
+{
+ return search(startpos, length(), c);
+}
+
+inline int String::index(const char* t, int startpos) const
+{
+ return search(startpos, length(), t);
+}
+
+inline int String::index(const String& y, int startpos) const
+{
+ return search(startpos, length(), y.chars(), y.length());
+}
+
+inline int String::index(const SubString& y, int startpos) const
+{
+ return search(startpos, length(), y.chars(), y.length());
+}
+
+inline int String::index(const Regex& r, int startpos) const
+{
+ int unused; return r.search(chars(), length(), unused, startpos);
+}
+
+inline int String::contains(char c) const
+{
+ return search(0, length(), c) >= 0;
+}
+
+inline int String::contains(const char* t) const
+{
+ return search(0, length(), t) >= 0;
+}
+
+inline int String::contains(const String& y) const
+{
+ return search(0, length(), y.chars(), y.length()) >= 0;
+}
+
+inline int String::contains(const SubString& y) const
+{
+ return search(0, length(), y.chars(), y.length()) >= 0;
+}
+
+inline int String::contains(char c, int p) const
+{
+ return match(p, length(), 0, &c, 1) >= 0;
+}
+
+inline int String::contains(const char* t, int p) const
+{
+ return match(p, length(), 0, t) >= 0;
+}
+
+inline int String::contains(const String& y, int p) const
+{
+ return match(p, length(), 0, y.chars(), y.length()) >= 0;
+}
+
+inline int String::contains(const SubString& y, int p) const
+{
+ return match(p, length(), 0, y.chars(), y.length()) >= 0;
+}
+
+inline int String::contains(const Regex& r) const
+{
+ int unused; return r.search(chars(), length(), unused, 0) >= 0;
+}
+
+inline int String::contains(const Regex& r, int p) const
+{
+ return r.match(chars(), length(), p) >= 0;
+}
+
+
+inline int String::matches(const SubString& y, int p) const
+{
+ return match(p, length(), 1, y.chars(), y.length()) >= 0;
+}
+
+inline int String::matches(const String& y, int p) const
+{
+ return match(p, length(), 1, y.chars(), y.length()) >= 0;
+}
+
+inline int String::matches(const char* t, int p) const
+{
+ return match(p, length(), 1, t) >= 0;
+}
+
+inline int String::matches(char c, int p) const
+{
+ return match(p, length(), 1, &c, 1) >= 0;
+}
+
+inline int String::matches(const Regex& r, int p) const
+{
+ int l = (p < 0)? -p : length() - p;
+ return r.match(chars(), length(), p) == l;
+}
+
+
+inline int SubString::contains(const char* t) const
+{
+ return S.search(pos, pos+len, t) >= 0;
+}
+
+inline int SubString::contains(const String& y) const
+{
+ return S.search(pos, pos+len, y.chars(), y.length()) >= 0;
+}
+
+inline int SubString::contains(const SubString& y) const
+{
+ return S.search(pos, pos+len, y.chars(), y.length()) >= 0;
+}
+
+inline int SubString::contains(char c) const
+{
+ return S.search(pos, pos+len, 0, c) >= 0;
+}
+
+inline int SubString::contains(const Regex& r) const
+{
+ int unused; return r.search(chars(), len, unused, 0) >= 0;
+}
+
+inline int SubString::matches(const Regex& r) const
+{
+ return r.match(chars(), len, 0) == len;
+}
+
+
+inline int String::gsub(const String& pat, const String& r)
+{
+ return _gsub(pat.chars(), pat.length(), r.chars(), r.length());
+}
+
+inline int String::gsub(const SubString& pat, const String& r)
+{
+ return _gsub(pat.chars(), pat.length(), r.chars(), r.length());
+}
+
+inline int String::gsub(const Regex& pat, const String& r)
+{
+ return _gsub(pat, r.chars(), r.length());
+}
+
+inline int String::gsub(const char* pat, const String& r)
+{
+ return _gsub(pat, -1, r.chars(), r.length());
+}
+
+inline int String::gsub(const char* pat, const char* r)
+{
+ return _gsub(pat, -1, r, -1);
+}
+
+
+inline String::operator const char*() const
+{
+ return str(chars());
+}
+
+inline ostream& operator<<(ostream& s, const String& x)
+{
+#ifdef VMS
+ s << x.chars(); return s;
+#else
+ s.put(x.chars()); return s;
+#endif
+
+}
+
+// a zillion comparison operators
+
+inline int operator==(const String& x, const String& y)
+{
+ return compare(x, y) == 0;
+}
+
+inline int operator!=(const String& x, const String& y)
+{
+ return compare(x, y) != 0;
+}
+
+inline int operator>(const String& x, const String& y)
+{
+ return compare(x, y) > 0;
+}
+
+inline int operator>=(const String& x, const String& y)
+{
+ return compare(x, y) >= 0;
+}
+
+inline int operator<(const String& x, const String& y)
+{
+ return compare(x, y) < 0;
+}
+
+inline int operator<=(const String& x, const String& y)
+{
+ return compare(x, y) <= 0;
+}
+
+inline int operator==(const String& x, const SubString& y)
+{
+ return compare(x, y) == 0;
+}
+
+inline int operator!=(const String& x, const SubString& y)
+{
+ return compare(x, y) != 0;
+}
+
+inline int operator>(const String& x, const SubString& y)
+{
+ return compare(x, y) > 0;
+}
+
+inline int operator>=(const String& x, const SubString& y)
+{
+ return compare(x, y) >= 0;
+}
+
+inline int operator<(const String& x, const SubString& y)
+{
+ return compare(x, y) < 0;
+}
+
+inline int operator<=(const String& x, const SubString& y)
+{
+ return compare(x, y) <= 0;
+}
+
+inline int operator==(const String& x, const char* t)
+{
+ return compare(x, t) == 0;
+}
+
+inline int operator!=(const String& x, const char* t)
+{
+ return compare(x, t) != 0;
+}
+
+inline int operator>(const String& x, const char* t)
+{
+ return compare(x, t) > 0;
+}
+
+inline int operator>=(const String& x, const char* t)
+{
+ return compare(x, t) >= 0;
+}
+
+inline int operator<(const String& x, const char* t)
+{
+ return compare(x, t) < 0;
+}
+
+inline int operator<=(const String& x, const char* t)
+{
+ return compare(x, t) <= 0;
+}
+
+inline int operator==(const SubString& x, const String& y)
+{
+ return compare(y, x) == 0;
+}
+
+inline int operator!=(const SubString& x, const String& y)
+{
+ return compare(y, x) != 0;
+}
+
+inline int operator>(const SubString& x, const String& y)
+{
+ return compare(y, x) < 0;
+}
+
+inline int operator>=(const SubString& x, const String& y)
+{
+ return compare(y, x) <= 0;
+}
+
+inline int operator<(const SubString& x, const String& y)
+{
+ return compare(y, x) > 0;
+}
+
+inline int operator<=(const SubString& x, const String& y)
+{
+ return compare(y, x) >= 0;
+}
+
+inline int operator==(const SubString& x, const SubString& y)
+{
+ return compare(x, y) == 0;
+}
+
+inline int operator!=(const SubString& x, const SubString& y)
+{
+ return compare(x, y) != 0;
+}
+
+inline int operator>(const SubString& x, const SubString& y)
+{
+ return compare(x, y) > 0;
+}
+
+inline int operator>=(const SubString& x, const SubString& y)
+{
+ return compare(x, y) >= 0;
+}
+
+inline int operator<(const SubString& x, const SubString& y)
+{
+ return compare(x, y) < 0;
+}
+
+inline int operator<=(const SubString& x, const SubString& y)
+{
+ return compare(x, y) <= 0;
+}
+
+inline int operator==(const SubString& x, const char* t)
+{
+ return compare(x, t) == 0;
+}
+
+inline int operator!=(const SubString& x, const char* t)
+{
+ return compare(x, t) != 0;
+}
+
+inline int operator>(const SubString& x, const char* t)
+{
+ return compare(x, t) > 0;
+}
+
+inline int operator>=(const SubString& x, const char* t)
+{
+ return compare(x, t) >= 0;
+}
+
+inline int operator<(const SubString& x, const char* t)
+{
+ return compare(x, t) < 0;
+}
+
+inline int operator<=(const SubString& x, const char* t)
+{
+ return compare(x, t) <= 0;
+}
+
+
+// a helper needed by at, before, etc.
+
+inline SubString String::_substr(int first, int l)
+{
+ if (first < 0 || (unsigned)(first + l) > length())
+ return SubString(_nilString, 0, 0) ;
+ else
+ return SubString(*this, first, l);
+}
+
+
+#endif
+
+#endif