Category : C++ Source Code
Archive   : WHEATLIB.ZIP
Filename : STRINGS.DOC

 
Output of file : STRINGS.DOC contained in archive : WHEATLIB.ZIP

Wheaton Strings library documentation

October 10, 1989
February 20, 1991 (minor update)
May 15, 1992 (minor update)
October 20, 1992 (minor update)

Copyright (c) 1992 by Paul Wheaton

The Wheaton Strings Library is public domain in the hopes that
the hundreds of vendors that are creating their own string
libraries can go with just one - I'm pretty tired of getting a
library in that seems like it will be pretty cool, just to find
out that it uses the same identifiers.

For those programmers that never read documentation but have
mysteriously made it this far, just look quickly at section 1.1.4 and
5.1. To make these libraries available, you need to include
link with WSTR.LIB, MISC.LIB and FATAL.OBJ.

This Strings library, consisting of one class and a few independent
functions, provides an easier, more intuitive way to manipulate
strings. By including this stuff into your programs you can use (or
create!) functions that do not need chunks of memory pre-allocated for
them. Concatenation is done with "+" or "+=" instead of "strcat".
Comparison is done with "==", "!=", "<", etc. instead of "strcmp".
Source ends up being more readable, and less verbose. Many common
string manipulation errors are completely eliminated. For programmers
new to "C", these libraries provide more functionality with fewer
operators to memorize, thus reducing the dreaded learning curve.

Strings are automatically converted from type String to char* and back
as needed. The two types can often be mixed to give the same results.


