Next Previous Contents

15. Appendix C mychar.cpp

You can download all programs as a single tar.gz file from Download mychar . To get this file, in the web-browser, save this file as 'Text' type.


//*****************************************************************
// Copyright policy is GNU/GPL but additional restriction is 
// 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++ mychar.cpp

#include "mychar.h"

// Global variables ....
//mychar *mychar::global_mychar = NULL; // global var
list<mychar>                 mychar::explodeH;

mychar::mychar()
{
        debug_("In cstr()", "ok");
        val = (char *) my_malloc(sizeof(char)* INITIAL_SIZE);
}

mychar::mychar(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
}

mychar::mychar(int bb)
{
        val = (char *) my_malloc(NUMBER_LENGTH); // integers 70 digits max
        sprintf(val, "%d", bb);
}

mychar::mychar(unsigned long bb)
{
        val = (char *) my_malloc(NUMBER_LENGTH); // long 70 digits max
        sprintf(val, "%lu", bb);
}

mychar::mychar(float bb)
{
        val = (char *) my_malloc(NUMBER_LENGTH); // float 70 digits max
        sprintf(val, "%f", bb);
}

mychar::mychar(double bb)
{
        val = (char *) my_malloc(NUMBER_LENGTH); // double 70 digits max
        sprintf(val, "%f", bb);
}

// Copy Constructor needed by operator +
mychar::mychar(const mychar & 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';
}

mychar::~mychar()
{
        //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;
}

// MUST use pointer-to-pointer **aa, otherwise the argument
// is NOT freed !!
/*
inline void mychar::free_glob(mychar **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");
}
*/

// Explodes the string and returns the list in 
// the list-head pointer explodeH
void mychar::explode(char *seperator)
{
        char *aa = NULL, *bb = NULL;
        aa = (char *) my_malloc(length());
        for (bb = strtok(aa, seperator); bb != NULL; bb = strtok(NULL, seperator) )
        {
                mychar *tmp = new mychar(bb);
                mychar::explodeH.insert(mychar::explodeH.end(), *tmp);
        }
        my_free(aa);

        list<mychar>::iterator iter1; // see file include/g++/stl_list.h
        debug_("Before checking explode..", "ok");
        if (mychar::explodeH.empty() == true )
        {
                debug_("List is empty!!", "ok");
        }

        for (iter1 = mychar::explodeH.begin(); iter1 != mychar::explodeH.end(); iter1++)
        {
                if (iter1 == NULL)
                {
                        debug_("Iterator iter1 is NULL!!", "ok" );
                        break;
                }
                debug_("(*iter1).val", (*iter1).val);
        }
}

// Implodes the strings in the list-head 
// pointer explodeH and returns the mychar class 
void mychar::implode(char *glue)
{
}

// Joins the strings in the list-head 
// pointer explodeH and returns the mychar class 
void mychar::join(char *glue)
{
        implode(glue);
}

// Repeat the input string n times
void mychar::repeat(char *input, unsigned int multiplier)
{
        // For example -
        // repeat("1", 4) returns "1111"
        if (!input) // input == NULL
        {
                val[0] = 0;
                return;
        }

        val = (char *) my_malloc(strlen(input) * multiplier);
        for (unsigned int tmpii = 0; tmpii < multiplier; tmpii++)
        {
                strcat(val, input);
        }
}

// Reverse the string
void mychar::reverse()
{
        // 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
        }
}

// Replace all occurences of string 'needle' with 'str' in the haystack 'val'
void mychar::replace(char *needle, char *str)
{
        // For example -
        //              replace("AAA", "BB") on val = "some AAA and AAACC"
        //              reurns val = "some BB and BBCC"
}

// Translate certain chars
void mychar::str_tr(char *from, char *to)
{
        // For e.g ("abcd", "ABC") translates all occurences of each 
        // character in 'from' to corresponding character in 'to'
}

// Center the text
void center(int length, char padchar = ' ')
{
        // For example -
        //              center(10, '*') on val="aa" returns "****aa****"
        //              center(10) on val="aa" returns "    aa    "
        // The result is a string of 'length' characters with val centered in it.
}

// 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 ' '
void 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"
}

// The result is string comprised of all characters between 
// and including <start> and <end>
void xrange(char start, char end)
{
        // For example -
        //      xrange('a', 'j') returns val = "abcdefghij"
        //      xrange(1, 8) returns val = "12345678"
}

// Removes any characters contained in <list>. The default character
// for <list> is a blank ' '
void compress(char *list)
{
        // For example -
        //      compress("$,%") on val = "$1,934" returns "1934"
        //      compress() on val = "call me alavoor vasudevan" returns "callmealavoorvasudevan"
}

// Deletes a portion of string of <length> characters from <start> position.
// If start is greater than the string length then string is unchanged.
void delstr(int start, int length)
{
        // For example -
        //      delstr(3,3) on val = 'pokemon' returns 'poon'
}

// 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
void insert(char *newstr, int start = 0, int length = 0, char padchar = ' ')
{
        // For example -
        //      insert("something new", 4, 20, '*') on val = "old thing" 
        //              returns "old something new*******thing"
}

// The result is string of <length> chars madeup of leftmost chars in val.
// Quick way to left justify a string.
void left(int length = 0, char padchar = ' ')
{
        // For example -
        //      left(10) on val = "Wig" returns "Wig      "
        //      left(4) on val = "Wighat" returns "Wigh"
}

// The result is string of <length> chars madeup of rightmost chars in val.
// Quick way to right justify a string.
void right(int length = 0, char padchar = ' ')
{
        // For example -
        //      right(10) on val = "never stop to saying" returns " to saying"
        //      right(4) on val = "Wighat" returns "ghat"
        //      right(6) on val = "4.50" returns "  4.50"
}

