mirror of https://github.com/tLDP/LDP
4502 lines
130 KiB
Plaintext
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 & 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>
|