Strings
1 Advantages over C
1.1 for programmers new to C
1.1.1 less to memorize
1.1.2 more intuitive
1.1.3 similar to other languages
1.1.4 faster to learn
1.2 for old C programmers
1.2.1 less to type
1.2.2 less worry about low level stuff: concentrate more on program
1.2.3 more readable
1.2.4 eliminate overflow errors
1.2.5 faster executable
length does not need to be calculated
1.2.6 use less memory
don't need to allocate memory to cover "worst case"
1.2.7 functions that are more independent (don't need storage space)
2 Disadvantages from C
2.1 speed overhead
allocating memory in the heap at creation and appending
2.2 storage overhead
storing length and extra pointers
3 A little bit about how this works
4 Implementing this with char* for optimal performance
5 Functions
5.1 String class member functions
5.1.1 declaring a String
5.1.1.1 based on a given string constant or char*
5.1.1.2 based on a character
5.1.1.3 based on another String
5.1.1.4 without initialization
5.1.1.5 extra allocation
5.1.2 Length() or Size()
5.1.3 + (concatenation)
5.1.4 += (appending form of concatenation)
5.1.5 = (assignment) and conversions
5.1.6 ==,!=,<,>,<=,>= (comparison)
5.1.7 () or At() (retrieving substrings)
5.1.7.1 Before(), Through(), From() and After()
5.1.8 [] (String char reference)
5.1.9 Left(), Right(), Center(), Just() (justification)
5.1.10 Capacity() (report current allocation)
5.1.11 ReAlloc() (change capacity)
5.1.12 ToLower() (force all upper case letters to lower case)
5.1.13 ToUpper() (force all lower case letters to upper case)
5.1.14 Index() (find the index of a char)
5.1.15 Insert() (insert a char or a sting into the string)
5.1.16 Delete() (delete characters from the string)
5.2 non-member functions
5.2.1 Str() (convert integers to String)
5.2.2 Form() (convert reals to a String using a format)
5.2.3 StringOf() (return a string of chars)
5.2.4 Spaces() (return a String of a certain number of spaces)
5.2.5 LeftText(), RightText(), CenterText(), JustText()



1 Advantages over C

I hope to show that using these String libraries in C++ is a great deal
easier than using the ANSI C string libraries or any string library that
could possibly be written in C. It is my opinion that productivity in
string manipulation development will increase by a factor of four for
those application programmers that use this library.

1.1 for programmers new to C

Any time that you move to a new language there will be a learning curve.
C is notorious for being too terse and, thus, hard to read and tougher to
learn. Much of this has to do with being a "mid level language": Easier
to work with than assembly yet harder than "high level languages" such as
Pascal or FORTRAN. C gains you a great deal of portability and runtime
effeciency over most "high level languages". C++ with a healthy set of
libraries provides all of the advantages of C coupled with the advantages
of a high level language. This library should make string manipulation
easier than not only C, but FORTRAN, Pascal, BASIC, LISP or Modula-2. A
programmer new to this library will probably find all of the string
manipulation features that they appreciated most in their favorite
languages and then some new twists that will make their programming lives
even easier.

1.1.1 less to memorize

C++ cures some of the idiosyncrasies of C that directly effect
string manipulation libraries, one of the worst being the pointer to
a character concept. In order for a programmer to keep from getting
into trouble when manipulating strings in C, they must memorize how
the compiler handles them (the strings): C Strings are an array of
characters terminated by a null character; strings are referenced by
a pointer to the first element of the string; runtime range checking
is not standard and is performed with library routines when the size
of the string is passed.

In this library, how the String is actually stored and manipulated
is hidden from the applications programmer. Runtime range checking
is performed by the library so the applications programmer can
concentrate on their application rather than monitor the size of
their strings and make sure everything will fit. Since string
manipulation using this library is similar to working with numbers
in C or C++, all of the exceptions for plain C string handling never
have to be learned.

1.1.2 more intuitive

ANSI C maintains a great deal of exceptions when it comes to string
handling. For example, if you have two strings, S1 and S2,
assignment of one from the other does not result in two identical
copies of the string, it results in two pointers pointing to the
same string: Modifying one effects the other. Generally, when an
assignment is made such as X=Y, the contents of X are separate from
Y yet the same. This library supports the more intuitive assignment
operation as well as other operators and functions that any string
library *ought* to have.

1.1.3 similar to other languages

Of course, all of the functions and operators available in C are
also available in C++. Many of them (C functions) will work with
the String type as well as good ole char*.

In Turbo Pascal

Var S1,S2:String;
Begin
S1:="oatmeal";
S2:="I like "+S1+".";
End;

In BASIC

550 S1$="oatmeal"
560 S2$="I like "+S1$+"."

In FORTRAN

char S1*8
char S2*16
S1='oatmeal'
S2='I like ' // S1 // '.'

In C (or C++ without this library)

char* S1="oatmeal";
char S2[16];
strcpy(S2,"I like ");
strcat(S2,S1);
strcat(S2,".");

or...

char* S1="oatmeal";
char S2[16];
sprintf(S2,"I like %s.",S1);

With this library...

String S1="oatmeal";
String S2="I like "+S1+".";

As I hope you can see, this library's operators and functions
provide a string manipulation library that implements the best and
most common parts of other languages. You should find that using
this library with C++ is a great deal simpler, more readable and
more powerful than what you were using before.

1.1.4 faster to learn

Given the aforementioned points, it ought to be clear that learning
how to use this library will take a small fraction of the time it
would take to learn ANSI C string manipulation. For most
applications all you need to know is that "String" is the
constructor, "=" is assignment and "+" is concatenation. Also,
anything that *seems* like it should work, probably will; if it
*seems* like there should be a function to handle a certain case,
there probably is.

1.2 for old C programmers

Don't fret! This library is completely compatible with the old
char* stuff. You only need to use it when it's convenient to you.
After a while, I hope that you'll use it 99% of the time (yes there
are a few times when using char* could save some execution time or
storage space). For the most part, I think you'll find that this
stuff cuts your development time to a third (maybe a quarter!) of
what it used to be in string manipulation.

1.2.1 less to type

Since C++ allows access to define operators, then the ANSI functions
to do string comparisons and the like can be circumvented for the
more convenient notations.

Notation for assignment

in C : strncpy(S1,S2,sizeof(S1));
in C++: S1=S2;

Concatenation

in C : strncat(S1,strncat(S2,S3,sizeof(S2)),sizeof(S1));
or : sprintf(S1,"%s%s%s",S1,S2,S3);
in C++: S1+=S2+S3;

Comparison

in C : strcmp(S1,S2)<0
in C++: S1
1.2.2 less worry about low level stuff: concentrate more on program

