LDP/LDP/howto/linuxdoc/C++Programming-HOWTO.sgml

4502 lines
130 KiB
Plaintext

<!doctype linuxdoc system>
<!--
************************** begin comment *****************************
The following is the HOW-TO for programming in C++.
This document is in the SGML format. You must use sgml package to
process this document
************************* end of comment *****************************
-->
<!--
************************** SGML USER GUIDE *****************************
The SGML user guide on linux is located at /usr/doc/sgml-tools
Read the example.sgml and guide.html documents.
Usage:
HTML sgml2html foo (Do not give extension .sgml here!!)
Text sgml2txt foo.sgml
Latex sgml2latex foo.sgml
Postscript sgml2latex -language=english -o ps foo.sgml
DVI sgml2latex -d foo.sgml
Lyx sgml2lyx foo.sgml
Richtext sgml2rtf foo.sgml
gnuinfo sgml2info foo.sgml
man sgml2txt -man foo.sgml
SGML sgmlcheck foo.sgml
************************* end of comment *****************************
-->
<article>
<!-- Title information -->
<title>C++ Programming HOW-TO
<!-- chapt change
C++ Programming HOW-TO
-->
<author>Al Dev (Alavoor Vasudevan)
<htmlurl url="mailto:alavoor@yahoo.com"
name="alavoor@yahoo.com">
<date>v11.0, 03 July 2000
<abstract>
This document discusses methods to avoid memory problems in C++ and
also will help you to program properly in C++ language.
The information in this document applies to all the operating sytems
that is - Linux, MS DOS, Apple Macintosh OS, Windows 95/NT,
OS/2, IBM OSes, VMS, Novell Netware, all flavors of
Unix like Solaris, HPUX, AIX, SCO, Sinix, BSD, etc.. and to
all other operating systems which support "C++" compiler (it
means almost all the operating systems on this planet!).
</abstract>
<!-- Table of contents -->
<toc>
<!-- Begin the document -->
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt>Introduction
-->
<sect>Introduction
<p>
C++ is the most popular language and will be used for a long time in the future
inspite of emergence of Java. C++ runs <bf>extremely fast</bf> and is
in fact <bf> 10 to 20 times FASTER than </bf> Java. Java runs very slow
because it is an byte-code-interpreted language running on top of "virtual engine".
Java runs faster with JIT compiler but is still slower than C++. And optimized
C++ program is
about <bf>3 to 4 times faster</bf> than Java
using the JIT (Just-In-Time) compiler!! The
memory management in Java is automated, so that programmers do not directly
deal with memory allocations. This document attempts
to automate the memory management in C++ to make it much more easy to use.
A neat feature of Java is that memory allocations are taken care of automatically.
This howto will enable "C++" to "compete/imitate" with Java language in memory management.
Because of manual memory allocations, debugging the C++ programs consumes a
major portion of time. The information
in this document will give you some better ideas and tips to reduce the debugging time.
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1>Problems facing the current C++ compilers
<p>
Since C++ is super-set of C, it got all the bad features of "C" language.
For example, in "C" programming - memory leaks, memory overflows are very common due
to usage of features like -
<code>
Datatype char * and char[]
String functions like strcpy, strcat, strncpy, strncat, etc..
Memory functions like malloc, realloc, strdup, etc..
</code>
The usage of <bf>char *</bf> and <bf>strcpy</bf> causes <it>horrible</it> memory
problems due to <it>"overflow"</it>,
<it>"fence past errors"</it>, <it>"step-on-others-toe"</it>
(hurting other variable's memory locations) or <it>"memory leaks"</it>.
The memory problems are extremely hard to debug and are
very time consuming to fix and trouble-shoot. Memory problems bring down
the productivity of programmers. This document helps in increasing the
productivity of programmers via different methods addressed to solve the
memory defects in "C++".
Memory related bugs are very tough to crack, and even experienced programmers
take several days, weeks or months to debug memory related problems. Many times memory
bugs will be "hiding" in the code for several months and can cause unexpected
program crashes!! The usage of
<bf>char *</bf> in C++
is costing USA and Japan $2 billion
every year in time lost in debugging and downtime of programs. If you use
<bf>char *</bf>
in C++ then it is a very costly affair especially if your programs have more
than 50,000 lines of code.
Hence, the following techniques are proposed to overcome the faults of "C"
language.
It is proposed that C++ compilers should prevent the programmers
from using the
<bf>"char *"</bf>
, <bf>"char[]"</bf> datatypes and
functions like <bf>strcpy</bf>, <bf>strcat</bf>,
<bf>strncpy</bf>, <bf>strncat</bf>.
The datatypes like char *, char[] and functions like strcpy, strcat
are <bf>evil</bf> and must be completetly <bf>BANNED</bf> from usage in C++!!
The
<bf>"char *"</bf>
is like <it>smallpox virus</it> and it must be eradicated from C++ world!!
If you want to use "char *" as in some system functions than you
should use "C" language. You would put
all your "C" programs in a seperate file and link to "C++" programs using
the <it>linkage-specification</it> statement <bf>extern "C" </bf> -
<code>
extern "C" {
#include <stdlib.h>
}
extern "C" {
comp();
some_c_function();
}
</code>
The <bf>extern "C"</bf> statement says that everything within the
brace-surrounded block - in this case, everything in the header file
and comp(), some_c_function() is compiled by a C compiler.
Instead of using char * and char[] all the C++ programmers MUST use the
<bf>'String class'</bf>
which is given in this document and
<bf>'string class'</bf>
included in the STDLIB.
The
<bf>'String class'</bf>
utilises the constructor and destructor to automate the memory management
and also provides many functions like <it>ltrim</it>, <it>substring</it>,
etc..
See also related
<bf>'string class'</bf>
in
the C++ compiler. The <bf>string class</bf> is part of the standard GNU C++
library and provides lot of string manipulation functions. The
<bf>'string class'</bf> and
<bf>'String class'</bf>
can remove the need of <bf>char *</bf> datatype.
Also, C++ programmers must be encouraged to use 'new', 'delete'
features instead of using 'malloc' or 'free'.
The
<bf>'String class'</bf>
does everything
that <bf>char *</bf> or <bf>char []</bf> does. It can
completely replace <bf>char</bf> datatype. Plus added
benefit is that programmers do not have to worry
about the memory problems and memory allocation at all!!
The GNU C++ compiler MUST drop off the support of <bf>char *, char[]</bf>
datatypes and in order to compile older programs using <bf>char</bf> datatype,
the compiler should provide a additional option called "-fchar-datatype" to g++ command.
Over the next 2 years all the C++ programs will use
<bf>'String class'</bf>
and
<bf>'string class'</bf>
and there will be no char * and char[]. The compiler
should try to prevent bad programming practices!
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1>Which one "C", "C++" or Java ?
<p>
It is recommended you do programming in object-oriented "C++" for all your
application programming or general purpose programming. You can take full
advantage of object oriented facilities of C++. The C++ compiler is lot
more complex than "C" compiler and C++ programs may run bit slower than "C"
programs. But speed difference between "C" and "C++" is very minute - it
could be few milli-seconds which may have little impact
for real-time programming.
Since computer hardware is becoming cheaper and faster and memory
'RAM' is getting faster and cheaper, it is worth doing code in C++ rather than
"C" as time saved in clarity and re-usability of C++ code
offsets the slow speed.
Compiler optimizer options like -O or -O3 can speed up C++/C
which is not available in Java.
Nowadays, "C" language is primarily used for "systems programming" to develop
operating sytems, device drivers etc..
Java is platform independent language more suitable for developing GUI running
inside web-browsers (Java applets) but runs very slow. Prefer to
use web-server-side programming "Fast-CGI" with C++ and HTML, DHTML,
XML to get better performance. Hence, the golden rule is <it>"Web-server side programming
use C++ and web-client side (browser) programming use Java applets"</it>. The
reason is - the server-side OS is under your control and never changes and you
will never know what the client side web-browser OS is. It can be Windows 95/98/NT/2000
or Linux, Apple Mac, OS/2, Netware, Solaris etc..
The greatness of Java is that it can run "GUI Applets" on any OS platform!
Java was created to replace the Microsoft Windows 95/NT GUI clients.
In other words - "Java is the Windows-GUI system of next century". Java
is already embedded in web-browsers like Netscape, Hot Java, etc..
Hence, Java runs on "client" and C++ runs on servers!!
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Download String <label id = "Download String">
-->
<sect> Download String <label id = "Download String">
<p>
All the programs, examples are given in Appendix of this document.
You can download as a single tar zip, the String class, libraries
and example programs from
<itemize>
<item> Go here and click on C++Programming howto.tar.gz file <url url="http://www.aldev.8m.com">
<item> Mirror site : <url url="http://aldev.webjump.com">
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Usage of String class
-->
<sect> Usage of String class
<p>
To use String class, you should first refer to a
sample program "example_String.cpp"
given in
<ref id ="Appendix A" name="Appendix A">
and the String class which is given in
<ref id ="Appendix B" name="Appendix B">.
The
<bf>'String class'</bf>
is a complete replacement for char and char * datatype.
You can use
<bf>'String class'</bf>
just like char and get much more functionalities.
You should include the library 'libString.a' which you can build from the
makefile given in
<ref id ="Appendix H" name="Appendix H"> and copy the library to
/usr/lib directory where all the "C++" libraries are located. To use
the 'libString.a' compile your programs like -
<code>
g++ example.cpp -lString
</code>
See illustration sample code as given below -
<code>
String aa;
aa = " Washington DC is the capital of USA ";
// You can use aa.val like a 'char *' variable in programs !!
for (unsigned long tmpii = 0; tmpii < aa.length(); tmpii++)
{
fprintf(stdout, "aa.val[%ld]=%c ", tmpii, aa.val[tmpii]);
}
// Using pointers on 'char *' val ...
// Note: You must use a temporary local variable and assign the
// pointer to aa.val. If you directly use aa.val and when
// aa.val is incremented with aa.val++, then aa will go
// call destructor and later when aa.val is accessed that
// will cause core dump !!
for (char *tmpcc = aa.val; *tmpcc != 0; tmpcc++)
{
// MUST use temporary variable tmpcc !! See note above.
fprintf(stdout, "aa.val=%c ", *tmpcc);
}
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1> Operators
<p>
The
<bf>'String class'</bf>
provides these operators :-
<itemize>
<item> Equal to <bf>==</bf>
<item> Not equal to <bf>!=</bf>
<item> Assignment <bf>=</bf>
<item> Add to itself and Assignment <bf>+=</bf>
<item> String concatenation or addition <bf>+</bf>
</itemize>
For example to use operators -
<code>
String aa;
String bb("Bill Clinton");
aa = "put some value string"; // assignment operator
aa += "add some more"; // Add to itself and assign operator
aa = "My name is" + " Alavoor Vasudevan "; // string cat operator
if (bb == "Bill Clinton") // boolean equal to operator
cout << "bb is eqaul to 'Bill Clinton' " << endl;
if (bb != "Al Gore") // boolean 'not equal' to operator
cout << "bb is not equal to 'Al Gore'" << endl;
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1> Functions
<p>
The functions provided by String class has the <bf>same name</bf>
as that Java language's
String class. The function names and the behaviour is <bf>exactly</bf> same
as that of Java's string class!! This will facilitate portability of code
between Java and C++ (you can cut and paste and do minimum changes to code).
The
<bf>'String class'</bf>
provides these <bf>Java like</bf> functions :-
<itemize>
<item> Current string length <bf>length()</bf>
<item> char charAt(int where);
<item> void getChars(int sourceStart, int sourceEnd, char target, int targetStart);
<item> char* toCharArray();
<item> bool equals(String str2); // See also == operator
<item> bool equals(char *str2); // See also == operator
<item> bool equalsIgnoreCase(String str2);
<item> bool regionMatches(int startIndex, String str2, int str2StartIndex, int numChars);
<item> bool regionMatches(bool ignoreCase, int startIndex, String str2, int str2StartIndex, int numChars);
<item> String toUpperCase();
<item> String toLowerCase();
<item> bool startsWith(String str2);
<item> bool startsWith(char *str2);
<item> bool endsWith(String str2);
<item> bool endsWith(char *str2);
<item> int compareTo(String str2);
<item> int compareTo(char *str2);
<item> int compareToIgnoreCase(String str2);
<item> int compareToIgnoreCase(char *str2);
<item> int indexOf(char ch, int startIndex = 0);
<item> int indexOf(char *str2, int startIndex = 0);
<item> int indexOf(String str2, int startIndex = 0);
<item> int lastIndexOf(char ch, int startIndex = 0);
<item> int lastIndexOf(char *str2, int startIndex = 0);
<item> int lastIndexOf(String str2, int startIndex = 0);
<item> String substring(int startIndex, int endIndex = 0);
<item> String replace(char original, char replacement);
<item> String replace(char *original, char *replacement);
<item> String trim(); // See also overloaded trim()
<item> String concat(String str2); // See also operator +
<item> String concat(char *str2); // See also operator +
<item> String append(String str2) {return concat(str2);} // See also operator +
<item> String append(char *str2) {return concat(str2);} // See also operator +
<item> String append(int bb) {return (*this + bb);} // See also operator +
<item> String append(unsigned long bb) {return (*this + bb);} // See also operator +
<item> String append(float bb) {return (*this + bb);} // See also operator +
<item> String insert(int index, String str2);
<item> String insert(int index, char ch);
<item> String reverse(); // See also overloaded reverse()
<item> String deleteCharAt(int loc);
<item> String deleteStr(int startIndex, int endIndex); // Java's "delete()"
</itemize>
These are addional functions which are not available in Java.
<itemize>
<item> Left trim the string. Remove leading white-spaces - newlines, tabs <bf>ltrim()</bf>
<item> Right trim the string. Remove trailing white-spaces - newlines, tabs <bf>rtrim()</bf>
<item> Remove trailing and leading white-spaces <bf>trim()</bf>
<item> Remove trailing newlines <bf>chop()</bf>
<item> Change string to upper case <bf>to_upper()</bf>
<item> Change string to lower case <bf>to_lower()</bf>
<item> Truncate or round-off the float value <bf>roundf(float input_val, short precision)</bf>
<item> Truncate or round-off the double value <bf>roundd(double input_val, short precision)</bf>
<item> Find position, matching substr beginning
from start <bf>pos(char *substr, unsigned long start)</bf>
<item> Explodes the string and returns the list in the
list-head pointer explodeH <bf>explode(char *seperator)</bf>
<item> Implodes the strings in the list-head pointer explodeH and
returns the String variable <bf>implode(char *glue)</bf>
<item> Joins the strings in the list-head pointer explodeH and
returns the String variable <bf>join(char *glue)</bf>
<item> Repeat the input string n times <bf>repeat(char *input, unsigned int multiplier)</bf>
<item> Replace all occurences of string 'needle' with 'str' in
the haystack 'val' <bf>replace(char *needle, char *str)</bf>
<item> Translate certain chars <bf>str_tr(char *from, char *to)</bf>
<item> Center the text string <bf>center(int length, char padchar = ' ')</bf>
<item> Formats the original string by placing 'number' of 'padchar' characters
between each set of blank-delimited words. Leading and Trailing blanks
are always removed. If 'number' is omitted or is 0, then all spaces are
in the string are removed. The default number is 0 and
default padchar ' ' <bf>space(int number = 0, char padchar = ' ')</bf>
<item> The result is string comprised of all characters between
and including 'start' and 'end' <bf>xrange(char start, char end)</bf>
<item> Removes any characters contained in 'list'. The default character
for 'list' is a blank ' ' <bf>compress(char *list)</bf>
<item> Deletes a portion of string of 'length' characters from 'start' position.
If start is greater than the string length than string is
unchanged <bf>delstr(int start, int length)</bf>
<item> The 'newstr' in inserted into val beginning at 'start'. The 'newstr' will
be padded or truncated to 'length' characters. The default 'length' is
string length
of newstr <bf>insert(char *newstr, int start = 0, int length = 0, char padchar = ' ')</bf>
<item> The result is string of 'length' chars madeup of leftmost chars in val.
Quick way to left justify a string <bf>left(int length = 0, char padchar = ' ')</bf>
<item> The result is string of 'length' chars madeup of rightmost chars in val.
Quick way to right justify a string <bf>right(int length = 0, char padchar = ' ')</bf>
<item> The 'newstr' in overlayed into val beginning at 'start'. The 'newstr' will
be padded or truncated to 'length' characters. The default 'length' is
string length
of newstr <bf>overlay(char *newstr, int start = 0, int length = 0, char padchar = ' ')</bf>
<item> Sub-string, extract a portion of string <bf>substr(int start, int length = 0)</bf>
<item> matches first match of regx <bf>at(char *regx)</bf>
<item> Returns string before regx <bf>before(char *regx)</bf>
<item> Returns string after regx <bf>after(char *regx)</bf>
<item> Returns true if string is NULL value <bf>bool isnull()</bf>
<item> Resets the string to NULL <bf>clear()</bf>
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1> Miscellaneous Functions
<p>
Some miscellaneous String functions are given here, but <bf>DO NOT USE</bf> these,
and instead use operators like '+', '+=', '==' etc.. These are 'private' members of
the 'String' class.
<itemize>
<item> Copy string <bf>str_cpy(char *bb)</bf>
<item> Long integer converted to string <bf>str_cpy(unsigned long bb)</bf>
<item> Integer converted to string <bf>str_cpy(int bb)</bf>
<item> Float converted to string <bf>str_cpy(float bb)</bf>
<item> String concatenate a char * <bf>str_cat(char *bb)</bf>
<item> String concatenate a int <bf>str_cat(int bb)</bf>
<item> String concatenate a int <bf>str_cat(unsigned long bb)</bf>
<item> String concatenate a float <bf>str_cat(float bb)</bf>
<item> Is equal to String ? <bf>bool equalto(const String & rhs, bool type = false)</bf>
<item> Is equal to char* ? <bf>bool equalto(const char *rhs, bool type = false)</bf>
</itemize>
For example to convert integer to string do -
<code>
String aa;
aa = 34; // The '=' operator will convert int to string
cout << "The value of aa is : " << aa.val << endl;
aa = 234.878; // The '=' operator will convert float to string
cout << "The value of aa is : " << aa.val << endl;
aa = 34 + 234.878;
cout << "The value of aa is : " << aa.val << endl;
// The output aa will be '268.878'
// You must cast String to convert
aa = (String) 34 + " Honourable President Ronald Reagan " + 234.878;
cout << "The value of aa is : " << aa.val << endl;
// The output aa will be '34 Honourable President Ronald Reagan 234.878'
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> C++ Zap (Delete) command <label id="zap">
-->
<sect> C++ Zap (Delete) command <label id="zap">
<p>
The
<bf>delete</bf> and
<bf>new</bf>
commands in C++ are much better than the malloc and free functions of "C".
Consider using new and zap (delete command) instead of malloc and free
as much as possible.
To make
<bf>delete</bf>
command even more cleaner, make a Zap() command. Define
a zap() command like this:
<code>
/*
** Use do while to make it robust and bullet-proof macro.
** For example, if "do-while" is NOT used then results will be
** something else just as in -
** if (bbint == 4)
** aa = 0
** else
** zap(aptr); // Problem!! aptr will be always set to NULL
*/
#define zap(x) do { delete(x); x = NULL; } while (0)
</code>
The zap() command will delete the pointer and set it NULL.
This will ensure that even if multiple zap()'s are called on the
same deleted pointer then the
program will not crash. For example -
<code>
zap(pFirstname);
zap(pFirstname); // no core dumps !! Because pFirstname is NULL now
zap(pFirstname); // no core dumps !! Because pFirstname is NULL now
zap(pLastname);
zap(pJobDescription);
</code>
There is nothing magical about this, it just saves
repetative code, saves typing time and makes programs more readable. The
C++ programmers often forget to reset the deleted pointer
to NULL, and this causes annoying
problems causing core dumps and crashes. The zap() takes care of
this automatically.
Do not stick a typecast in the zap() command -- if something errors out on the
above zap() command it likely has another error somewhere.
Also
<ref id="my_malloc" name="my_malloc()">
, my_realloc() and my_free() should be used
instead of malloc(), realloc() and free(), as they
are much cleaner and have additional checks.
For an example, see the file "String.h" which is using
the
<ref id="my_malloc" name="my_malloc()">
and my_free() functions.
<bf>WARNING :</bf> Do not use free() to free memory allocated with 'new'
or 'delete' to free memory allocated with malloc. If you do, then
results will be unpredictable!!
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Pointers are problems <label id="pointers">
-->
<sect> Pointers are problems <label id="pointers">
<p>
Pointers are not required for general purpose programming. In modern
languages like Java there is no support for pointers!! Pointers make
the programs messy and programs using pointers are very hard to read.
Avoid using pointers as much as possible and use references. Pointers are really a
great pain. It is possible to write a application without using pointers.
A <bf>reference</bf> is an alias; when you create a reference, you initialize
it with the name of another object, the target. From the moment on, the reference
acts as an alternative name of the target, and anything you do to the reference
is really done to the target.
<bf>Syntax of References:</bf> Declare a reference by writing the type, followed by
the reference operator (&), followed by the reference name. References
<bf>MUST</bf> be initialized at the time of creation.
For example -
<code>
int weight;
int & rweight = weight;
DOG aa;
DOG & rDogRef = aa;
</code>
<it>Do's</it> of references -
<itemize>
<item>Do use references to create an alias to an object
<item>Do initialize all references
<item>Do use references for high efficiency and performance of program.
<item>Do use <bf>const</bf> to protect references and pointers whenever possible.
</itemize>
<it>Do not's</it> of references -
<itemize>
<item><bf>IMPORTANT: </bf>Don't use references to NULL objects !!!!
<item>Don't confuse the address of operator &amp with reference operator !! The references
are used in the declarations section (see Syntax of References above).
<item>Don't try to reassign a reference
<item>Don't use pointers if references will work
<item>Don't return a reference to a local object
<item>Don't pass by reference if the item referred to may go out of scope
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Usage of my_malloc and my_free <label id="my_malloc">
-->
<sect> Usage of my_malloc and my_free <label id="my_malloc">
<p>
Try to avoid using malloc and realloc as much as possible and use <bf>new</bf>
and <bf><ref id="zap" name="zap">(delete)</bf>. But sometimes you may need to
use the "C" style memory allocations in "C++". Use the functions
<bf>my_malloc()</bf> ,
<bf>my_realloc()</bf> and
<bf>my_free()</bf>.
These functions do proper allocations and initialisations and try to prevent
memory problems. Also these functions (in DEBUG mode) can keep track
of memory allocated and print total memory usage before and after the program
is run. This tells you if there are any memory leaks.
The my_malloc and my_realloc is defined as below. It allocates little more memory
(SAFE_MEM = 5) and initializes the space and if it cannot allocate it exits the
program. The 'call_check(), remove_ptr()' functions are active only when DEBUG is defined in
makefile and are assigned to
((void)0) i.e. NULL
for non-debug production release. They enable the total-memory used tracing.
<code>
void *local_my_malloc(size_t size, char fname[], int lineno)
{
size_t tmpii = size + SAFE_MEM;
void *aa = NULL;
aa = (void *) malloc(tmpii);
if (aa == NULL)
raise_error_exit(MALLOC, VOID_TYPE, fname, lineno);
memset(aa, 0, tmpii);
call_check(aa, tmpii, fname, lineno);
return aa;
}
char *local_my_realloc(char *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpjj = 0;
if (aa) // aa != NULL
tmpjj = strlen(aa);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (char) * (tmpqq);
aa = (char *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
aa[tmpqq-1] = 0;
unsigned long kk = tmpjj;
if (tmpjj > tmpqq)
kk = tmpqq;
for ( ; kk < tmpqq; kk++)
aa[kk] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
</code>
See
<ref id ="Appendix D" name="my_malloc.cpp">.
and the header file
<ref id ="Appendix E" name="my_malloc.h">.
for full implementation of the my_malloc program.
An example on usage of my_malloc and my_free as below:
<code>
char *aa;
int *bb;
float *cc;
aa = (char *) my_malloc(sizeof(char)* 214);
bb = (int *) my_malloc(sizeof(int) * 10);
cc = (float *) my_malloc(sizeof(int) * 20);
aa = my_realloc(aa, sizeof(char) * 34);
bb = my_realloc(bb, sizeof(int) * 14);
cc = my_realloc(cc, sizeof(float) * 10);
</code>
Note that in my_realloc you do not need to cast the datatype as the
variable itself is passed and correct my_realloc is called which
returns the proper datatype pointer. The my_realloc has overloaded
functions for char*, int* and float*.
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Debug files
-->
<sect> Debug files
<p>
To debug any C++ or C programs include the file
<ref id="Appendix F" name="debug.h">
and in your 'Makefile' define DEBUG to turn on the traces from the debug.h functions.
When you remove the '-DDEBUG' then the debug function calls are set to
((void)0) i.e. NULL,
hence it has no impact on final production release version of project. You can generously
use the debug functions in your programs and it will not increase the size of production
executable.
See the file
<ref id="Appendix G" name="debug.cpp">
for implementation of debug routines.
And see the file
<ref id="Appendix D" name="my_malloc.cpp">
for sample which uses debug.h and debug functions.
See the sample
<ref id="Appendix H" name="Makefile">
.
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> C++ Online-Docs
-->
<sect> C++ Online-Docs
<p>
Visit the following C++ sites :-
<itemize>
<item>C++ Crash-proof site <url url="http://www.troubleshooters.com/codecorn/crashprf.htm">
<item>C++ Memory site<url url="http://www.troubleshooters.com/codecorn/memleak.htm">
</itemize>
Internet has vast amounts of documentation on C++. Visit the search engines
like Yahoo, Lycos, Infoseek, Excite. Type in the
keywords
<bf>'C++ tutorials'</bf>
<bf>'C++ references'</bf>
<bf>'C++ books'</bf>
. You can narrow down the search criteria by clicking on <it>Advanced</it>
search and select <it>search by exact phrase</it>
<itemize>
<item> <url url="http://www.yahoo.com">
<item> <url url="http://www.lycos.com">
<item> <url url="http://www.infoseek.com">
<item> <url url="http://www.excite.com">
<item> <url url="http://www.mamma.com">
</itemize>
<sect1> C++ Tutorials
<p>
There are many on-line tutorials available on internet. Type 'C++ tutorials'
in the search engine.
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1> C++ Coding Standards
<p>
Visit the C++ Coding Standards URLs
<itemize>
<item> C++ coding standard <url url="http://www.cs.umd.edu/users/cml/cstyle/CppCodingStandard.html">
<item> Coding standards from Possibility <url url="http://www.possibility.com/Cpp/CppCodingStandard.html">
<item> Coding standards from Ambysoft <url url="http://www.ambysoft.com/javaCodingStandards.html">
<item> Rules and recommendations <url url="http://www.cs.umd.edu/users/cml/cstyle/">
<item> Indent and annotate <url url="http://www.cs.umd.edu/users/cml/cstyle/indhill-annot.html">
<item> Elemental rules <url url="http://www.cs.umd.edu/users/cml/cstyle/Ellemtel-rules.html">
<item> C++ style doc <url url="http://www.cs.umd.edu/users/cml/cstyle/Wildfire-C++Style.html">
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
<sect1> C++ Quick-Reference
<p>
Type 'C++ Reference' in the search engine.
<sect1> C++ Usenet Newsgroups
<p>
<itemize>
<item> C++ newsgroups : <url url="comp.lang.c++.announce">
<item> C++ newsgroups : <url url="comp.lang.c++.*">
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt change> Memory Tools
-->
<sect> Memory Tools
<p>
Use the following memory debugging tools
<itemize>
<item> On linux contrib cdrom see mem_test*.rpm package
<item> On linux cdrom see ElectricFence*.rpm package
<item> Purify Tool from Rational Software Corp <url url="http://www.rational.com">
<item> Insure++ Tool from Parasoft Corp <url url="http://www.parasoft.com">
<item> Linux Tools at <url url="http://www.xnet.com/~blatura/linapp6.html#tools">
<item> Search the Internet engines like Yahoo, Lycos, Excite, Mamma.com
for keyword "Linux memory debugging tools".
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt change> Related URLs
-->
<sect> Related URLs
<p>
Visit following locators which are related to C, C++ -
<itemize>
<item> Vim color text editor for C++, C <url url="http://metalab.unc.edu/LDP/HOWTO/Vim-HOWTO.html">
<item> C++ Beautifier HOWTO <url url="http://metalab.unc.edu/LDP/HOWTO/C-C++Beautifier-HOWTO.html">
<item> CVS HOWTO for C++ programs <url url="http://metalab.unc.edu/LDP/HOWTO/CVS-HOWTO.html">
<item> Linux goodies main site <url url="http://www.aldev.8m.com">
<item> Linux goodies mirror site <url url="http://aldev.webjump.com">
</itemize>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt change> Other Formats of this Document
-->
<sect> Other Formats of this Document
<p>
This document is published in 11 different formats namely - DVI, Postscript,
Latex, Adobe Acrobat PDF,
LyX, GNU-info, HTML, RTF(Rich Text Format), Plain-text, Unix man pages and SGML.
<itemize>
<item>
You can get this HOWTO document as a single file tar ball in HTML, DVI,
Postscript or SGML formats from -
<url url="ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/other-formats/">
<item>Plain text format is in: <url url="ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO">
<item>Translations to other languages like French, German, Spanish,
Chinese, Japanese are in
<url url="ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO">
Any help from you to translate to other languages is welcome.
</itemize>
The document is written using a tool called "SGML tool" which can be got from -
<url url="http://www.xs4all.nl/~cg/sgmltools/">
Compiling the source you will get the following commands like
<itemize>
<item>sgml2html C++Programming-HOWTO.sgml (to generate html file)
<item>sgml2rtf C++Programming-HOWTO.sgml (to generate RTF file)
<item>sgml2latex C++Programming-HOWTO.sgml (to generate latex file)
</itemize>
LaTeX documents may be converted into PDF files simply by
producing a Postscript output using <bf>sgml2latex</bf> ( and dvips) and running the
output through the Acrobat <bf>distill</bf> (<url url="http://www.adobe.com">) command as follows:
<code>
bash$ man sgml2latex
bash$ sgml2latex filename.sgml
bash$ man dvips
bash$ dvips -o filename.ps filename.dvi
bash$ distill filename.ps
bash$ man ghostscript
bash$ man ps2pdf
bash$ ps2pdf input.ps output.pdf
bash$ acroread output.pdf &
</code>
Or you can use Ghostscript command <bf>ps2pdf</bf>.
ps2pdf is a work-alike for nearly all the functionality of
Adobe's Acrobat Distiller product: it
converts PostScript files to Portable Document Format (PDF) files.
<bf>ps2pdf</bf> is implemented as a very small command script (batch file) that invokes Ghostscript, selecting a special "output device"
called <bf>pdfwrite</bf>. In order to use ps2pdf, the pdfwrite device must be included in the makefile when Ghostscript was compiled;
see the documentation on building Ghostscript for details.
This howto document is located at -
<itemize>
<item> <url url="http://sunsite.unc.edu/LDP/HOWTO/C++Programming-HOWTO.html">
</itemize>
Also you can find this document at the following mirrors sites -
<itemize>
<item> <url url="http://www.caldera.com/LDP/HOWTO/C++Programming-HOWTO.html">
<item> <url url="http://www.WGS.com/LDP/HOWTO/C++Programming-HOWTO.html">
<item> <url url="http://www.cc.gatech.edu/linux/LDP/HOWTO/C++Programming-HOWTO.html">
<item> <url url="http://www.redhat.com/linux-info/ldp/HOWTO/C++Programming-HOWTO.html">
<item> Other mirror sites near you (network-address-wise) can be found at
<url url="http://sunsite.unc.edu/LDP/hmirrors.html">
select a site and go to directory /LDP/HOWTO/C++Programming-HOWTO.html
</itemize>
In order to view the document in dvi format, use the xdvi program. The xdvi
program is located in tetex-xdvi*.rpm package in Redhat Linux which can be
located through ControlPanel | Applications | Publishing | TeX menu buttons.
To read dvi document give the command -
<tscreen><verb>
xdvi -geometry 80x90 howto.dvi
man xdvi
</verb></tscreen>
And resize the window with mouse.
To navigate use Arrow keys, Page Up, Page Down keys, also
you can use 'f', 'd', 'u', 'c', 'l', 'r', 'p', 'n' letter
keys to move up, down, center, next page, previous page etc.
To turn off expert menu press 'x'.
You can read postscript file using the program 'gv' (ghostview) or
'ghostscript'.
The ghostscript program is in ghostscript*.rpm package and gv
program is in gv*.rpm package in Redhat Linux
which can be located through ControlPanel | Applications | Graphics menu
buttons. The gv program is much more user friendly than ghostscript.
Also ghostscript and gv are available on other platforms like OS/2,
Windows 95 and NT, you view this document even on those platforms.
<itemize>
<item>Get ghostscript for Windows 95, OS/2, and for all OSes from <url url="http://www.cs.wisc.edu/~ghost">
</itemize>
To read postscript document give the command -
<tscreen><verb>
gv howto.ps
ghostscript howto.ps
</verb></tscreen>
You can read HTML format document using Netscape Navigator, Microsoft Internet
explorer, Redhat Baron Web browser or any of the 10 other web browsers.
You can read the latex, LyX output using LyX a X-Windows front end to latex.
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Copyright
-->
<sect> Copyright
<p>
Copyright policy is GNU/GPL as per LDP (Linux Documentation project).
LDP is a GNU/GPL project.
Additional requests are that you retain the author's name, email address
and this copyright notice on all the copies. If you make any changes
or additions to this document then you please
intimate all the authors of this document.
Brand names mentioned in this document are property of their respective
owners.
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix A example_String.cpp <label id="Appendix A">
-->
<sect> Appendix A example_String.cpp <label id="Appendix A">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
// To prevent memory leaks - a char class to manage character variables
// Always prefer to use string class
// instead of char[] or char *
// To compile and test this program do -
// Assuming that libString.a is in the current directory
// g++ example_String.cpp -L. -lString
#include <stdlib.h> // for putenv
#include "String.h"
//#include <string> // This is at /usr/include/g++-2/string
//#include <cstring> // This is at /usr/include/g++-2/cstring and includes /usr/inlcude/strings.h
/////////////////////////////////////////////////
// A example program to demo usage of String
// Note: In this example, I did not use memory
// manipulation functions like new, delete, malloc,
// strdup at all!! The String class takes care of
// it automatically !!
/////////////////////////////////////////////////
int main(int argc, char **argv)
{
char p_name[1024];
sprintf(p_name, "PROGRAM_NAME=%s", argv[0]);
putenv(p_name);
print_total_memsize(); // in the beginning
String aa, bb, egg;
char tmpaa[100];
//bb.str_cpy(" bbSTRing ");
bb = " bbSTRing ";
// Testing the + operator
// aa + " rhs "; // You will not get any output here !!!
// You must directly use in fprintf as in below line -
fprintf(stdout, "1) aa.val is :%sEOF\n", (aa + " my rhs " ).val);
// Testing the = operator
aa = " lhs " ;
fprintf(stdout, "2) With operator= aa.val is :%sEOF\n", aa.val);
// Testing the + operator
// " lhs " + aa; // You will not get any output here !!!
// You must directly use in fprintf as in below line -
fprintf(stdout, "3) With lsh operator+, aa.val is :%sEOF\n", (" my lhs " + aa ).val);
// ***************** Java like functions ********************
aa = "Some Value 2345";
fprintf(stdout, "4) aa.charAt() is :%c %sEOF\n", aa.charAt(3), aa.val);
aa = "Some Value 2345";
strcpy(tmpaa, "tmpaa value");
aa.getChars(3, 8, tmpaa, 2);
fprintf(stdout, "5) aa.getChars() is : %s %sEOF\n", tmpaa, aa.val);
aa = "Some Value 2345";
fprintf(stdout, "6) aa.toCharArray() is : %sEOF\n", aa.toCharArray());
aa = "Some2345";
if (aa.equals("Some2345"))
fprintf(stdout, "7) aa.equals() is true : %sEOF\n", aa.val);
else
fprintf(stdout, "7) aa.equals() is false : %sEOF\n", aa.val);
aa = "testinglettercase";
egg = "TestingLetterCase";
if (aa.equalsIgnoreCase(egg))
fprintf(stdout, "8) egg equals aa (case insensitive) aa.val is :%sEOF\n", aa.val);
else
fprintf(stdout, "8) egg not equals aa (case insensitive) aa.val is :%sEOF\n", aa.val);
aa = "kkktestinglettercase";
egg = "abtestingLetterCase";
if (aa.regionMatches(true, 3, egg, 2, 7))
fprintf(stdout, "9) regionMatches is true aa.val is :%sEOF\n", aa.val);
else
fprintf(stdout, "9) regionMatches is false aa.val is :%sEOF\n", aa.val);
//aa.str_cpy(bb.val);
aa = bb + "Some Value 2345";
egg = aa.toUpperCase();
fprintf(stdout, "10) egg.val is :%sEOF\n", egg.val);
aa = bb + "Some Value 2345";
egg = aa.toLowerCase();
fprintf(stdout, "11) egg.val is :%sEOF\n", egg.val);
aa = "Some Value 2345";
egg = "Some";
if (aa.startsWith("Some"))
//if (aa.startsWith(egg))
fprintf(stdout, "12) aa.startsWith() is true :%sEOF\n", aa.val);
else
fprintf(stdout, "12) aa.startsWith() is false :%sEOF\n", aa.val);
aa = "Some Value 2345";
egg = " 2345";
if (aa.endsWith(" 2345"))
//if (aa.endsWith(egg))
fprintf(stdout, "13) aa.endsWith() is true :%sEOF\n", aa.val);
else
fprintf(stdout, "13) aa.endsWith() is false :%sEOF\n", aa.val);
aa = "bbb Some Value 2345";
egg = "caabc";
if (aa.compareTo(egg) == 0)
fprintf(stdout, "14) aa.compareTo() is zero :%sEOF\n", aa.val);
else
if (aa.compareTo(egg) > 0)
fprintf(stdout, "14) aa.compareTo() is greater :%sEOF\n", aa.val);
else
if (aa.compareTo(egg) < 0)
fprintf(stdout, "14) aa.compareTo() is less than :%sEOF\n", aa.val);
aa = "bbb Some Value 2345";
strcpy(tmpaa, "aabbb Some Value 2345");
if (aa.compareTo(tmpaa) == 0)
fprintf(stdout, "15) aa.compareTo() is zero :%sEOF\n", aa.val);
else
if (aa.compareTo(tmpaa) > 0)
fprintf(stdout, "15) aa.compareTo() is greater :%sEOF\n", aa.val);
else
if (aa.compareTo(tmpaa) < 0)
fprintf(stdout, "15) aa.compareTo() is less than :%sEOF\n", aa.val);
aa = "bbb Some Value 2345";
//egg = "bbb Some Value 2345";
egg = "CCaabc"; // change values to caabc, aabc
if (aa.compareToIgnoreCase(egg) == 0)
fprintf(stdout, "16) aa.compareToIgnoreCase() is zero :%sEOF\n", aa.val);
else
if (aa.compareToIgnoreCase(egg) > 0)
fprintf(stdout, "16) aa.compareToIgnoreCase() is greater :%sEOF\n", aa.val);
else
if (aa.compareToIgnoreCase(egg) < 0)
fprintf(stdout, "16) aa.compareToIgnoreCase() is less than :%sEOF\n", aa.val);
aa = "bbb Some Value 2345";
//strcpy(tmpaa, "bbb Some Value 2345");
strcpy(tmpaa, "CAABbb Some Value 2345"); // change value to caabb, aab
if (aa.compareToIgnoreCase(tmpaa) == 0)
fprintf(stdout, "17) aa.compareToIgnoreCase() is zero :%sEOF\n", aa.val);
else
if (aa.compareToIgnoreCase(tmpaa) > 0)
fprintf(stdout, "17) aa.compareToIgnoreCase() is greater :%sEOF\n", aa.val);
else
if (aa.compareToIgnoreCase(tmpaa) < 0)
fprintf(stdout, "17) aa.compareToIgnoreCase() is less than :%sEOF\n", aa.val);
aa = "bbb Some Value 2345";
strcpy(tmpaa, "Some");
egg = "Value";
fprintf(stdout, "18) aa.indexOf('S') %d :%sEOF\n", aa.indexOf('S'), aa.val);
fprintf(stdout, "18) aa.indexOf(tmpaa) %d :%sEOF\n", aa.indexOf(tmpaa), aa.val);
fprintf(stdout, "18) aa.indexOf(egg) %d :%sEOF\n", aa.indexOf(egg), aa.val);
aa = "bbb Some Value Some 2345";
strcpy(tmpaa, "Some");
egg = "Some";
fprintf(stdout, "19) aa.lastIndexOf('S') %d :%sEOF\n", aa.lastIndexOf('S'), aa.val);
fprintf(stdout, "19) aa.lastIndexOf(tmpaa) %d :%sEOF\n", aa.lastIndexOf(tmpaa), aa.val);
fprintf(stdout, "19) aa.lastIndexOf(egg) %d :%sEOF\n", aa.lastIndexOf(egg), aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "20) aa.substring(5) %s :%sEOF\n",
aa.substring(5).val, aa.val);
aa = "bbb Some Value Some 2345";
strcpy(tmpaa, "Some");
egg = "Some";
fprintf(stdout, "20) aa.replace('S', 'V') %s :%sEOF\n",
aa.replace('S', 'V').val, aa.val);
fprintf(stdout, "20) aa.replace(Som, Vzz) %s :%sEOF\n",
aa.replace("Som", "Vzz").val, aa.val);
aa = " bbb Some Value Some 2345 ";
fprintf(stdout, "21) aa.trim() %s val :%sEOF\n",
aa.trim().val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "21) aa.concat() %s val :%sEOF\n",
aa.concat("add one").val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "21) aa.append() %s val :%sEOF\n",
aa.append("add append").val, aa.val);
aa = "bbb Some Value Some 2345";
egg = "jjjj";
fprintf(stdout, "21) aa.insert(5, egg) %s val :%sEOF\n",
aa.insert(5, egg).val, aa.val);
fprintf(stdout, "21) aa.insert(5, ch) %s val :%sEOF\n",
aa.insert(5, 'M').val, aa.val);
aa = "12345678";
fprintf(stdout, "46) aa.reverse()=%s aa.val is :%sEOF\n", aa.reverse().val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "21) aa.deleteCharAt(4) %s val :%sEOF\n",
aa.deleteCharAt(4).val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "22) aa.deleteStr(3,5) %s val :%sEOF\n",
aa.deleteStr(3,5).val, aa.val);
// ***************** end Java like functions ********************
aa = "bbb Some Value Some 2345";
fprintf(stdout, "23) aa.str_tr(bomekk, BOME) %s val :%sEOF\n",
aa.tr("bomekk", "BOME").val, aa.val);
aa = "bbb Some Value Some 2345";
aa = "$1,934 100%.234";
fprintf(stdout, "24) aa.compress() %s val :%sEOF\n",
aa.compress("$,%").val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "25) aa.xrange('a', 'j') %s val :%sEOF\n",
aa.xrange('a', 'j').val, aa.val);
fprintf(stdout, "25) aa.xrange('1', '8') %s val :%sEOF\n",
aa.xrange('1', '8').val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "26) aa.center(15) %s val :%sEOF\n",
aa.center(15).val, aa.val);
fprintf(stdout, "26) aa.center(15, '*') %s val :%sEOF\n",
aa.center(15, '*').val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "27) aa.space(3) %s val :%sEOF\n",
aa.space(3).val, aa.val);
aa = " Some Value Some 2345";
fprintf(stdout, "28) aa.left() %s val :%sEOF\n",
aa.left().val, aa.val);
fprintf(stdout, "28) aa.left(18) %s val :%sEOF\n",
aa.left(18).val, aa.val);
aa = " 2345 ";
fprintf(stdout, "29) aa.right():%s val :%sEOF\n",
aa.right().val, aa.val);
fprintf(stdout, "29) aa.right(5):%s val :%sEOF\n",
aa.right(5).val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "30) aa.overlay(12345678, 4, 10, *):%s val :%sEOF\n",
aa.overlay("12345678", 4, 10, '*').val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "31) aa.at(Som) %s :%sEOF\n",
aa.at("Som").val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "32) aa.before(Som) %s :%sEOF\n",
aa.before("Skkkom").val, aa.val);
aa = "bbb Some Value Some 2345";
fprintf(stdout, "33) aa.after(Som) %s :%sEOF\n",
aa.after("Som").val, aa.val);
aa = " bb some value ";
aa.ltrim(true);
fprintf(stdout, "34) aa.val is :%sEOF\n", aa.val);
aa = " bb some value ";
aa.rtrim(true);
fprintf(stdout, "35) aa.val is :%sEOF\n", aa.val);
aa = " bb some value ";
aa.trim(true);
fprintf(stdout, "36) aa.val is :%sEOF\n", aa.val);
aa = bb;
aa = aa + " testing newlines \n\n\n\n";
aa.chopall();
fprintf(stdout, "37) aa.val is :%sEOF\n", aa.val);
aa = bb;
aa = aa + " rhs ";
fprintf(stdout, "38) aa.val is :%sEOF\n", aa.val);
aa = bb;
aa = " lhs " + aa;
fprintf(stdout, "39) aa.val is :%sEOF\n", aa.val);
// Sample addition of numbers
//aa = (String) 9989 + "kkk" + 33 ;
aa = 9999;
fprintf(stdout, "40) aa.val is :%sEOF\n", aa.val);
aa = bb;
aa = " lhs " + aa + " rhs " + " 9989 " + " 33 ";
fprintf(stdout, "41) aa.val is :%sEOF\n", aa.val);
aa = " AA value ";
aa = bb + "alkja " + " 99djd " ;
fprintf(stdout, "42) aa.val is :%sEOF\n", aa.val);
aa = " AA value ";
aa = (String) "alkja " + " 99djd " ;
fprintf(stdout, "43) aa.val is :%sEOF\n", aa.val);
aa = " AA value ";
aa += (String) " al dev test kkk... " + " al2 slkj" + " al3333 ";
fprintf(stdout, "44) aa.val is :%sEOF\n", aa.val);
aa = " AA value ";
aa = aa + " add aa " + aa + aa + aa + " 1111 " + " 2222 " + aa + aa + aa + " 3333 ";
fprintf(stdout, "45) aa.val is :%sEOF\n", aa.val);
aa = "12345678";
aa.reverse(true);
fprintf(stdout, "46) aa.val is :%sEOF\n", aa.val);
aa = " AA value ";
aa = aa + " add aa " + aa + 1111 +" "+ 2222 + " " + 3.344 + aa;
fprintf(stdout, "47) aa.val is :%sEOF\n", aa.val);
aa.roundd(123456.0123456789012345, 13);
fprintf(stdout, "48) double aa.val is :%sEOF\n", aa.val);
aa.roundf(123456.0123456789, 13);
fprintf(stdout, "49) float aa.val is :%sEOF\n", aa.val);
// Test equal to operators
aa = " AA value ";
String cc(" AA value ");
if (aa == cc)
fprintf(stdout, "50)aa=%s and cc=%s are equal!!\n", aa.val, cc.val);
else
fprintf(stdout, "51)aa=%s and cc=%s are NOT equal!!\n", aa.val, cc.val);
cc = "CC";
if (aa == cc)
fprintf(stdout, "52)aa=%s and cc=%s are equal!!\n", aa.val, cc.val);
else
fprintf(stdout, "53)aa=%s and cc=%s are NOT equal!!\n", aa.val, cc.val);
if (aa == " AA value ")
fprintf(stdout, "54)aa=%s and string are equal!!\n", aa.val);
else
fprintf(stdout, "55)aa=%s and string are NOT equal!!\n", aa.val);
if (aa == " AA valuexxx ")
fprintf(stdout, "56)aa=%s and string are equal!!\n", aa.val);
else
fprintf(stdout, "57)aa=%s and string are NOT equal!!\n", aa.val);
aa = " AA bb value 12345678 ";
fprintf(stdout, "58) aa.length() is :%ldEOF\n", aa.length());
aa = " AA bb value 12345678 ";
fprintf(stdout, "59) aa.repeat(BA, 4).val=%s aa.val is :%sEOF\n",
aa.repeat("BA", 4).val, aa.val);
aa = "";
aa = "aa";
if (aa.isnull())
fprintf(stdout, "60) aa.isnull() result=true%sEOF\n", aa.val);
else
fprintf(stdout, "60) aa.isnull() result=false%sEOF\n", aa.val);
aa = " some value aa";
aa.clear();
fprintf(stdout, "61) aa.clear() %sEOF\n", aa.val);
aa = " abcd efg hijk lmno ";
fprintf(stdout, "62) aa.token():%s val :%sEOF\n",
aa.token().val, aa.val);
fprintf(stdout, "62) aa.token():%s val :%sEOF\n",
aa.token().val, aa.val);
fprintf(stdout, "62) aa.token():%s val :%sEOF\n",
aa.token().val, aa.val);
fprintf(stdout, "62) aa.token():%s val :%sEOF\n",
aa.token().val, aa.val);
fprintf(stdout, "62) aa.token():%s val :%sEOF\n",
aa.token().val, aa.val);
aa = " 2345 ";
if (aa.is_integer()) // is true
fprintf(stdout, "63) aa is a integer val :%sEOF\n", aa.val);
else
fprintf(stdout, "63) aa is NOT a integer val :%sEOF\n", aa.val);
aa = " 23.045 ";
if (aa.is_numeric()) // is true
fprintf(stdout, "64) aa is a numeric val :%sEOF\n", aa.val);
else
fprintf(stdout, "64) aa is NOT a numeric val :%sEOF\n", aa.val);
aa = " 23045 ";
fprintf(stdout, "65) aa.int_value()=%d val :%sEOF\n",
aa.int_value(), aa.val);
aa = " 230.45 ";
fprintf(stdout, "66) aa.double_value()=%f val :%sEOF\n",
aa.double_value(), aa.val);
aa = " testing abcdefg";
aa.chop();
fprintf(stdout, "68) aa.chop() aa.val is :%sEOF\n", aa.val);
aa = " str1 str2 string3 abcdefg joe john hardy ";
String *strlist;
int strcount = 0;
strlist = aa.explode(strcount);
for (int ii = 0; ii <= strcount; ii++)
{
fprintf(stdout, "69) strlist[%d] is :%sEOF\n",
ii, strlist[ii].val);
}
aa = " some aa ";
cout << "\n\nPlease enter a line and hit return key : ";
aa.getline();
fprintf(stdout, "70) aa.getline() is :%sEOF\n", aa.val);
// You can use aa.val like a 'char *' variable in programs !!
fprintf(stdout, "\n ");
for (unsigned long tmpii = 0; tmpii < aa.length(); tmpii++)
{
fprintf(stdout, "aa.val[%ld]=%c ", tmpii, aa.val[tmpii]);
}
fprintf(stdout, "\n");
// Using pointers on 'char *' val ...
fprintf(stdout, "\n ");
// You must use a temporary local variable and assign the
// pointer to aa.val. If you directly use aa.val and when
// aa.val is incremented with aa.val++, then aa will go
// call destructor and later when aa.val is accessed that
// will cause core dump !!
for (char *tmpcc = aa.val; *tmpcc != 0; tmpcc++)
{
// MUST use temporary var tmpcc !! See note above.
fprintf(stdout, "aa.val=%c ", *tmpcc);
}
fprintf(stdout, "\n");
print_total_memsize(); // in the end
exit(0);
}
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix B String.h<label id="Appendix B">
-->
<sect> Appendix B String.h <label id="Appendix B">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
// To prevent memory leaks - a char class to manage character variables
// Always prefer to use String or string class
// instead of char[] or char *
//
#ifndef __STRING_H_
#define __STRING_H_
//#include <iostream> // do not use iostream as program becomes bulky..
//#include <stdlib.h> // for free() amd malloc()
#include <string.h> // for strcpy()
#include <ctype.h> // for isspace()
#include <stdio.h> // for sprintf()
#include <list.h> // for sprintf()
#include <math.h> // for modf(), rint()
#include "my_malloc.h"
#include "debug.h" // debug_(name, value) debug2_(name, value, LOG_YES)
const short INITIAL_SIZE = 50;
const short NUMBER_LENGTH = 70;
// a small class with a VERY MINIMUM of functions and variables...
// This class to be kept small...
class String
{
public:
String();
String(char bb[]); // needed by operator+
String(int bb); // needed by operator+
String(unsigned long bb); // needed by operator+
String(float bb); // needed by operator+
String(double bb); // needed by operator+
String(const String & rhs); // Copy Constructor needed by operator+
~String();
char *val;
// Functions below imitate Java language's String object
unsigned long length() { return strlen(val); }
char charAt(int where);
void getChars(int sourceStart, int sourceEnd,
char target[], int targetStart);
char* toCharArray();
bool equals(String str2); // See also == operator
bool equals(char *str2); // See also == operator
bool equalsIgnoreCase(String str2);
bool regionMatches(int startIndex, String str2,
int str2StartIndex, int numChars);
bool regionMatches(bool ignoreCase, int startIndex,
String str2, int str2StartIndex, int numChars);
String toUpperCase();
String toLowerCase();
bool startsWith(String str2);
bool startsWith(char *str2);
bool endsWith(String str2);
bool endsWith(char *str2);
int compareTo(String str2);
int compareTo(char *str2);
int compareToIgnoreCase(String str2);
int compareToIgnoreCase(char *str2);
int indexOf(char ch, int startIndex = 0);
int indexOf(char *str2, int startIndex = 0);
int indexOf(String str2, int startIndex = 0);
int lastIndexOf(char ch, int startIndex = 0);
int lastIndexOf(char *str2, int startIndex = 0);
int lastIndexOf(String str2, int startIndex = 0);
String substring(int startIndex, int endIndex = 0);
String replace(char original, char replacement);
String replace(char *original, char *replacement);
String trim(); // See also overloaded trim()
String concat(String str2); // See also operator +
String concat(char *str2); // See also operator +
String append(String str2) {return concat(str2);} // See also operator +
String append(char *str2) {return concat(str2);} // See also operator +
String append(int bb) {return (*this + bb);} // See also operator +
String append(unsigned long bb) {return (*this + bb);} // See also operator +
String append(float bb) {return (*this + bb);} // See also operator +
String insert(int index, String str2);
String insert(int index, char ch);
String reverse(); // See also overloaded reverse()
String deleteCharAt(int loc);
String deleteStr(int startIndex, int endIndex); // Java's "delete()"
// ---- End of Java like String object functions -----
// These are additional functions which are not
// available in Java's String object...
void reverse(bool dummy); // dummy to get different signature
void trim(bool dummy); // dummy to get different signature
String ltrim();
void ltrim(bool dummy); // dummy to get different signature
String rtrim();
void rtrim(bool dummy); // dummy to get different signature
void chopall(char ch='\n'); // removes trailing character 'ch'
void chop(); // removes one trailing character
void roundf(float input_val, short precision);
void decompose_float(long *integral, long *fraction);
void roundd(double input_val, short precision);
void decompose_double(long *integral, long *fraction);
void explode(char *seperator); // see also token() and overloaded explode()
String *explode(int & strcount, char seperator = ' '); // see also token()
void implode(char *glue);
void join(char *glue);
String repeat(char *input, unsigned int multiplier);
String tr(char *from, char *to); // translate characters
String center(int padlength, char padchar = ' ');
String space(int number = 0, char padchar = ' ');
String xrange(char start, char end);
String compress(char *list = " ");
String insert(char *newstr, int start = 0, int length = 0, char padchar = ' ');
String left(int slength = 0, char padchar = ' ');
String right(int slength = 0, char padchar = ' ');
String overlay(char *newstr, int start = 0, int slength = 0, char padchar = ' ');
String at(char *regx); // matches first match of regx
String before(char *regx); // returns string before regx
String after(char *regx); // returns string after regx
String mid(int startIndex = 0, int length = 0);
bool isnull();
void clear();
bool is_integer();
bool is_numeric();
int int_value();
double double_value();
String token(char seperator = ' '); // see also explode()
String crypt(char *original, char *salt);
String getline(FILE *infp = stdin);
///////////////////////////////////////////////
// List of duplicate function names
///////////////////////////////////////////////
// bool find(); // Use regionMatches()
// bool search(); // Use regionMatches()
// bool matches(); // Use regionMatches()
// int rindex(String str2, int startIndex = 0); Use lastIndexOf()
// String blanks(int slength); // Use repeat()
// String prepend(String str2); // Use + operator. See also append()
// String split(char seperator = ' '); // Use token()
bool contains(char *str2, int startIndex = 0); // use indexOf()
// void empty(); Use clear()
// void vacuum(); Use clear()
// bool is_float(); Use is_numeric();
// bool is_decimal(); Use is_numeric();
// double float_value(); Use double_value();
// double numeric_value(); Use double_value();
// All Operators ...
String operator+ (const String & rhs);
friend String operator+ (const String & lhs, const String & rhs);
String& operator+= (const String & rhs); // using reference will be faster
String& operator= (const String & rhs); // using reference will be faster
bool operator== (const String & rhs); // using reference will be faster
bool operator== (const char *rhs);
bool operator!= (const String & rhs);
bool operator!= (const char *rhs);
static list<String> explodeH; // list head
private:
//static String *global_String; // for use in add operator
//inline void free_glob(String **aa);
void str_cpy(char bb[]);
void str_cpy(int bb); // itoa
void str_cpy(unsigned long bb);
void str_cpy(float bb); // itof
void str_cat(char bb[]);
void str_cat(int bb);
void str_cat(unsigned long bb);
void str_cat(float bb);
bool equalto(const String & rhs, bool type = false);
bool equalto(const char *rhs, bool type = false);
String *pString; // temporary pointer for internal use..
inline void allocpString();
};
// Global variables are defined in String.cpp
#endif // __STRING_H_
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix C String.cpp<label id="Appendix C">
-->
<sect> Appendix C String.cpp <label id="Appendix C">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
// Use string class or this class
// To prevent memory leaks - a char class to manage character variables
// Always prefer to use string class
// instead of char[] or char *
//
// To compile and test this program do -
// g++ String.cpp
#include "String.h"
// Global variables ....
//String *String::global_String = NULL; // global var
list<String> String::explodeH;
String::String()
{
debug_("In cstr()", "ok");
val = (char *) my_malloc(sizeof(char)* INITIAL_SIZE);
pString = NULL;
}
String::String(char *bb)
{
unsigned long tmpii = strlen(bb);
val = (char *) my_malloc(sizeof(char)* tmpii);
strncpy(val, bb, tmpii);
val[tmpii] = '\0';
//debug_("In cstr(char *bb) bb", bb);
//debug_("In cstr(char *bb) val", val);
#ifdef DEBUG
//fprintf(stderr, "\nAddress of val=%x\n", & val);
//fprintf(stderr, "\nAddress of this-pointer=%x\n", this);
#endif // DEBUG
pString = NULL;
}
String::String(int bb)
{
val = (char *) my_malloc(NUMBER_LENGTH); // integers 70 digits max
sprintf(val, "%d", bb);
pString = NULL;
}
String::String(unsigned long bb)
{
val = (char *) my_malloc(NUMBER_LENGTH); // long 70 digits max
sprintf(val, "%lu", bb);
pString = NULL;
}
String::String(float bb)
{
val = (char *) my_malloc(NUMBER_LENGTH); // float 70 digits max
sprintf(val, "%f", bb);
pString = NULL;
}
String::String(double bb)
{
val = (char *) my_malloc(NUMBER_LENGTH); // double 70 digits max
sprintf(val, "%f", bb);
pString = NULL;
}
// Copy Constructor needed by operator +
String::String(const String & rhs)
{
// Do a deep-copy instead of compiler's default shallow copy copy-cstr
debug_("In copy-cstr()", "ok");
unsigned long tmpii = strlen(rhs.val);
val = (char *) my_malloc(sizeof(char)* tmpii);
strncpy(val, rhs.val, tmpii);
val[tmpii] = '\0';
pString = NULL;
}
String::~String()
{
//debug_("In dstr val", val);
#ifdef DEBUG
//fprintf(stderr, "\nAddress of val=%x\n", & val);
//fprintf(stderr, "\nAddress of this-pointer=%x\n", this);
#endif // DEBUG
my_free(val);
//delete [] val;
val = NULL;
delete pString; pString = NULL;
}
inline void String::allocpString()
{
// pString will be deleted in destructor
if (!pString) // if (pString == NULL)
pString = new String(this->val);
else
*pString = this->val;
}
// MUST use pointer-to-pointer **aa, otherwise the argument
// is NOT freed !!
/*
inline void String::free_glob(String **aa)
{
debug_("called free_glob()", "ok" );
if (*aa != NULL) // (*aa != NULL)
{
debug_("*aa is not null", "ok");
delete *aa;
*aa = NULL;
}
//else
debug_("*aa is null", "ok");
//if (*aa == NULL)
debug_("*aa set to null", "ok");
}
*/
// Imitating Java's charAt string function...
char String::charAt(int where)
{
if (where <= (int) length() )
return (val[where]);
else
return 0;
}
// Imitate Java's getChars function...
// The sourceStart specifies the index of the beginning of the substring
// and sourceEnd specifies an index that is one past the end of desired
// substring. Thus the substring contains characters from sourceStart
// through (sourceEnd - 1). The array that will receive the characters
// is specified by target. The index within target at which the substring
// will be copied is passed in targetStart. Care must be taken to assure
// that the target array is large enough to hold the number of characters
// in the specified substring.
// For e.g. getChars(3, 6, aa, 0) on "ABCDEFGHIJK" gives aa ="DEF"
void String::getChars(int sourceStart, int sourceEnd, char target[], int targetStart)
{
if (sourceEnd >= sourceStart)
{
if (sourceEnd > (int) (length() - 1) )
sourceEnd = (int) length() - 1;
strncpy(& target[targetStart], & val[sourceStart], sourceEnd - sourceStart);
target[targetStart + (sourceEnd - sourceStart)] = 0;
}
else
{
cerr << "\nSourceEnd is greater than SourceStart!!\n" << endl;
}
}
// Imitate Java's getChars string function...
// Returns array of characters for the entire string
char* String::toCharArray()
{
return (val);
}
// Imitate Java's equals string function...
bool String::equals(String str2) // See also == operator
{
return ( equalto(str2.val));
}
// Imitate Java's equals string function...
bool String::equals(char *str2) // See also == operator
{
return ( equalto(str2));
}
// Imitate Java's equalsIgnoreCase string function...
bool String::equalsIgnoreCase(String str2)
{
String aa, bb;
aa = this->toLowerCase();
bb = str2.toLowerCase();
return ( aa.equalto(bb.val) );
}
// Imitate Java's regionMatches string function...
// The startIndex specifies the index at which the region begins within
// the invoking String object. The string being compared is str2. The
// index at which comparison will start within str2 is specified by
// str2Index. The length of the substring being compared is numChars.
bool String::regionMatches(int startIndex, String str2, int str2StartIndex, int numChars)
{
if (startIndex > (int) length())
{
cerr << "\nstartIndex greater than length of string\n" << endl;
return false;
}
if (str2StartIndex > (int) str2.length())
{
cerr << "\nstr2StartIndex of string2 greater than length of string\n" << endl;
return false;
}
if (strncmp(& this->val[startIndex], & str2.val[str2StartIndex], numChars) == 0)
return true;
else
return false;
}
// Imitate Java's regionMatches string function...
// This is overloaded function of regionMatches
// If ignoreCase is true, the case of the characters is ignored, otherwise
// case is significant (i.e. if ignoreCase is true then ignore the
// case and compare)
// The startIndex specifies the index at which the region begins within
// the invoking String object. The string being compared is str2. The
// index at which comparison will start within str2 is specified by
// str2Index. The length of the substring being compared is numChars.
bool String::regionMatches(bool ignoreCase, int startIndex, String str2, int str2StartIndex, int numChars)
{
if (ignoreCase) // if (ignoreCase == true)
{
if (startIndex > (int) length())
{
cerr << "\nstartIndex greater than length of string\n" << endl;
return false;
}
if (str2StartIndex > (int) str2.length())
{
cerr << "\nstr2StartIndex of string2 greater than length of string\n" << endl;
return false;
}
String string1, string2;
string1 = this->toLowerCase();
string2 = str2.toLowerCase();
if (strncmp(& string1.val[startIndex], & string2.val[str2StartIndex], numChars) == 0)
return true;
else
return false;
}
else
{
return regionMatches(startIndex, str2, str2StartIndex, numChars);
}
}
// Imitate Java's toLowerCase string function...
// String ss("sometest");
// String egg = ss.toLowerCase();
String String::toLowerCase()
{
allocpString();
for (long tmpii = strlen(pString->val); tmpii >= 0; tmpii--)
{
pString->val[tmpii] = tolower(pString->val[tmpii]);
}
return *pString; // return the object now
}
// Imitate Java's toUpperCase string function...
// String ss("sometest");
// String egg = ss.toUpperCase();
String String::toUpperCase()
{
allocpString();
for (long tmpii = strlen(pString->val); tmpii >= 0; tmpii--)
{
pString->val[tmpii] = toupper(pString->val[tmpii]);
}
return *pString; // return the object now
}
// Imitate Java's startsWith string function...
bool String::startsWith(String str2)
{
if (!strncmp(this->val, str2.val, str2.length() )) // if (strncmp() == 0)
return true;
else
return false;
}
// Imitate Java's startsWith string function...
// overloaded function
bool String::startsWith(char *str2)
{
int lenstr2 = strlen(str2);
if (!strncmp(this->val, str2, lenstr2)) // if (strncmp() == 0)
return true;
else
return false;
}
// Imitate Java's endsWith string function...
bool String::endsWith(String str2)
{
// string length of str2 should be less than current string
if (str2.length() > length())
return false;
if (!strncmp(& this->val[length() - str2.length()], str2.val, str2.length() )) // if (strncmp() == 0)
return true;
else
return false;
}
// Imitate Java's endsWith string function...
bool String::endsWith(char *str2)
{
// string length of str2 should be less than current string
if (strlen(str2) > length())
return false;
if (!strncmp(& this->val[length() - strlen(str2)], str2, strlen(str2) ) ) // if (strncmp() == 0)
return true;
else
return false;
}
// Imitate Java's compareTo string function...
// For sorting applications, you need to know which is less than, equal to
// or greater than the next.
// A string is less than another if it comes before the other in dictionary
// order. A string is greater than another if it comes after the other in
// dictionary order.
// Less than zero --> The invoking string is less than str2
// Greater than zero --> The invoking string is greater than str2
// Zero --> The two strings are equal.
int String::compareTo(String str2)
{
int flag = 0;
// Compare letters in string to each letter in str2
for (int tmpii = 0, tmpjj = length(), tmpkk = str2.length(); tmpii < tmpjj; tmpii++)
{
if (tmpii > tmpkk)
break;
if (val[tmpii] == str2.val[tmpii])
flag = 0;
else
if (val[tmpii] > str2.val[tmpii])
{
flag = 1;
break;
}
else // if (val[tmpii] < str2.val[tmpii])
{
flag = -1;
break;
}
}
return flag;
}
// Imitate Java's compareTo string function...
// Overloaded function of compareTo
int String::compareTo(char *str2)
{
int flag = 0;
// Compare letters in string to each letter in str2
for (int tmpii = 0, tmpjj = length(), tmpkk = strlen(str2); tmpii < tmpjj; tmpii++)
{
if (tmpii > tmpkk)
break;
if (val[tmpii] == str2[tmpii])
flag = 0;
else
if (val[tmpii] > str2[tmpii])
{
flag = 1;
break;
}
else // if (val[tmpii] < str2[tmpii])
{
flag = -1;
break;
}
}
return flag;
}
// Imitate Java's compareToIgnoreCase string function...
int String::compareToIgnoreCase(String str2)
{
String tmpaa = this->toLowerCase(),
tmpbb = str2.toLowerCase();
return tmpaa.compareTo(tmpbb);
}
// Imitate Java's compareToIgnoreCase string function...
// Overloaded function
int String::compareToIgnoreCase(char *str2)
{
String tmpaa = this->toLowerCase(),
tmpcc(str2), tmpbb = tmpcc.toLowerCase();
return tmpaa.compareTo(tmpbb);
}
// Imitate Java's indexOf string function...
// Searches for the first occurence of a character or string
// Return the index at which the character or substring was
// found, or -1 on failure.
int String::indexOf(char ch, int startIndex = 0)
{
int ii = startIndex;
for (; ii < (int) length(); ii++)
{
if (val[ii] == ch)
break;
}
if (ii == (int) length())
return -1;
return ii;
}
// Imitate Java's indexOf string function...
// Overloaded function
int String::indexOf(char *str2, int startIndex = 0)
{
char * tok;
long res = -1;
if ( !isnull() && (startIndex < (int) strlen(val) ) )
{
tok = strstr(val + startIndex, str2);
if (tok == NULL)
res = -1;
else
res = (int) (tok - val);
}
return res;
}
// Imitate Java's indexOf string function...
// Overloaded function
int String::indexOf(String str2, int startIndex = 0)
{
char * tok;
long res = -1;
if ( !isnull() && (startIndex < (int) strlen(val) ) )
{
tok = strstr(val + startIndex, str2.val);
if (tok == NULL)
res = -1;
else
res = (int) (tok - val);
}
return res;
}
// Imitate Java's lastIndexOf string function...
// Searches for the last occurence of a character or string
// Return the index at which the character or substring was
// found, or -1 on failure.
int String::lastIndexOf(char ch, int startIndex = 0)
{
int ii;
// Begin search from the last character of string
if (!startIndex) // if (startIndex == 0)
ii = length();
else
ii = startIndex;
for (; ii > -1; ii--)
{
if (val[ii] == ch)
break;
}
if (!ii && val[ii] != ch) // if (ii == 0)
return -1;
return ii;
}
// Imitate Java's lastIndexOf string function...
// Overloaded function
int String::lastIndexOf(char *str2, int startIndex = 0)
{
char *tok = NULL;
int res = -1;
register char *tmpaa = strdup(val); // malloc here
if (!tmpaa) // tmpaa == NULL
{
cerr << "\nMemory alloc failed in strdup in lastIndexOf()\n" << endl;
exit(-1);
}
if (!startIndex) // if (startIndex == 0)
startIndex = strlen(val);
else
tmpaa[startIndex+1] = 0;
for (int ii = 0; ii <= startIndex; ii++)
{
tok = strstr(& tmpaa[ii], str2);
if (tok == NULL)
break;
else
{
res = (int) (tok - tmpaa);
debug_("res", res);
ii = res; // jump to where it matched (+1 in for loop)
}
}
free(tmpaa);
debug_("res", res);
debug_("indexOf", & val[res]);
return res;
}
// Imitate Java's lastIndexOf string function...
// Overloaded function
int String::lastIndexOf(String str2, int startIndex = 0)
{
char *tok = NULL;
int res = -1;
register char *tmpaa = strdup(val); // malloc here
if (!tmpaa) // tmpaa == NULL
{
cerr << "\nMemory alloc failed in strdup in lastIndexOf()\n" << endl;
exit(-1);
}
if (!startIndex) // if (startIndex == 0)
startIndex = strlen(val);
else
tmpaa[startIndex+1] = 0;
for (int ii = 0; ii <= startIndex; ii++)
{
tok = strstr(& tmpaa[ii], str2.val);
if (tok == NULL)
break;
else
{
res = (int) (tok - tmpaa);
debug_("res", res);
ii = res; // jump to where it matched (+1 in for loop)
}
}
free(tmpaa);
debug_("res", res);
debug_("indexOf", & val[res]);
return res;
}
// Imitate Java's substring string function...
// The startIndex specifies the beginning index, and endIndex specifies
// the stopping point. The string returned contains all the characters
// from the beginning index, up to, but not including, the ending index.
String String::substring(int startIndex, int endIndex = 0)
{
if (!endIndex) // endIndex == 0
return(String(& val[startIndex] ) );
else
{
String tmp = String(& val[startIndex] );
tmp.val[endIndex -1] = 0;
return(tmp);
}
}
// Imitate Java's concat string function...
String String::concat(String str2)
{
return (*this + str2);
}
// Imitate Java's concat string function...
// overloaded function
String String::concat(char *str2)
{
return (*this + str2);
}
// Imitate Java's replace string function...
// Replace all occurences of string 'original' with
// 'replacement' in 'val'
String String::replace(char original, char replacement)
{
// For example -
// replace('A', 'B') on val = "some AAA and AAACC"
// reurns val = "some BBB and BBBCC"
//String *tmpstr = new String(val); Use default copy cstr
String tmpstr(val);
for (int ii = 0, len = length(); ii < len; ii++)
{
if (tmpstr.val[ii] == original)
tmpstr.val[ii] = replacement;
}
return tmpstr; // this will use copy constructor to make a default copy
}
// Imitate Java's replace string function...
// overloaded function
// Replace all occurences of string 'original' with
// 'replacement' in 'val'
String String::replace(char *original, char *replacement)
{
char *tok = NULL, *bb;
register char *aa = strdup(val);
int lenrepl = strlen(replacement);
// Allocate space for bb
{ // local scope
int tmpii = 0;
for (int ii = 0; ;ii++)
{
tok = strstr(& aa[ii], original);
if (tok == NULL)
break;
else
{
ii = ii + (int) (tok -aa);
tmpii++;
}
}
if (!tmpii) // tmpii == 0, no match of 'original' found
return (String(val)); // return original string
tmpii = length() + (tmpii * lenrepl) + 20;
debug_("strstr tmpii", tmpii );
bb = (char *) malloc(tmpii);
memset(bb, 0, tmpii);
}
for (int res = -1; ;)
{
debug_("aa", aa);
tok = strstr(aa, original);
if (tok == NULL)
{
strcat(bb, aa);
break;
}
else
{
res = (int) (tok - aa);
strncat(bb, aa, res);
strcat(bb, replacement);
//bb[strlen(bb)] = 0;
debug_("res", res );
debug_("bb", bb );
strcpy(aa, & aa[res+lenrepl]);
}
}
debug_("bb", bb );
free(aa);
String tmpstr(bb);
free(bb);
return tmpstr;
}
/*
another method of doing replace function but slow..
String String::replace(char *original, char *replacement)
{
// For example -
// replace("AAA", "BB") on val = "some AAA and AAACC"
// reurns val = "some BB and BBCC"
String bb(this->before(original).val);
if (bb.length() == 0)
return String(val); // return original string
bb += replacement;
String tmpaa(this->val), cc, dd;
for (;;)
{
cc = tmpaa.after(original).val;
debug_("cc", cc.val );
if (!cc.length()) // if (cc.length() == 0)
break;
dd = cc.before(original).val;
if (dd.length() == 0)
{
bb += cc;
break;
}
else
{
bb += dd;
bb += replacement;
}
tmpaa = cc;
}
debug_("bb.val", bb.val );
return bb;
}
*/
// Imitate Java's trim string function...
String String::trim()
{
//String *tmpstr = new String(val);
String tmpstr(val);
tmpstr.rtrim(true);
tmpstr.ltrim(true);
debug_("tmpstr.val", tmpstr.val);
return tmpstr; // this will use copy constructor to make a default copy
}
// Imitate Java's insert string function...
String String::insert(int index, String str2)
{
String tmpstr(this->insert(str2.val, index).val);
debug_("tmpstr.val", tmpstr.val);
return tmpstr;
}
// Imitate Java's insert string function...
String String::insert(int index, char ch)
{
char aa[2];
aa[0] = ch;
aa[1] = 0;
String tmpstr(this->insert(aa, index).val);
debug_("tmpstr.val", tmpstr.val);
return tmpstr;
}
// Imitate Java's deleteCharAt string function...
String String::deleteCharAt(int loc)
{
char *tmpaa = strdup(val); // malloc here
strcpy(& tmpaa[loc], & tmpaa[loc+1]);
String tmpstr(tmpaa);
free(tmpaa);
return tmpstr;
}
// Imitate Java's delete string function...
// Note: -->Java name is "delete()", cannot use reserved name delete() in C++
// The startIndex specifies the index of the first character to remove,
// and endIndex specifies an index one past the last character to remove.
// Thus, the substring deleted runs from startIndex to (endIndex - 1)
String String::deleteStr(int startIndex, int endIndex)
{
// For example -
// deleteStr(3,3) on val = 'pokemon' returns 'poon'
char *tmpaa = strdup(val); // malloc here
strcpy(& tmpaa[startIndex], & tmpaa[endIndex]);
String tmpstr(tmpaa);
free(tmpaa);
return tmpstr;
}
// Imitate Java's reverse string function...
String String::reverse()
{
// For example -
// reverse() on "12345" returns "54321"
String tmpstr(val);
char aa;
unsigned long tot_len = length();
unsigned long midpoint = tot_len / 2;
for (unsigned long tmpjj = 0; tmpjj < midpoint; tmpjj++)
{
aa = tmpstr.val[tmpjj]; // temporary storage var
tmpstr.val[tmpjj] = tmpstr.val[tot_len - tmpjj - 1]; // swap the values
tmpstr.val[tot_len - tmpjj - 1] = aa; // swap the values
}
return tmpstr;
}
// ---- End of Java like String object functions -----
// Returns string before regx. Matches first occurence of regx
String String::at(char *regx)
{
char *tok = NULL;
tok = strstr(val, regx);
if (tok == NULL)
return(String(""));
else
{
int res = (int) (tok - val);
char *lefttok = strdup(val);
memset(lefttok, 0, length());
strcpy(lefttok, & val[res]);
String tmpstr(lefttok);
free(lefttok);
return(tmpstr);
}
}
// Returns string before regx. Matches first occurence of regx
String String::before(char *regx)
{
char *tok = NULL;
tok = strstr(val, regx);
if (tok == NULL)
return(String(""));
else
{
int res = (int) (tok - val);
char *lefttok = strdup(val);
lefttok[res] = 0;
String tmpstr(lefttok);
free(lefttok);
return(tmpstr);
}
}
// Returns string after regx. Matches first occurence of regx
String String::after(char *regx)
{
char *tok = NULL;
tok = strstr(val, regx);
if (tok == NULL)
return(String(""));
else
{
int res = (int) (tok - val);
char *lefttok = strdup(val);
memset(lefttok, 0, length());
strcpy(lefttok, & val[res + strlen(regx)]);
String tmpstr(lefttok);
free(lefttok);
return(tmpstr);
}
}
// Explodes the string and returns the list in
// the list-head pointer explodeH
// See also token()
void String::explode(char *seperator)
{
char *aa = NULL, *bb = NULL;
aa = (char *) my_malloc(length());
for (bb = strtok(aa, seperator); bb != NULL; bb = strtok(NULL, seperator) )
{
String *tmp = new String(bb);
String::explodeH.insert(String::explodeH.end(), *tmp);
}
my_free(aa);
list<String>::iterator iter1; // see file include/g++/stl_list.h
debug_("Before checking explode..", "ok");
if (String::explodeH.empty() == true )
{
debug_("List is empty!!", "ok");
}
for (iter1 = String::explodeH.begin(); iter1 != String::explodeH.end(); iter1++)
{
if (iter1 == NULL)
{
debug_("Iterator iter1 is NULL!!", "ok" );
break;
}
debug_("(*iter1).val", (*iter1).val);
}
}
// Overloaded function of explode(). This will return an
// array of strings and total number in strcount reference
// variable.
// See also token()
String *String::explode(int & strcount, char seperator = ' ')
{
String aa(val);
aa.trim(true);
strcount = 0;
for (int ii = 0, jj = aa.length(); ii < jj; ii++)
{
if (aa.val[ii] == seperator)
strcount++;
}
String *tmpstr = new String[strcount+1];
if (!strcount) // strcount == 0
tmpstr[0] = aa.val;
else
{
for (int ii = 0; ii <= strcount; ii++)
tmpstr[ii] = aa.token();
}
return tmpstr;
}
// Implodes the strings in the list-head
// pointer explodeH and returns the String class
void String::implode(char *glue)
{
}
// Joins the strings in the list-head
// pointer explodeH and returns the String class
void String::join(char *glue)
{
implode(glue);
}
// Repeat the input string n times
String String::repeat(char *input, unsigned int multiplier)
{
// For example -
// repeat("k", 4) returns "kkkk"
if (!input) // input == NULL
{
return (String(""));
}
char *aa = (char *) my_malloc(strlen(input) * multiplier);
for (unsigned int tmpii = 0; tmpii < multiplier; tmpii++)
{
strcat(aa, input);
}
String tmpstr(aa);
my_free(aa);
return tmpstr;
}
// Reverse the string
// Overloaded version of reverse(). This will directly
// change the object.
void String::reverse(bool dummy)
{
// For example -
// reverse() on "12345" returns "54321"
char aa;
unsigned long tot_len = length();
unsigned long midpoint = tot_len / 2;
for (unsigned long tmpjj = 0; tmpjj < midpoint; tmpjj++)
{
aa = val[tmpjj]; // temporary storage var
val[tmpjj] = val[tot_len - tmpjj - 1]; // swap the values
val[tot_len - tmpjj - 1] = aa; // swap the values
}
}
// Translate certain chars
// For e.g ("abcd", "ABC") translates all occurences of each
// character in 'from' to corresponding character in 'to'
String String::tr(char *from, char *to)
{
int lenfrom = strlen(from), lento = strlen(to);
if (lento > lenfrom)
lento = lenfrom; // set it to least
else
if (lento < lenfrom)
lenfrom = lento; // set it to least
debug_("lento", lento);
register char *aa = strdup(val);
for (int ii = 0, jj = length(); ii < jj; ii++) // for every char in val
{
for (int kk = 0; kk < lento; kk++) // for every char in "from" string
{
if (aa[ii] == from[kk])
aa[ii] = to[kk];
}
}
String tmpstr(aa);
free(aa);
return tmpstr;
}
// Center the text
String String::center(int padlength, char padchar = ' ')
{
// For example -
// center(10, '*') on val="aa" returns "****aa****"
// center(10) on val="aa" returns " aa "
// The result is a string of 'padlength' characters with val centered in it.
int tmpii = sizeof(char) * (padlength + length() + 10);
char *aa = (char *) malloc(tmpii);
memset(aa, 0, tmpii);
for (int jj = 0, kk = (int) padlength/2; jj < kk; jj++)
{
aa[jj] = padchar;
}
strcat(aa, val);
for (int jj = strlen(aa), kk = jj + (int) padlength/2; jj < kk; jj++)
{
aa[jj] = padchar;
}
String tmpstr(aa);
free(aa);
return tmpstr;
}
// Formats the original string by placing <number> of <padchar> characters
// between each set of blank-delimited words. Leading and Trailing blanks
// are always removed. If <number> is omitted or is 0, then all spaces are
// in the string are removed. The default number is 0 and
// default padchar ' '
String String::space(int number, char padchar = ' ')
{
// For example -
// space(3) on val = "I do not know"
// will return "I do not know"
// space(1, '_') on val = "A deep black space"
// will return "A_deep_black_space"
// space() on val = "I know this"
// will return "Iknowthis"
debug_("this->val", this->val );
String tmpstr = this->trim().val;
debug_("tmpstr.val", tmpstr.val );
// count spaces
int spacecount = 0;
for (int ii = 0, jj = tmpstr.length(); ii < jj; ii++)
{
if (tmpstr.val[ii] == ' ')
spacecount++;
}
debug_("spacecount", spacecount);
char ee[2];
ee[0] = padchar;
ee[1] = 0;
String bb = tmpstr.repeat(ee, spacecount);
int tmpii = sizeof(char) * (tmpstr.length() + (number * spacecount) + 20);
char *aa = (char *) malloc(tmpii);
memset(aa, 0, tmpii);
for (int ii = 0, jj = tmpstr.length(); ii < jj; ii++)
{
if (tmpstr.val[ii] == ' ')
strcat(aa, bb.val);
else
{
ee[0] = val[ii];
strcat(aa, ee);
}
}
tmpstr = aa;
free(aa);
return tmpstr;
}
// The result is string comprised of all characters between
// and including <start> and <end>
String String::xrange(char start, char end)
{
// For example -
// xrange('a', 'j') returns val = "abcdefghij"
// xrange(1, 8) returns val = "12345678"
if (end < start)
{
cerr << "\nThe 'end' character is less than 'start' !!" << endl;
return String("");
}
// Note: The 'end' is greater than 'start'!! And add +1
int tmpii = sizeof(char) * (end - start + 11);
char *aa = (char *) malloc(tmpii);
memset(aa, 0, tmpii);
debug_("xrange tmpii", tmpii);
for (int ii = start, jj = 0; ii <= end; ii++, jj++)
{
aa[jj] = ii;
debug_("xrange aa[jj]", aa[jj] );
}
String tmpstr(aa);
free(aa);
return tmpstr;
}
// Removes any characters contained in <list>. The default character
// for <list> is a blank ' '
String String::compress(char *list = " ")
{
// For example -
// compress("$,%") on val = "$1,934" returns "1934"
// compress() on val = "call me alavoor vasudevan" returns "callmealavoorvasudevan"
int lenlist = strlen(list);
register char *aa = strdup(val);
for (int ii = 0, jj = length(); ii < jj; ii++) // for every char in val
{
for (int kk = 0; kk < lenlist; kk++) // for every char in "from" string
{
if (aa[ii] == list[kk])
{
strcpy(& aa[ii], & aa[ii+1]);
}
}
}
String tmpstr(aa);
free(aa);
return tmpstr;
}
// The <newstr> is inserted into val beginning at <start>. The <newstr> will
// be padded or truncated to <length> characters. The default <length> is
// string length of newstr
String String::insert(char *newstr, int start = 0, int lengthstr = 0, char padchar = ' ')
{
// For example -
// insert("something new", 4, 20, '*') on val = "old thing"
// returns "old something new*******thing"
int tmplen = sizeof(char) * length() + strlen(newstr) + lengthstr + 10;
char *tmpaa = (char *) malloc (tmplen);
memset(tmpaa, 0, tmplen);
if (!start) // start == 0
{
strcpy(tmpaa, newstr);
strcat(tmpaa, this->val);
}
else
{
strncpy(tmpaa, this->val, start);
strcat(tmpaa, newstr);
strcat(tmpaa, & this->val[start]);
}
String tmpstr(tmpaa);
free(tmpaa);
return tmpstr;
}
// The result is string of <length> chars madeup of leftmost chars in val.
// Quick way to left justify a string.
String String::left(int slength = 0, char padchar = ' ')
{
// For example -
// left(15) on val = "Wig" returns "Wig "
// left(4) on val = "Wighat" returns "Wigh"
// left() on val = " Wighat" returns "Wighat "
if (!slength) // slength == 0
slength = length();
debug_("left() slength", slength);
int tmpii = slength + 20;
char *aa = (char *) malloc(tmpii);
memset(aa, 0, tmpii);
debug_("this->ltrim().val ", this->ltrim().val);
strcpy(aa, this->ltrim().val);
debug_("left() aa", aa );
int currlen = strlen(aa);
if (currlen < slength)
{
// pad the string now
char ee[2];
ee[0] = padchar;
ee[1] = 0;
strcat(aa, this->repeat(ee, (unsigned int) (slength-currlen) ).val);
}
else
{
aa[slength] = 0;
}
debug_("left() aa", aa );
String tmpstr(aa);
free(aa);
return tmpstr;
}
// The result is string of <length> chars madeup of rightmost chars in val.
// Quick way to right justify a string.
String String::right(int slength = 0, char padchar = ' ')
{
// For example -
// right(10) on val = "never to saying " returns " to saying"
// right(4) on val = "Wighat" returns "ghat"
// right(8) on val = "4.50" returns " 4.50"
// right() on val = " 4.50 " returns " 4.50"
if (!slength) // slength == 0
slength = length();
debug_("right() slength", slength);
int tmpii = slength + 20;
char *aa = (char *) malloc(tmpii);
memset(aa, 0, tmpii);
int currlen = this->rtrim().length();
debug_("right() currlen", currlen );
if (currlen < slength)
{
// pad the string now
char ee[2];
ee[0] = padchar;
ee[1] = 0;
strcpy(aa, this->repeat(ee, (unsigned int) (slength-currlen) ).val);
strcat(aa, this->rtrim().val);
debug_("right() aa", aa );
}
else
{
strcpy(aa, this->rtrim().val);
strcpy(aa, & aa[currlen-slength]);
aa[slength] = 0;
}
debug_("right() aa", aa );
String tmpstr(aa);
free(aa);
return tmpstr;
}
// The <newstr> is overlayed into val beginning at <start>. The <newstr> will
// be padded or truncated to <length> characters. The default <length> is
// string length of newstr
String String::overlay(char *newstr, int start = 0, int slength = 0, char padchar = ' ')
{
// For example -
// overlay("12345678", 4, 10, '*') on val = "oldthing is very bad"
// returns "old12345678**ery bad"
// overlay("12345678", 4, 5, '*') on val = "oldthing is very bad"
// returns "old12345ery bad"
int len_newstr = strlen(newstr);
if (!slength) // slength == 0
slength = len_newstr;
char *aa = (char *) malloc(slength + len_newstr + 10);
aa[0] = 0;
char ee[2];
ee[0] = padchar;
ee[1] = 0;
if (len_newstr < slength)
{
// pad it now
strcpy(aa, newstr);
strcat(aa, this->repeat(ee, (slength-len_newstr)).val );
}
else
{
strcpy(aa, newstr);
aa[slength] = 0;
}
// Now overlay the string.
String tmpstr(val);
debug_("tmpstr.val", tmpstr.val);
for (int ii=start, jj=tmpstr.length(), kk=start+slength, mm=0;
ii < jj; ii++, mm++)
{
if (ii == kk)
break;
if (mm == slength)
break;
tmpstr.val[ii] = aa[mm];
}
free(aa);
debug_("tmpstr.val", tmpstr.val);
return tmpstr;
}
// If string is literrally equal to .. or not equal to
// If type is false than it is ==
bool String::equalto(const String & rhs, bool type = false)
{
if (type == false) // test for ==
{
if (strlen(rhs.val) == length())
{
if (!strncmp(rhs.val, val, length())) // == 0
return true;
else
return false;
}
else
return false;
}
else // test for !=
{
if (strlen(rhs.val) != length())
{
if (!strncmp(rhs.val, val, length())) // == 0
return true;
else
return false;
}
else
return false;
}
}
// If string is literrally equal to .. or not equal to
// If type is false than it is ==
bool String::equalto(const char *rhs, bool type = false)
{
if (type == false) // test for ==
{
if (strlen(rhs) == length())
{
if (!strncmp(rhs, val, length())) // == 0
return true;
else
return false;
}
else
return false;
}
else // test for !=
{
if (strlen(rhs) != length())
{
if (!strncmp(rhs, val, length())) // == 0
return true;
else
return false;
}
else
return false;
}
}
// Synonym function is empty()
bool String::isnull()
{
if (val[0] == '\0')
return true;
else
{
if (val == NULL)
return true;
else
return false;
}
}
// Synonym function is vacuum()
void String::clear()
{
val = (char *) my_realloc(val, 10);
val[0] = '\0';
}
// Remove trailing ALL given character 'ch' - see also chop()
// For example :
// val = "abcdef\n\n\n" then chopall() = "abcdef"
// val = "abcdefffff" then chopall('f') = "abcde"
void String::chopall(char ch='\n')
{
unsigned long tmpii = strlen(val) - 1 ;
for (; tmpii >= 0; tmpii--)
{
if (val[tmpii] == ch)
val[tmpii] = 0;
else
break;
}
}
// Remove trailing character - see also chopall()
// chop() is often used to remove trailing newline character
void String::chop()
{
val[strlen(val)-1] = 0;
}
// Overloaded version of trim(). This will directly
// change the object.
void String::trim(bool dummy)
{
this->rtrim(true);
this->ltrim(true);
debug_("this->val", this->val);
}
// Overloaded version of ltrim(). This will directly
// change the object.
void String::ltrim(bool dummy)
{
// May cause problems in my_realloc since
// location of bb will be destroyed !!
char *bb = val;
if (bb == NULL)
return;
while (isspace(*bb))
bb++;
debug_("bb", bb);
if (bb != NULL && bb != val)
{
debug_("doing string copy", "done");
str_cpy(bb); // causes problems in my_realloc and bb is getting destroyed!!
}
else
debug_("Not doing string copy", "done");
}
String String::ltrim()
{
// May cause problems in my_realloc since
// location of bb will be destroyed !!
char *aa, *bb = strdup(val);
if (bb == NULL) // strdup failed ..
return String("");
for (aa = bb; isspace(*aa);)
aa++;
debug_("aa", aa);
if (aa == NULL)
{
free(bb);
// bb = NULL; not required as you are returning immdly
return String(val); // No-change, return as it is
}
String tmpstr(aa);
free(bb);
// bb = NULL; not required as you are returning immdly
return tmpstr;
}
// Overloaded version of rtrim(). This will directly
// change the object.
void String::rtrim(bool dummy)
{
for (long tmpii = strlen(val) - 1 ; tmpii >= 0; tmpii--)
{
if ( isspace(val[tmpii]) )
val[tmpii] = '\0';
else
break;
}
}
String String::rtrim()
{
String tmpstr(val);
for (long tmpii = strlen(tmpstr.val) - 1 ; tmpii >= 0; tmpii--)
{
if ( isspace(tmpstr.val[tmpii]) )
tmpstr.val[tmpii] = '\0';
else
break;
}
return tmpstr;
}
// Use for rounding off fractions digits of floats
// Rounds-off floats with given precision and then
// stores the result into String's val field
// Also returns the result as a char *
void String::roundf(float input_val, short precision)
{
float integ_flt, deci_flt;
const short MAX_PREC = 4;
debug_("In roundf", "ok");
if (precision > MAX_PREC) // this is the max reliable precision
precision = MAX_PREC;
// get the integral and decimal parts of the float value..
deci_flt = modff(input_val, & integ_flt);
for (int tmpzz = 0; tmpzz < precision; tmpzz++)
{
debug_("deci_flt", deci_flt);
deci_flt *= 10;
}
debug_("deci_flt", deci_flt);
unsigned long deci_int = (unsigned long) ( rint(deci_flt) );
val = (char *) my_malloc(NUMBER_LENGTH); // float 70 digits max
if (deci_int > 999) // (MAX_PREC) digits
sprintf(val, "%lu.%lu", (unsigned long) integ_flt, deci_int);
else
if (deci_int > 99) // (MAX_PREC - 1) digits
sprintf(val, "%lu.0%lu", (unsigned long) integ_flt, deci_int);
else
if (deci_int > 9) // (MAX_PREC - 2) digits
sprintf(val, "%lu.00%lu", (unsigned long) integ_flt, deci_int);
else
sprintf(val, "%lu.00000%lu", (unsigned long) integ_flt, deci_int);
}
void String::roundd(double input_val, short precision)
{
double integ_flt, deci_flt;
const short MAX_PREC = 6;
if (precision > MAX_PREC) // this is the max reliable precision
precision = MAX_PREC;
debug_("In roundd", "ok");
// get the integral and decimal parts of the double value..
deci_flt = modf(input_val, & integ_flt);
for (int tmpzz = 0; tmpzz < precision; tmpzz++)
{
debug_("deci_flt", deci_flt);
deci_flt *= 10;
}
debug_("deci_flt", deci_flt);
val = (char *) my_malloc(NUMBER_LENGTH); // double 70 digits max
unsigned long deci_int = (unsigned long) ( rint(deci_flt) );
if (deci_int > 99999) // (MAX_PREC) digits
sprintf(val, "%lu.%lu", (unsigned long) integ_flt, deci_int);
else
if (deci_int > 9999) // (MAX_PREC - 1) digits
sprintf(val, "%lu.0%lu", (unsigned long) integ_flt, deci_int);
else
if (deci_int > 999) // (MAX_PREC - 2) digits
sprintf(val, "%lu.00%lu", (unsigned long) integ_flt, deci_int);
else
if (deci_int > 99) // (MAX_PREC - 3) digits
sprintf(val, "%lu.000%lu", (unsigned long) integ_flt, deci_int);
else
if (deci_int > 9) // (MAX_PREC - 4) digits
sprintf(val, "%lu.0000%lu", (unsigned long) integ_flt, deci_int);
else // (MAX_PREC - 5) digits
sprintf(val, "%lu.00000%lu", (unsigned long) integ_flt, deci_int);
}
// Provided for documentation purpose only
// You must use the function indexOf()
bool String::contains(char *str2, int startIndex = 0)
{
// For example -
// if (indexOf("ohboy") > -1 )
// cout << "\nString contains 'ohboy'" << endl;
// if (indexOf("ohboy") < 0 )
// cout << "\nString does NOT contain 'ohboy'" << endl;
// if (indexOf("ohboy", 4) > -1 )
// cout << "\nString contains 'ohboy'" << endl;
// if (indexOf("ohboy", 4) < 0 )
// cout << "\nString does NOT contain 'ohboy'" << endl;
cerr << "\nYou must use indexOf() function instead of contains()\n" << endl;
exit(-1);
}
// Leading, trailing white-spaces of string are ignored
bool String::is_integer()
{
String tmpstr(val);
tmpstr.trim(true);
debug_("tmpstr.val", tmpstr.val );
if ( strspn ( tmpstr.val, "0123456789" ) != tmpstr.length() )
return ( false ) ;
else
return ( true ) ;
}
// Leading, trailing white-spaces of string are ignored
bool String::is_numeric()
{
String tmpstr(val);
tmpstr.trim(true);
debug_("tmpstr.val", tmpstr.val );
if ( strspn ( tmpstr.val, "0123456789.+-e" ) != tmpstr.length() )
return ( false ) ;
else
return ( true ) ;
}
// See also explode()
// Warning : The String instance is modified by removing
// the returned token from the string. It is advised
// that you save the original string before calling
// this function like for example :
// String savestr = origstr;
// String aa, bb, cc;
// aa = origstr.token();
// bb = origstr.token();
// cc = origstr.token();
//
// This routine returns the first non-'seperator' (default
// white-space) token string from the String instance
String String::token(char seperator = ' ')
{
char ee[2];
ee[0] = seperator;
ee[1] = 0;
char *res = strtok(val, ee);
if (!res) // if res == NULL
{
debug_("token", res);
debug_("val", val);
return(String(val));
}
else
{
String tmpstr(res);
// Should take string length of val and not res
// because strtok() had put a NULL ('\0') at the location
// and also strtok() ignores the leading blanks of val
strcpy(val, & val[strlen(val)+1]);
debug_("token", res);
debug_("val", val);
return tmpstr;
}
}
String String::crypt(char *original, char *salt)
{
return String("");
}
int String::int_value()
{
if ( length() == 0 ) {
cerr << "Cannot convert a zero length string "
<< " to a numeric" << endl ;
abort() ;
}
if ( ! is_integer() ) {
cerr << "Cannot convert string [" << val
<< "] to an integer numeric string" << endl ;
abort() ;
}
return ( atoi ( val ) ) ;
}
double String::double_value()
{
if ( length() == 0 ) {
cerr << "Cannot convert a zero length string "
<< " to a numeric" << endl ;
abort() ;
}
if ( ! is_numeric() ) {
cerr << "Cannot convert string [" << val
<< "] to a double numeric string" << endl ;
abort() ;
}
double d = atof ( val ) ;
return ( d ) ;
}
String String::getline(FILE *infp = stdin)
{
register char ch, *aa = NULL;
register const short SZ = 100;
// Initial value of ii > SZ so that aa is alloc'ed memory
register int jj = 0;
for (int ii = SZ+1; (ch = getc(infp)) != EOF; ii++, jj++)
{
if (ii > SZ) // allocate memory in steps of SZ for performance
{
aa = (char *) realloc(aa, jj + ii + 15); // +15 is safe mem
ii = 0;
}
if (ch == '\n') // read untill newline is encountered
break;
aa[jj] = ch;
}
aa[jj] = 0;
str_cpy(aa); // puts the value in string
free(aa);
return *this;
}
//////////////////////////////////////////////////////////
// Private functions start from here .........
//////////////////////////////////////////////////////////
void String::str_cpy(char bb[])
{
debug_("In str_cpy bb", bb);
if (bb == NULL)
{
val[0] = '\0';
return;
}
unsigned long tmpii = strlen(bb);
if (tmpii == 0)
{
val[0] = '\0';
return;
}
debug_("In str_cpy tmpii", tmpii);
debug_("In str_cpy val", val);
val = (char *) my_realloc(val, tmpii);
//val = new char [tmpii + SAFE_MEM_2];
debug_("In str_cpy bb", bb);
strncpy(val, bb, tmpii);
debug_("In str_cpy val", val);
val[tmpii] = '\0';
debug_("In str_cpy val", val);
}
void String::str_cpy(int bb)
{
char tmpaa[100];
sprintf(tmpaa, "%d", bb);
str_cpy(tmpaa);
}
void String::str_cpy(unsigned long bb)
{
char tmpaa[100];
sprintf(tmpaa, "%ld", bb);
str_cpy(tmpaa);
}
void String::str_cpy(float bb)
{
char tmpaa[100];
sprintf(tmpaa, "%f", bb);
str_cpy(tmpaa);
}
void String::str_cat(char bb[])
{
unsigned long tmpjj = strlen(bb), tmpii = strlen(val);
val = (char *) my_realloc(val, tmpii + tmpjj);
debug_("val in str_cat() ", val);
strncat(val, bb, tmpjj);
}
void String::str_cat(int bb)
{
char tmpaa[100];
sprintf(tmpaa, "%d", bb);
unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(val);
val = (char *) my_realloc(val, tmpii + tmpjj);
strncat(val, tmpaa, tmpjj);
}
void String::str_cat(unsigned long bb)
{
char tmpaa[100];
sprintf(tmpaa, "%ld", bb);
unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(val);
val = (char *) my_realloc(val, tmpii + tmpjj);
strncat(val, tmpaa, tmpjj);
}
void String::str_cat(float bb)
{
char tmpaa[100];
sprintf(tmpaa, "%f", bb);
unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(val);
val = (char *) my_realloc(val, tmpii + tmpjj);
strncat(val, tmpaa, tmpjj);
}
//////////////////////////////////////////////////////////
// All operator functions start from here .........
//////////////////////////////////////////////////////////
String operator+ (const String & lhs, const String & rhs)
{
/*******************************************************/
// Note : For adding two char strings, first cast String
// as in -
//aa = (String) "alkja " + " 99djd " ;
/*******************************************************/
String tmp(lhs);
tmp.str_cat(rhs.val);
return(tmp);
/*
if (String::global_String == NULL)
{
String::global_String = new String;
String::global_String->str_cpy(lhs.val);
String::global_String->str_cat(rhs.val);
//return *String::global_String;
return String(String::global_String->val);
}
*/
/*
else
if (String::global_String1 == NULL)
{
debug_("1)global", "ok" );
String::global_String1 = new String;
String::global_String1->str_cpy(lhs.val);
String::global_String1->str_cat(rhs.val);
return *String::global_String1;
}
*/
/*
else
{
fprintf(stderr, "\nError: cannot alloc global_String\n");
exit(-1);
}
*/
/*
String *aa = new String;
aa->str_cpy(lhs.val);
aa->str_cat(rhs.val);
return *aa;
*/
}
String String::operator+ (const String & rhs)
{
String tmp(*this);
tmp.str_cat(rhs.val);
debug_("rhs.val in operator+", rhs.val );
debug_("tmp.val in operator+", tmp.val );
return (tmp);
}
// Using reference will be faster in = operator
String& String:: operator= ( const String& rhs )
{
if (& rhs == this)
{
debug_("Fatal Error: In operator(=). rhs is == to 'this pointer'!!", "ok" );
return *this;
}
this->str_cpy(rhs.val);
debug_("rhs value", rhs.val );
// Free global vars memory
//free_glob(& String::global_String);
//if (String::global_String == NULL)
//fprintf(stderr, "\nglobal_String is freed!\n");
//return (String(*this));
return *this;
}
// Using reference will be faster in = operator
String& String::operator+= (const String & rhs)
{
/*******************************************************/
// Note : For adding two char strings, first cast String
// as in -
//aa += (String) "cccc" + "dddd";
/*******************************************************/
if (& rhs == this)
{
debug_("Fatal error: In operator+= rhs is equals 'this' ptr", "ok");
return *this;
}
this->str_cat(rhs.val);
return *this;
//return (String(*this));
}
bool String::operator== (const String & rhs)
{
return(equalto(rhs.val));
}
bool String::operator== (const char *rhs)
{
return(equalto(rhs));
}
bool String::operator!= (const String & rhs)
{
return(equalto(rhs.val, true));
}
bool String::operator!= (const char *rhs)
{
return(equalto(rhs, true));
}
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix D my_malloc.cpp<label id="Appendix D">
-->
<sect> Appendix D my_malloc.cpp <label id="Appendix D">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
/*
** In your main() function put these lines -
char p_name[1024];
sprintf(p_name, "PROGRAM_NAME=%s", argv[0]);
putenv(p_name);
print_total_memsize(); // in the beginning
......
......
print_total_memsize(); // in the end
*/
#include <stdio.h>
#include <alloc.h> // for c++ -- malloc, alloc etc...
#include <stdlib.h> // malloc, alloc..
#include <time.h> // strftime, localtime, ...
#include <list.h> // strftime, localtime, ... see file include/g++/stl_list.h
//#include <debug.h> // debug_("a", a); debug2_("a", a, true);
#include "my_malloc.h"
const short SAFE_MEM = 10;
const short DATE_MAX_SIZE = 200;
const short MALLOC = 1;
const short REALLOC = 2;
const short VOID_TYPE = 1;
const short CHAR_TYPE = 2;
const short SHORT_TYPE = 3;
const short INT_TYPE = 4;
const short LONG_TYPE = 5;
const short FLOAT_TYPE = 6;
const short DOUBLE_TYPE = 7;
const char LOG_FILE[30] = "memory_error.log";
// Uncomment this line to debug total mem size allocated...
//#define DEBUG_MEM "debug_memory_sizes_allocated"
static void raise_error_exit(short mtype, short datatype, char fname[], int lineno);
#ifdef DEBUG
class MemCheck
{
public:
MemCheck(void *aptr, size_t amem_size, char fname[], int lineno);
void *ptr;
size_t mem_size;
static list<MemCheck> mcH; // list head
static unsigned long total_memsize; // total memory allocated
};
// Global variables ....
list<MemCheck> MemCheck::mcH;
unsigned long MemCheck::total_memsize = 0;
MemCheck::MemCheck(void *aptr, size_t amem_size, char fname[], int lineno)
{
char func_name[100];
FILE *ferr = NULL;
sprintf(func_name, "MemCheck() - File: %s Line: %d", fname, lineno);
ferr = fopen(LOG_FILE, "a");
if (ferr == NULL)
{
fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE);
fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE);
#ifdef DEBUG_MEM
exit(-1);
#else
return;
#endif
}
// Search if the pointer already exists in the list...
bool does_exist = false;
list<MemCheck>::iterator iter1; // see file include/g++/stl_list.h
//fprintf(ferr, "\n%s Before checking.. !!\n", func_name);
if (MemCheck::mcH.empty() == true )
{
//fprintf(ferr, "\n%s List is empty!!\n", func_name);
}
for (iter1 = MemCheck::mcH.begin(); iter1 != MemCheck::mcH.end(); iter1++)
{
if (iter1 == NULL)
{
fprintf(ferr, "\n%s Iterator iter1 is NULL!!\n", func_name);
break;
}
if ( ((*iter1).ptr) == aptr)
{
does_exist = true;
fprintf(ferr, "\n%s Already exists!!\n", func_name);
fprintf(ferr, "\n%s Fatal Error exiting now ....!!\n", func_name);
#ifdef DEBUG_MEM
exit(-1); //------------------------------------------------------------------>>>
#else
return;
#endif
// Now change the mem size to new values...
// For total size - Remove old size and add new size
//fprintf(ferr, "\n%s total_memsize = %lu\n", func_name, (*iter1).total_memsize);
//fprintf(ferr, "\n%s mem_size = %u\n", func_name, (*iter1).mem_size);
//fprintf(ferr, "\n%s amem_size = %u\n", func_name, amem_size);
(*iter1).total_memsize = (*iter1).total_memsize + amem_size;
if ((*iter1).total_memsize > 0 )
{
if ((*iter1).total_memsize >= (*iter1).mem_size )
(*iter1).total_memsize = (*iter1).total_memsize - (*iter1).mem_size;
else
{
fprintf(ferr, "\n\n%s total_memsize is less than mem_size!!", func_name);
fprintf(ferr, "\n%s total_memsize = %lu", func_name, (*iter1).total_memsize);
fprintf(ferr, "\n%s mem_size = %u", func_name, (*iter1).mem_size);
fprintf(ferr, "\n%s amem_size = %u\n", func_name, amem_size);
}
}
(*iter1).mem_size = amem_size;
}
}
// The pointer aptr does not exist in the list, so append it now...
if (does_exist == false)
{
//fprintf(ferr, "\n%s aptr Not found\n", func_name);
ptr = aptr;
mem_size = amem_size;
MemCheck::total_memsize += amem_size;
MemCheck::mcH.insert(MemCheck::mcH.end(), *this);
}
fclose(ferr);
}
static inline void call_check(void *aa, size_t tmpii, char fname[], int lineno)
{
MemCheck bb(aa, tmpii, fname, lineno);
if (& bb); // a dummy statement to avoid compiler warning msg.
}
static inline void remove_ptr(void *aa, char fname[], int lineno)
{
char func_name[100];
if (aa == NULL)
return;
sprintf(func_name, "remove_ptr() - File: %s Line: %d", fname, lineno);
FILE *ferr = NULL;
ferr = fopen(LOG_FILE, "a");
if (ferr == NULL)
{
fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE);
fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE);
#ifdef DEBUG_MEM
exit(-1);
#else
return;
#endif
}
bool does_exist = false;
if (MemCheck::mcH.empty() == true)
{
//fprintf(ferr, "\n%s List is empty!!\n", func_name);
//fclose(ferr);
//return;
}
list<MemCheck>::iterator iter1; // see file include/g++/stl_list.h
for (iter1 = MemCheck::mcH.begin(); iter1 != MemCheck::mcH.end(); iter1++)
{
if (iter1 == NULL)
{
fprintf(ferr, "\n%s Iterator iter1 is NULL!!\n", func_name);
break;
}
if ( ((*iter1).ptr) == aa)
{
does_exist = true;
// Now change the mem size to new values...
// For total size - Remove old size
//fprintf(ferr, "\n%s total_memsize = %lu\n", func_name, (*iter1).total_memsize);
//fprintf(ferr, "\n%s mem_size = %u\n", func_name, (*iter1).mem_size);
if ((*iter1).total_memsize > 0 )
{
if ((*iter1).total_memsize >= (*iter1).mem_size )
(*iter1).total_memsize = (*iter1).total_memsize - (*iter1).mem_size;
else
{
fprintf(ferr, "\n\n%s total_memsize is less than mem_size!!", func_name);
fprintf(ferr, "\n%s total_memsize = %lu", func_name, (*iter1).total_memsize);
fprintf(ferr, "\n%s mem_size = %u\n", func_name, (*iter1).mem_size);
}
}
MemCheck::mcH.erase(iter1);
break; // must break to avoid infinite looping
}
}
if (does_exist == false)
{
//fprintf(ferr, "\n%s Fatal Error: - You did not allocate memory!! \n", func_name);
//fprintf(ferr, "\n%s The value passed is %s\n", func_name, (char *) aa);
}
else
//fprintf(ferr, "\n%s found\n", func_name);
fclose(ferr);
}
static inline void call_free_check(void *aa, char *fname, int lineno)
{
char func_name[100];
sprintf(func_name, "call_free_check() - File: %s Line: %d", fname, lineno);
FILE *ferr = NULL;
ferr = fopen(LOG_FILE, "a");
if (ferr == NULL)
{
fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE);
fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE);
#ifdef DEBUG_MEM
exit(-1);
#else
return;
#endif
}
bool does_exist = false;
list<MemCheck>::iterator iter1; // see file include/g++/stl_list.h
for (iter1 = MemCheck::mcH.begin(); iter1 != MemCheck::mcH.end(); iter1++)
{
if (iter1 == NULL)
{
fprintf(ferr, "\n%s Iterator iter1 is NULL!!\n", func_name);
break;
}
if ( ((*iter1).ptr) == aa)
{
does_exist = true;
//fprintf(ferr, "\n%s iter1.mem_size = %u\n", func_name, (*iter1).mem_size);
//fprintf(ferr, "\n%s Total memory allocated = %lu\n", func_name, (*iter1).total_memsize);
if ((*iter1).total_memsize > 0 )
{
if ((*iter1).total_memsize >= (*iter1).mem_size )
(*iter1).total_memsize = (*iter1).total_memsize - (*iter1).mem_size;
else
{
fprintf(ferr, "\n\n%s total_memsize is less than mem_size!!", func_name);
fprintf(ferr, "\n%s total_memsize = %lu", func_name, (*iter1).total_memsize);
fprintf(ferr, "\n%s mem_size = %u", func_name, (*iter1).mem_size);
}
}
MemCheck::mcH.erase(iter1);
break; // must break to avoid infinite looping
}
}
if (does_exist == false)
{
fprintf(ferr, "\n%s Fatal Error: free() - You did not allocate memory!!\n",
func_name);
//fprintf(ferr, "\n%s The value passed is %s\n", func_name, (char *) aa);
fclose(ferr);
#ifdef DEBUG_MEM
exit(-1);
#else
return;
#endif
}
else
{
//fprintf(ferr, "\n%s found\n", func_name);
}
fclose(ferr);
}
void local_print_total_memsize(char *fname, int lineno)
{
char func_name[100];
sprintf(func_name, "local_print_total_memsize() - %s Line: %d", fname, lineno);
FILE *ferr = NULL;
ferr = fopen(LOG_FILE, "a");
if (ferr == NULL)
{
fprintf(stdout, "\nWarning: Cannot open file %s\n", LOG_FILE);
fprintf(stderr, "\nWarning: Cannot open file %s\n", LOG_FILE);
#ifdef DEBUG_MEM
exit(-1);
#else
return;
#endif
}
fprintf(ferr, "\n%s Total memory MemCheck::total_memsize = %lu\n", func_name, MemCheck::total_memsize);
fclose(ferr);
}
#else //------------> DEBUG
void local_print_total_memsize(char *fname, int lineno)
{
// This function is available whether debug or no-debug...
}
#endif // DEBUG
void local_my_free(void *aa, char fname[], int lineno)
{
if (aa == NULL)
return;
call_free_check(aa, fname, lineno);
free(aa);
aa = NULL;
}
// size_t is type-defed unsigned long
void *local_my_malloc(size_t size, char fname[], int lineno)
{
size_t tmpii = size + SAFE_MEM;
void *aa = NULL;
aa = (void *) malloc(tmpii);
if (aa == NULL)
raise_error_exit(MALLOC, VOID_TYPE, fname, lineno);
memset(aa, 0, tmpii);
call_check(aa, tmpii, fname, lineno);
return aa;
}
// size_t is type-defed unsigned long
char *local_my_realloc(char *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpjj = 0;
if (aa) // aa != NULL
tmpjj = strlen(aa);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (char) * (tmpqq);
aa = (char *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
aa[tmpqq-1] = 0;
unsigned long kk = tmpjj;
if (tmpjj > tmpqq)
kk = tmpqq;
for ( ; kk < tmpqq; kk++)
aa[kk] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
// size_t is type-defed unsigned long
short *local_my_realloc(short *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (short) * (tmpqq);
aa = (short *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
// Not for numbers!! aa[tmpqq-1] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
// size_t is type-defed unsigned long
int *local_my_realloc(int *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (int) * (tmpqq);
aa = (int *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
// Not for numbers!! aa[tmpqq-1] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
// size_t is type-defed unsigned long
long *local_my_realloc(long *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (long) * (tmpqq);
aa = (long *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
// Not for numbers!! aa[tmpqq-1] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
// size_t is type-defed unsigned long
float *local_my_realloc(float *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (float) * (tmpqq);
aa = (float *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
// Not for numbers!! aa[tmpqq-1] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
// size_t is type-defed unsigned long
double *local_my_realloc(double *aa, size_t size, char fname[], int lineno)
{
remove_ptr(aa, fname, lineno);
unsigned long tmpqq = size + SAFE_MEM;
size_t tmpii = sizeof (double) * (tmpqq);
aa = (double *) realloc(aa, tmpii);
if (aa == NULL)
raise_error_exit(REALLOC, CHAR_TYPE, fname, lineno);
// do not memset!! memset(aa, 0, tmpii);
// Not for numbers!! aa[tmpqq-1] = 0;
call_check(aa, tmpii, fname, lineno);
return aa;
}
static void raise_error_exit(short mtype, short datatype, char fname[], int lineno)
{
if (mtype == MALLOC)
{
fprintf(stdout, "\nFatal Error: malloc() failed!!");
fprintf(stderr, "\nFatal Error: malloc() failed!!");
}
else
if (mtype == REALLOC)
{
fprintf(stdout, "\nFatal Error: realloc() failed!!");
fprintf(stderr, "\nFatal Error: realloc() failed!!");
}
else
{
fprintf(stdout, "\nFatal Error: mtype not supplied!!");
fprintf(stderr, "\nFatal Error: mtype not supplied!!");
exit(-1);
}
// Get current date-time and print time stamp in error file...
char date_str[DATE_MAX_SIZE + SAFE_MEM];
time_t tt;
tt = time(NULL);
struct tm *ct = NULL;
ct = localtime(& tt); // time() in secs since Epoch 1 Jan 1970
if (ct == NULL)
{
fprintf(stdout, "\nWarning: Could not find the local time, localtime() failed\n");
fprintf(stderr, "\nWarning: Could not find the local time, localtime() failed\n");
}
else
strftime(date_str, DATE_MAX_SIZE , "%C", ct);
FILE *ferr = NULL;
char filename[100];
strcpy(filename, LOG_FILE);
ferr = fopen(filename, "a");
if (ferr == NULL)
{
fprintf(stdout, "\nWarning: Cannot open file %s\n", filename);
fprintf(stderr, "\nWarning: Cannot open file %s\n", filename);
}
else
{
// **************************************************
// ******* Do putenv in the main() function *********
// char p_name[1024];
// sprintf(p_name, "PROGRAM_NAME=%s", argv[0]);
// putenv(p_name);
// **************************************************
char program_name[200+SAFE_MEM];
if (getenv("PROGRAM_NAME") == NULL)
{
fprintf(ferr, "\n%sWarning: You did not putenv() PROGRAM_NAME env variable in main() function\n",
date_str);
program_name[0] = 0;
}
else
strncpy(program_name, getenv("PROGRAM_NAME"), 200);
if (mtype == MALLOC)
fprintf(ferr, "\n%s: %s - Fatal Error - my_malloc() failed.", date_str, program_name);
else
if (mtype == REALLOC)
{
fprintf(ferr, "\n%s: %s - Fatal Error - my_realloc() failed.", date_str, program_name);
char dtype[50];
switch(datatype)
{
case VOID_TYPE:
strcpy(dtype, "char*");
break;
case CHAR_TYPE:
strcpy(dtype, "char*");
break;
case SHORT_TYPE:
strcpy(dtype, "char*");
break;
case INT_TYPE:
strcpy(dtype, "char*");
break;
case LONG_TYPE:
strcpy(dtype, "char*");
break;
case FLOAT_TYPE:
strcpy(dtype, "char*");
break;
case DOUBLE_TYPE:
strcpy(dtype, "char*");
break;
default:
strcpy(dtype, "none*");
break;
}
fprintf(ferr, "\n%s %s - Fatal Error: %s realloc() failed!!", date_str, program_name, dtype);
}
fprintf(ferr, "\n%s %s - Very severe error condition. Exiting application now....",
date_str, program_name);
fclose(ferr);
}
exit(-1);
}
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix E my_malloc.h<label id="Appendix E">
-->
<sect> Appendix E my_malloc.h <label id="Appendix E">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
/*
** In your main() function put -
char p_name[1024];
sprintf(p_name, "PROGRAM_NAME=%s", argv[0]);
putenv(p_name);
print_total_memsize(); // in the beginning
......
......
print_total_memsize(); // in the end
*/
/* Use zap instead of delete as this will be very clean!!
** Use do while to make it robust and bullet-proof macro
*/
#define zap(x) do { if (x) { delete(x); x = 0; } } while (0)
void *local_my_malloc(size_t size, char fname[], int lineno);
char *local_my_realloc(char *aa, size_t size, char fname[], int lineno);
short *local_my_realloc(short *aa, size_t size, char fname[], int lineno);
void local_my_free(void *aa, char fname[], int lineno);
void local_print_total_memsize(char fname[], int lineno);
#define my_free(NM) (void) (local_my_free(NM, __FILE__, __LINE__))
#define my_malloc(SZ) (local_my_malloc(SZ, __FILE__, __LINE__))
#define my_realloc(NM, SZ) (local_my_realloc(NM, SZ, __FILE__, __LINE__))
#define print_total_memsize() (void) (local_print_total_memsize(__FILE__, __LINE__))
#ifdef DEBUG //------------> DEBUG
#else //------------> DEBUG
#define call_check(AA, BB, CC, DD) ((void) 0)
#define call_free_check(AA, BB, CC) ((void) 0)
#define remove_ptr(AA, CC, DD) ((void) 0)
#endif //------------> DEBUG
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix F debug.h<label id="Appendix F">
-->
<sect> Appendix F debug.h <label id="Appendix F">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
/****************************************************************
Program for debugging C++/C programs
*****************************************************************/
#define print_log(AA, BB, CC, DD, EE) ((void) 0)
#ifdef DEBUG
#include <iostream>
#include <string>
//#include <assert.h> // assert() macro which is also used for debugging
const bool LOG_YES = true; // print output to log file
const bool LOG_NO = false; // Do not print output to log file
// Debugging code
// Use debug2_ to output result to a log file
#define debug_(NM, VL) (void) ( local_dbg(NM, VL, __FILE__, __LINE__) )
#define debug2_(NM, VL, LOG_FILE) (void) ( local_dbg(NM, VL, __FILE__, __LINE__, LOG_FILE) )
void local_dbg(char name[], char value[], char fname[], int lineno, bool logfile= false);
void local_dbg(char name[], string value, char fname[], int lineno, bool logfile= false);
void local_dbg(char name[], int value, char fname[], int lineno, bool logfile= false);
void local_dbg(char name[], unsigned long value, char fname[], int lineno, bool logfile= false);
void local_dbg(char name[], float value, char fname[], int lineno, bool logfile= false);
void local_dbg(char name[], double value, char fname[], int lineno, bool logfile= false);
#else //--------> else
#define debug_(NM, VL) ((void) 0)
#define debug2_(NM, VL, LOG_FILE) ((void) 0)
#endif // DEBUG
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix G debug.cpp <label id="Appendix G">
-->
<sect> Appendix G debug.cpp <label id="Appendix G">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
//*****************************************************************
// Copyright policy is GNU/GPL and it is requested that
// you include author's name and email on all copies
// Author : Al Dev Email: alavoor@yahoo.com
//*****************************************************************
/****************************************************************
Program for debugging C++/C programs
*****************************************************************/
#ifdef DEBUG // ONLY if DEBUG is defined than these functions below are needed
#include "debug.h"
//#include "log.h"
// Variable value[] can be char, string, int, unsigned long, float, etc...
void local_dbg(char name[], char value[], char fname[], int lineno, bool logfile) {
if (value == NULL)
return;
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %s\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], string value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %s\n", fname, lineno, name, value.c_str());
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value.c_str() << endl; }
void local_dbg(char name[], int value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %d\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], unsigned int value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %u\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], long value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %d\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], unsigned long value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %u\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], short value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %d\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], unsigned short value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %u\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], float value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %f\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
void local_dbg(char name[], double value, char fname[], int lineno, bool logfile) {
if (logfile == true)
print_log("\nDebug %s : Line: %d %s is = %f\n", fname, lineno, name, value);
else
cout << "\nDebug " << fname << ": Line: " << lineno << " " << name << " is = " << value << endl; }
// You add many more here - value can be a class, ENUM, datetime, etc...
#endif // DEBUG
#endif // DEBUG
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
<chapt> Appendix H Makefile <label id="Appendix H">
-->
<sect> Appendix H Makefile <label id="Appendix H">
<p>
You can download all programs as a single tar.gz file from <ref id="Download String">.
To get this file, in the web-browser, save this file as 'Text' type.
<code>
#//*****************************************************************
#// Copyright policy is GNU/GPL and it is requested that
#// you include author's name and email on all copies
#// Author : Al Dev Email: alavoor@yahoo.com
#//*****************************************************************
.SUFFIXES: .pc .cpp .c .o
CC=gcc
CXX=g++
MAKEMAKE=mm
LIBRARY=libString.a
DEST=/home/myname/lib
# To build the library, and main test program uncomment line below :-
#MYCFLAGS=-O -Wall
# To test without debug trace uncomment line below:-
MYCFLAGS=-g3 -Wall
# To enable 'full debug ' tracing uncomment line below:-
#MYCFLAGS=-g3 -DDEBUG -Wall
#PURIFY=purify -best-effort
SRCS=my_malloc.cpp String.cpp debug.cpp example_String.cpp
HDR=my_malloc.h String.h debug.h
OBJS=my_malloc.o String.o debug.o example_String.o
EXE=String
# For generating makefile dependencies..
SHELL=/bin/sh
CPPFLAGS=$(MYCFLAGS) $(OS_DEFINES)
CFLAGS=$(MYCFLAGS) $(OS_DEFINES)
#
# If the libString.a is in the current
# directory then use -L. (dash L dot)
MYLIBDIR=-L$(MY_DIR)/libmy -L.
ALLLDFLAGS= $(LDFLAGS) $(MYLIBDIR)
COMMONLIBS=-lstdc++ -lm
MYLIBS=-lString
LIBS=$(COMMONLIBS) $(MYLIBS)
all: $(LIBRARY) $(EXE)
$(MAKEMAKE):
@rm -f $(MAKEMAKE)
$(PURIFY) $(CXX) -M $(INCLUDE) $(CPPFLAGS) *.cpp > $(MAKEMAKE)
$(EXE): $(OBJS)
@echo "Creating a executable "
$(PURIFY) $(CC) -o $(EXE) $(OBJS) $(ALLLDFLAGS) $(LIBS)
$(LIBRARY): $(OBJS)
@echo "\n***********************************************"
@echo " Loading $(LIBRARY) ... to $(DEST)"
@echo "***********************************************"
@ar cru $(LIBRARY) $(OBJS)
@echo "\n "
.cpp.o: $(SRCS) $(HDR)
# @echo "Creating a object files from " $*.cpp " files "
$(PURIFY) $(CXX) -c $(INCLUDE) $(CPPFLAGS) $*.cpp
.c.o: $(SRCS) $(HDR)
# @echo "Creating a object files from " $*.c " files "
$(PURIFY) $(CC) -c $(INCLUDE) $(CFLAGS) $*.c
clean:
rm -f *.o *.log *~ *.log.old *.pid core err a.out lib*.a afiedt.buf
rm -f $(EXE)
rm -f $(MAKEMAKE)
#%.d: %.c
# @echo "Generating the dependency file *.d from *.c"
# $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< | sed '\''s/$*.o/& $@/g'\'' > $@'
#%.d: %.cpp
# @echo "Generating the dependency file *.d from *.cpp"
# $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< | sed '\''s/$*.o/& $@/g'\'' > $@'
# Must include all the c flags for -M option
#$(MAKEMAKE):
# @echo "Generating the dependency file *.d from *.cpp"
# $(CXX) -M $(INCLUDE) $(CPPFLAGS) *.cpp > $(MAKEMAKE)
include $(MAKEMAKE)
#include $(SRCS:.cpp=.d)
#include $(SRCS:.c=.d)
</code>
<!--
*******************************************
************ End of Section ***************
*******************************************
-->
</article>