// 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
void overlay(char *newstr, int start = 0, int length = 0, char padchar = ' ')
{
        // For example -
        //      overlay("12345678", 4, 10, '*') on val = "oldthing is very bad"
        //              returns "old12345678**ery bad"
}

// sub string 
mychar mychar::substr(int start, int length = 0)
{
        if (!length) // length == 0
                return(mychar(& val[start-1]) );
        else
        {
                mychar tmp = mychar(& val[start-1]);
                tmp.val[length-1] = 0;
                return(tmp);
        }
}

// If string is literrally equal to .. or not equal to
// If type is false then it is ==
bool mychar::equalto(const mychar & 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 then it is ==
bool mychar::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;
        }
}

// find position, matching substr beginning from start..
long mychar::pos(char *substr, unsigned long start)
{
        char * tok;
        long res = -1;

        if ( !isnull() && (start < strlen(val) ) )
        {
                tok = strstr(val + start, substr);
                if (tok == NULL)
                        res = -1;
                else
                        res = (long) (tok - val);
        }
        return res;
}

bool mychar::isnull()
{
        if (val[0] == '\0')
                return true;
        else
        {
                if (val == NULL)
                        return true;
                else
                        return false;
        }
}

void mychar::clear()
{
        val = (char *) my_realloc(val, 10);
        val[0] = '\0';
}

// Remove trailing new-lines
void mychar::chop()
{
        unsigned long tmpii = strlen(val) - 1 ;
        for (; tmpii >= 0; tmpii--)
        {
                if (val[tmpii] == '\n')
                        val[tmpii] = 0;
                else
                        break;
        }
}

void mychar::ltrim()
{
        // 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!!
                strcpy(val, bb); // strcpy is ok since val space is > bb space
        }
        else
                debug_("Not doing string copy", "done");
}

void mychar::rtrim()
{
        for (long tmpii = strlen(val) - 1 ; tmpii >= 0; tmpii--)
        {
                if ( isspace(val[tmpii]) )
                        val[tmpii] = '\0';
                else
                        break;
        }
}

void mychar::trim()
{
        rtrim();
        ltrim();
}

void mychar::to_lower()
{
        for (long tmpii = strlen(val); tmpii >= 0; tmpii--)
        {
                val[tmpii] = tolower(val[tmpii]);
        }
}

// Use for rounding off fractions digits of floats
// Rounds-off floats with given precision and then
// stores the result into mychar's val field
// Also returns the result as a char *
void mychar::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 mychar::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); 
}

void mychar::to_upper()
{
        for (long tmpii = strlen(val); tmpii >= 0; tmpii--)
        {
                val[tmpii] = toupper(val[tmpii]);
        }
}

void mychar::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 mychar::str_cpy(int bb)
{
        char tmpaa[100];
        sprintf(tmpaa, "%d", bb);
        str_cpy(tmpaa);
}

void mychar::str_cpy(unsigned long bb)
{
        char tmpaa[100];
        sprintf(tmpaa, "%ld", bb);
        str_cpy(tmpaa);
}

void mychar::str_cpy(float bb)
{
        char tmpaa[100];
        sprintf(tmpaa, "%f", bb);
        str_cpy(tmpaa);
}

void mychar::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 mychar::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 mychar::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 mychar::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);
}

mychar operator+ (const mychar & lhs, const mychar & rhs)
{
        /*******************************************************/
        // Note : For adding two char strings, first cast mychar 
        // as in - 
        //aa = (mychar) "alkja " + " 99djd " ;
        /*******************************************************/

        mychar tmp(lhs);
        tmp.str_cat(rhs.val);
        return(tmp);

        /*
        if (mychar::global_mychar == NULL)
        {
                mychar::global_mychar = new mychar;
                mychar::global_mychar->str_cpy(lhs.val);
                mychar::global_mychar->str_cat(rhs.val);
                //return *mychar::global_mychar;
                return mychar(mychar::global_mychar->val);
        }
        */
        /*
        else
        if (mychar::global_mychar1 == NULL)
        {
                debug_("1)global", "ok" );
                mychar::global_mychar1 = new mychar;
                mychar::global_mychar1->str_cpy(lhs.val);
                mychar::global_mychar1->str_cat(rhs.val);
                return *mychar::global_mychar1;
        }
        */
        /*
        else
        {
                fprintf(stderr, "\nError: cannot alloc global_mychar\n");
                exit(-1);
        }
        */

        /*
        mychar *aa = new mychar;
        aa->str_cpy(lhs.val);
        aa->str_cat(rhs.val);
        return *aa;
        */
}

mychar mychar::operator+ (const mychar & rhs)
{
        mychar 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
mychar& mychar:: operator= ( const mychar& 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(& mychar::global_mychar);
        //if (mychar::global_mychar == NULL)
                //fprintf(stderr, "\nglobal_mychar is freed!\n");

        //return (mychar(*this));
        return *this;
}

// Using reference will be faster in = operator
mychar& mychar::operator+= (const mychar & rhs)
{
        /*******************************************************/
        // Note : For adding two char strings, first cast mychar 
        // as in - 
        //aa += (mychar) "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 (mychar(*this));
}

bool mychar::operator== (const mychar & rhs)
{
        return(equalto(rhs.val));
}

bool mychar::operator== (const char *rhs)
{
        return(equalto(rhs));
}

bool mychar::operator!= (const mychar & rhs)
{
        return(equalto(rhs.val, true));
}

bool mychar::operator!= (const char *rhs)
{
        return(equalto(rhs, true));
}


Next Previous Contents