Without this library there is the frequent need of application programmer
range checking: Making sure that arrays are declared of sufficient size;
indexing is within bounds; using the appropriate function/operator on the
appropriate structure (such as sizeof on char* vs. char[x]).

With this library, nearly all of these problems are eliminated.
Being a higher level set of functions and operators, the
applications programmer spends a great deal less time worrying about
how the strings are stored and maintained and is given more time to
solving the problem at hand.

Expanding an earlier example:

(Example 1.2.2)

The purpose here is to assign a string to all three strings and then
concatenate them all together, storing the result in the first
string.

ANSI C, style 1

1 | char S1[18];
2 | char S2[13];
3 | char* S3=" mice.";
4 | strcpy(S1,"Three");
5 | strcpy(S2," blind");
6 | strncat(S1,strncat(S2,S3,sizeof(S2)),sizeof(S1));

ANSI C, style 2

11 | char S1[18];
12 | char* S2=" blind";
13 | char* S3=" mice.";
14 | strcpy(S1,"Three");
15 | sprintf(S1,"%s%s%s",S1,S2,S3);

C++ with Strings library

21 | String S1="Three";
22 | String S2=" blind";
23 | String S3=" mice.";
24 | S1+=S2+S3;

Note that in lines 1 and 2, the applications programmer needed to
decide whether char* or char[x] could be used and, if the latter,
how much storage was going to be needed. In style 1, S2 needed to
be defined as an array because part of the concatenation process was
going to involve storing a concatenated result in S2. There were
ways to avoid this while still avoiding the use of sprintf such as
concatenating S1 to S2 and then S1 to S3. On those lines where
"char* S=" was used, "static char S[]=" could have been used. Also,
the programmer could choose to use strcat instead of strncat and
thus avoid the use of sizeof, but if they modified some code, they
may forget to expand their arrays and overwrite memory. On the other
hand, sometimes when a programmer types in one of these function
calls they insert the wrong variable into sizeof and the problems
may not show up till years later. In style 2, not only is there the
same allocation problem for S1, but there is also the issue of
memorizing the use of sprintf: The parameter order and the effects
of special characters in the form string. Also, modifications beg
for runtime crashes: If another string is needed and specified in
the form string as "%s%s%s%s" yet the new parameter is not added,
this can result in many, less than predictable results. These are
all things that the programmer must always consider when
manipulating strings in C.

In C++, using this library, the applications programmer has no *need*
to worry about the declaration size of a string: Resizing is done
dynamically. Any sort of modification can be made to this piece of
code as far as adding new strings and the like without having to be
sure to change the code somewhere else too.

1.2.3 more readable

Although readability is known in programming circles as a "religious
issue", I think many (if not all) programmers can agree that this
library is more readable than any library that can be created in
ANSI C.

Strings are treated a great deal more like other built-in (atomic)
types of C, such as numbers. Therefore they do not carry all of the
exceptions that ANSI C string structures (which are a combination of
two atomic types: the char and the pointer) do. Further, defining
the object as a String better clarifies the intent. "String S;" says
that S is a string, whereas "char* S;" says that S is a pointer to a
character which the programmer must know can be used to handle a
string or, more simply, as a pointer to a single char or an array of
chars that is not to be used as a string.

From example 1.2.2:

ANSI C, style 1, line 6
strncat(S1,strncat(S2,S3,sizeof(S2)),sizeof(S1));

ANSI C, style 2, line 15
sprintf(S1,"%s%s%s",S1,S2,S3);

C++ with Strings library, line 24
S1+=S2+S3;

Just comparing these three lines of code in size tells you that the
first two are going to take longer to read than the last just
because there are more characters (Their size, in characters, is 49,
30 and 10, respectively). In the first line, there are two function
calls (strncat), two operator calls (sizeof), two of the variables
are referenced twice and a whole mess of parentheses. In the second
line there are two references to S1 and the form string ("%s%s%s")
which, when debugging, needs to be compared to the following
parameters to be sure that there are the same number of parameters
as "%s"s. I think that the last line is about as plain and easy to
understand as it could get. What is happening is very quick to read
and easier to understand. There is no place in this line that a
conflicting error could occur (such as a sizeof on the wrong var in
the first line or a "%s" without a matching argument in the second).

1.2.4 eliminate overflow errors

An ANSI C string programming problem that is pretty hard to track
down is when a user feeds a program a string that is bigger than the
applications programmer expected to have that string ever hold. The
result is that data is written where other data is supposed to be
stored. This can lead to anything from some garbled data to a
system crash.

By using the "String" type of this library, this problem is avoided.
when an attempt is made to store more string than will fit into the
current allocation, more space is allocated and the string is stored
there.

1.2.5 faster executable

I have to admit that generally, this string stuff has a slight speed
overhead. However, there is at least one case where speed can
obviously be improved: The length of the string is always known and
does not need to be calculated.

A good example of where this pays off is in a loop where the
programmer wants to examine every character in a string.

In C:

char* S;
...
for(I=0;I ...

In C++ with this library

String S;
...
for(I=0;I ...

In the first example, the length of the string is re-calculated with
every pass through the loop whereas in the second example the string
length is retrieved from a value stored in memory. Of course, an
alert C programmer can repair the problem with the first example by
storing the length in a temporary variable before the loop is
executed.

Other than that, what would save execution time is fewer function
calls with shorter, fewer parameters.

1.2.6 use less memory

Again, don't misinterpret this: There's also a slight memory
overhead in most cases. The exceptions are that: Programmers don't
need to over allocate memory to cover "worst case"; fewer function
calls with fewer parameters make for less code space.

For example, say a string is passed to a function that can be any
size from 5 to 1005 and the first thing that needs to be done is to
make a local copy of that string. Also, the function is going to
modify the string such that it may grow and shrink within a range of
5 to 2005 chars. In C, the proper thing to do is to allocate a
chunk of memory that can hold 2005 characters. With this library
you just assign the given string to a new one and the new string
will automatically be the current size and as modifications are
made, it will grow as needed. If most calls to this function pass
strings of length 10 and have internal strings resulting in a length
of 15, then the C stuff will have wasted almost 2000 bytes of memory
while this library will be using just a few bytes over 15.

1.2.7 functions that are more independent (don't need storage space)

If you write a function that returns a string in ANSI C, then you
first need to receive a pointer to a place in memory where you can
store the resulting string. In C++ with this library, you can just
return a "String" object without first being passed a chunk of
memory. For example, say I want a function called Str, that when
passed an integer, would return a string. A possibility in C is
"char* Str(long Num, char* S)". When calling this function, the
programmer must allocate enough space to store the resulting string
and pass a pointer to this area via the second parameter. That same
pointer will be returned on exit. This is a lot of extra hassle for
the applications programmer. In C++ with this library you can have
"String Str(long Num)". The storage space is created dynamically
and the result is passed to whatever does the calling. The
applications programmer does not need to bother with preparing
storage space for the result.

2 Disadvantages from C

I think that 95% of the time, the advantages of using this library
far outweigh the disadvantages. Also, I think, 99% of the time,
the disadvantages are negligable, non-existent or compensated for.
Note that as a programmer becomes more familiar with this library,
there are ways to optimize a mix between this code and the
old char* stuff for better performance and space savings.

2.1 speed overhead

Every time a string is created and sometimes when a string is
expanded in size, memory needs to be allocated. When the string is
disposed of, that memory needs to be reclaimed. This memory
management does take up time. Also, several of the functions need
to take a little time to modify a local variable to keep track of
the length.

2.2 storage overhead

Not only does a "String" store all that a "char[]" does, it also
keeps an extra pointer and two integers (keep in mind that with any
C++ class, how an object is stored and its methods may change). A
large array of short strings would probably save a lot of space if
the char* type was used instead of the String type.

3 A little bit about how this works

Keep in mind that while the interface to this library will probably
weather time pretty well, always be prepared for some changes. How
it works internally probably *will* change although some of the
concepts may stay the same. As with any C++ class library, you may
depend on the interface staying the same, but *never* depend on the
internal workings and storage staying the same: If you happen to
discover how things are stored and processed internally and access
those values or methods directly, you'll probably regret it later.
Now, although I'm about to explain how some of the internal stuff
works, this is to help you decide how to best optimize your own
code, not so that you can modify this library or its private data.

When a String is declared

String S="Foo";

8 bytes are taken up on the stack and 19 are taken up on the heap.
The C++ heap management system may also have taken up some memory
for housekeeping so that the heap memory can be cleanly reclaimed.
Some time is taken to do the heap allocation, to record the length
of the string, the amount of memory allocated, the location of the
heap storage space and then to copy the string constant into the
heap with the null terminator.

Now, say we append to this string

S+="Bar";

The string constant, with its null terminator, is quickly copied
into the heap immediately after "Foo" and the string length status
is incremented by 3. There are now 12 bytes free on the heap
already allocated for use for this string. 6 bytes of the heap
space is used for the string and 1 is used for the null terminator.

S+=" is derived from the acronym FUBAR.";

The concatenation function recognizes that the amount of memory
needed to store the resulting string is 40 bytes. 19 is currently
allocated. 55 bytes of a new storage area is allocated. The text
"FooBar" is copied from the old storage area to the new storage
area. The string constant, with its null terminator, is now copied
into the new storage area following "FooBar". The old storage area
is released back to the heap. The local storage area pointer is set
to point at the new storage area. The size of the new storage area
is recorded. The length status is incremented to 39.

4 Implementing this with char* for optimal performance

By reading the previous section on how the internals of this library
work, it should be clear that declaring a string of type String that
is initialized and referenced, yet never modified, may be a waste of
time and space. Say you have a small bit of code:

void Foo(const char*);
void Bar(const char*);
...
String S="DooDah";
Foo(S);
Bar(S);

When S is constructed, it takes some time and space to get set up
and then just passes a pointer to its local copy of "DooDah" to Foo
and Bar. If S were set up as

char* S="DooDah";

instead, then there would be absolutely no time or space spent on
construction. S would be calculated at compile time rather than run
time and is the exact type as what is asked for so there is no
conversion time to speak of. The result is a smaller and faster
program without much loss of readability.

5 Functions

This library provides the same two flavors of functions that most
C++ class libraries do: Member functions and non-member functions.
The big difference is that member functions are called through their
string object (like S.Left(3)) while non-member functions are called
directly (like LeftText(S,3)). Operators, which are a form of a
function, like '+', '=' and '<', kinda look and act like they're
non-member functions, but are usually member functions cuz when the
C++ compiler sees them it will usually break them into a member
function of one of the operands: "S1 something that looks like "S1.LessThan(S2)" (or, more realistically,
"S1.operator<(S2)").

5.1 String class member functions

The main thing to remember when using these functions and operators
is that it should *seem* to be the way that you want to manipulate
the string. If you're just getting started you might try looking at
sections 5.1.1, 5.1.3 and then using the library. After using it a
bit, come back and read the rest so that you can get more
functionality and perhaps optimize things a bit more.

5.1.1 declaring a String

Don't let all of these extra operators for constructing a String
scare you off. These are mostly just extra whistles and bells
provided for optimizing existing code. For the most part, all of
your string declarations will probably be of the form

String S1="some text"; // S1 is now "some text"
String S2='X'; // S2 is now "X"
String S3=""; // S3 is now empty
String S4=S1; // S4 is now "some text"
String S5=S1+S2; // S5 is now "some textX"

5.1.1.1 based on a given string constant or char*

This is the String constructor that will probably be used more than
all the others combined. Maybe even as much as 95% of the time.
Although the preferred syntax is

String S="some text";

the syntax

String S("some text");

may also be used.

5.1.1.2 based on a character

Initializing a String to a single character may be done with either
of these two formats

String S1='x';
String S2('x');

the preferred method being the first. To initialize a string to a
certain length stuffed with a certain character, you must use the
second method followed by the length you want the string to be:

String S3('x',5); // S3 is now "xxxxx"

5.1.1.3 based on another String

"String S2=S1;" or "String S2(S1);" where S1 is predeclared of
type String.

5.1.1.4 without initialization

I think that

String S="";

is the best notation, although

String S;

can also be used.

Don't use

String S();

cuz the compiler will think that you have just declared a function
called "S" that takes no parameters and returns a String.

5.1.1.5 extra allocation

This feature is provided ONLY as an optimization technique. It
should not be used for all programming, especially by those just
starting out. Although using it does no harm, it adds more to read
in the program and thus makes the program less readable to the
beginner. I advise not using this feature except in those areas
where the time or space savings are crucial ("The fastest algorithm
can frequently be replaced by one that is almost as fast and much
easier to understand" -- ACM programming pearls).

When a string is constructed, a piece of memory is allocated to
store the actual string. Generally, a little more memory than what
is immediately needed is provided in case the string does a little
growing.

Should the programmer decide that time is a critical element and
knows that a string will be expanded beyond it's initial size by,
say, 30 characters, they may specify in the String constructor that
room for 30 extra characters needs to be allocated so that the
string won't need to be re-allocated later.

Another case is when the space is a critical element and the
programmer knows that the string will not become any larger. It can
then be specified in the String constructor that no additional room
for growth should be allocated.

The above 4 constructors may all be expanded to have an additional
parameter that will say how much more space should be allocated at
initialization time. The following examples all show an additional
allocation for 30 characters.

1: String S("some text",30);
In this example, re-allocation will not occur until the string
grows beyond 39 characters in size.

2: String S('x',5,30);
Note here that three parameters are required to achieve extra
allocation. If you want to initialize your string to a single
character with thirty extra characters worth of memory allocated
you must use ('x',1,30). ('x',30) will initialize a string of
30 'x's and the default extra allocation.

3: String S(S2,30);
4: String S(30);

At this writing, the default amount of extra allocation is 15
characters. This will probably change as time passes and this
library becomes implemented on different systems.

Keep in mind that the amount of memory allocated to hold a string is
different from the length of the string (which is always shorter).
Also keep in mind that when referring to the amount of memory
allocated, that value is strictly for string text, not a null
terminator, a length indicator or any other information. When a
String is allocated for 3 characters and is assigned to be "abc",
re-allocation does not occur.

5.1.2 Length() or Size()

Prototype: int Length()
int Size()

These two functions are very similar, yet care needs to used in
differentiating between the two. Both take the same parameters
(none) and return the same type (int).

Length() works like the ANSI C function strlen. It returns the
number of characters in the current string. This function is much
faster than strlen.

Size() returns the number of bytes needed to store this string
object on disk. This value is generally greater than the value
returned by Length() and the amount of difference will change for
different versions of this library on different machines (for
example, some systems will seperate strings with a carriage return
while others use a carriage return followed by a line feed). I
mention all of this cuz sometimes a programmer may notice a trend
(perhaps that in their experience Size() has always returned a value
one greater than Length()) and try to take advantage of it, only to
have it haunt them later.

5.1.3 + (concatenation)

This is the one thing that I like about this library (and C++) more
than any other. When you need to concatenate a whole mess of strings
together, you simply put a "+" between them. You can even mix
String types with char* and char types.

char* S1="aa";
String S2="bb";
String S3=S1+S2+"cc"; // S3 is now "aabbcc"

The only catch with all this is that a programmer would be tempted
to do something like

String S3=S1+"cc"; // error!!!

in this case, the compiler tries to first evaluate S1+"cc" which are
both pointers to a character. Since pointers are not allowed to be
added to pointers, the compiler will return an error. The solution
is to somehow mix a string into the concatenation list. In this
example, the best way would be to first convert S1 to a string

String S3=String(S1)+"cc"; // S3 is now "aacc"

5.1.4 += (appending form of concatenation)

Given

char* S1="aa";
String S2="bb";

then

S2+=S1; // S2 is now "bbaa"

however

S1+=S2; // error!!!

will not work. Remember that S1 is essentially a pointer. Trying
to increment a pointer by an object doesn't make much sense and
programmers are not allowed to modify or overload operators for
built-in (atomic) types.

5.1.5 = (assignment) and conversions

Another great thing that this library provides over ANSI C is simple
string assignment. With S1 and S2 of type String, "S1=S2" will give you
two equal, yet unique *Strings*. Modifications to S1 will not alter S2!
Also strings of type String may take assignment from strings of type
char*, a character, a character constant or a string constant.
Respectively:

char* S1="aa";
char C1='b';
String S2;
S2=S1;
S2=C1;
S2='c';
S2="dd";

Conversely, partial access to a String is allowed as char*. The only
"catch" is that the user must declare the receiving pointer as type
"const char*". This is to protect the internal representation, or
allocated copy of, the String type string. Most functions which accept a
parameter of type char*, specify that parameter prefaced with "const", so
the string may be passed directly and the converter will automatically
pass the appropriate pointer without reservations. Given

void Foo(const char*);
void Bar(char*);
String S="bar";

the code "Foo(S)" would be fine, but "Bar(S)" would result in an
error because S could not be converted. Since Bar does not specify
that it will not modify the string that is passed to it, then it may
do so and thus screw up the handling of S by this library.

Copying a string of type String to a string of type char* should be done
using the ANSI C strcpy or (preferably) strncpy functions:

String S1="Foo";
char S2[10];
strncpy(S2,S1,sizeof(S2));

5.1.6 ==,!=,<,>,<=,>= (comparison)

These operators simply call the ANSI C strcmp function. They are
provided for higher readability ("S1
5.1.7 () or At() (retrieving substrings)

Prototype: String At(int Index, int Length)
char At(int Index)

String S1="FooBar";
String S2=S1(1,3); // S2 is now "ooB"

Note that the parens can be prefixed with "At" if desired. The
above line could then read

String S2=S1.At(1,3); // S2 is now "ooB"

The second parameter is optional. If it's left out, a single char
is returned.

String S2=S1.At(3); // S2 is now "B"
char C=S1.At(3); // C is now 'B'

5.1.7.1 Before(), Through(), From() and After()

Prototype: String Before(int Index)
String Through(int Index)
String From(int Index)
String After(int Index)

Four quickie functions that can add a little readability to your
substring retrieval.

String S1="abcdefghijk";
String S2=S1.Before(5); // S2 is now "abcde"
String S3=S1.Through(5); // S3 is now "abcdef"
String S4=S1.From(5); // S4 is now "fghijk"
String S5=S1.After(5); // S5 is now "ghijk"

5.1.8 [] (String char reference)

Use this just as you would use it on an ANSI C style string.

String S="FooBar";
S[0]=S[3]; // S is now "BooBar"

This indexing is completely safe. As could be expected, referencing
beyond the end of the string will probably not do what you want
(although all data will remain safe). If you assign a null ('\0' or
0) to a character in the string, you will confuse the string
handler. If you want to truncate the string, call Left.

5.1.9 Left(), Right(), Center(), Just() (justification)

Prototype: void Left(int NewSize)
void Right(int NewSize)
void Center(int NewSize)
void Just(SByte Type, int NewSize)

Left, Right and Center all take one paramater, the new size of the
string desired. If the size of the string is larger than the new
size desired, the right part of the string is truncated. Otherwise,
the string is padded with spaces to bring the string up to the new
size desired.

Examples:

String S="Foo";
S.Left(1); // S is now "F"
S.Left(3); // S is now "F "
S="Foo"; // S is now "Foo"
S.Right(5); // S is now " Foo"
S.Right(3); // S is now " F"
S="Foo"; // S is now "Foo"
S.Center(5); // S is now " Foo "

The function "Just" simply acts as a parser

S="Foo";
S.Just(Center,5); // S is now " Foo "

5.1.10 Capacity() (report current allocation)

Prototype: int Capacity()

Simply reports how many characters long the string can get without
having to re-allocate.

5.1.11 ReAlloc() (change capacity)

Prototype: int ReAlloc(int NewCapacity)

Will perform a re-allocation to the capacity required. You might
use this to prevent future multiple re-allocation.

5.1.12 ToLower() (force all upper case letters to lower case)

Prototype: void ToLower()

5.1.13 ToUpper() (force all lower case letters to upper case)

Prototype: void ToUpper()

5.1.14 Index() (find the index of a char)

Prototype: int Index(char SearchChar, int StartIndex=0)

Starting at StartIndex, the string will be searched until SearchChar
is found or the end of the string is reached. If SearchChar is
found, the function returns the index to the char, otherwise the
function will return the constant "NotFound".

5.1.15 Insert() (insert a char or a sting into the string)

Prototype: void Insert(char C,int Index=0)
void Insert(const char* St,int Index=0)

String S="abcdefghijk";
S.Insert('X',3); // S is now "abcXdefghijk"
S.Insert("ZZZ",1); // S is now "aZZZbcXdefghijk"
S.Insert("AA"); // S is now "AAaZZZbcXdefghijk"
// S="AA"+S would be more readable I think

5.1.16 Delete() (delete characters from the string)

Prototype: void Delete(int Index=0,int Length=1)

String S="abcdefghijk";
S.Delete(1,2); // S is now "adefghijk"

5.2 non-member functions

These functions add a lot of coding convenience since they all
return strings without the need of preallocated space. They can be
used directly in functions that ask for a string without having an
intermediate storage identifier:

void Foo(const char*);
String Str(SLong);
...
Foo(Str(10000));

In ANSI C, you would have to first declare a temporary string big
enough to store the result of "Str", pass the string to "Str" and
then pass the result, which is stored in your string, to "Foo".

5.2.1 Str() (convert integers to String)

Prototype: String Str(long)

Examples:

int B=3;
String S=Str(B); // S is now "3"
S=Str(999999); // S is now "999999"
S=Str(-99999); // S is now "-99999"

5.2.2 Form() (convert reals to a String using a format)

Prototype: String Form(const char* Format,double Val)
String Form(int FLen,long Val)

You pass a legal format and a number to fit in it, and you'll get a
string back that is the same length as your format and has your
number properly arranged in it.

Characters that can be used are:

'#' a number, or a space if left of decimal, 0 if right
'@' same as '#' cept is 0 if there is no number
'.' defines the decimal place, if any. May only be one
',' a comma place holder

The characters '<' and '>' may be used to show negation. They must
both be used with '<' as the first character in the string and '>'
as the last.

Examples:

String S=Form("##",12.4); // S is now "12"
S=Form("<###,###.##>",-12.4); // S is now "< 12.40>"
S=Form("<###,###.##>", 12.4); // S is now " 12.40 "
S=Form("@@@@@", 12.4); // S is now "00012"
S=Form("@@@@@", -12.4); // S is now "-0012"
S=Form("#####", -12.4); // S is now " -12"
S=Form("@@@@@[email protected]@", 12.4); // S is now "00012.40"
S=Form("###,###.##", 12345); // S is now " 12,345.00"
S=Form("##", 123); // S is now "**"

The first parameter may also be a number...

S=Form( 6, 1234); // S is now " 1,234"
S=Form( 4, 1234); // S is now "1234"
S=Form( 2, 1234); // S is now "**"
S=Form(-6, 1234); // S is now " 1234 "
S=Form(-6,-1234); // S is now "<1234>"
S=Form(-7,-1234); // S is now "<1,234>"
S=Form( 6,-12.3); // S is now " -12"

If the first parameter is a number, then the second must be an
integer (or it will be converted to one).

5.2.3 StringOf() (return a string of chars)

Prototype: String StringOf(int HowMany, char OfWhat)

To remember the parameters of this think of "I want a string of
twenty periods", so you make the function call "StringOf(20,'.')".
To help remember the string constructor parameters (a very different
thing!), remember that it's based on the char and the number of
those chars is optional, so the char must come first.

String S=StringOf(5,'x'); // S is now "xxxxx"
String S('x',5); // S is now "xxxxx"

5.2.4 Spaces() (return a String containing a certain number of spaces)

Prototype: String Spaces(int HowMany)

5.2.5 LeftText(), RightText(), CenterText(), JustText()

Prototype: String LeftText(const char* CS, int NewSize)
String RightText(const char* CS, int NewSize)
String CenterText(const char* CS, int NewSize)
String JustText(const char* CS, SByte Type, int NewSize)

Remarkably similar to the String member functions Left, Right,
Center and Just.