Page suivante Page précédente Table des matières

16. Annexe C String.cpp

Vous pouvez récupérer tous les programmes en un seul tar.gz sur Telecharger String . Pour obtenir ce fichier, dans un butineur web, sauvez ce fichier en type 'texte'.


//
// Auteur : Al Dev
// Utilisez la classe string ou cette classe
//
// Pour prévenir les fuites de mémoire - une classe caractère qui gère les
// variables caractères.
// Préférez toujours l'utilisation de la classe string à char[] et char *.
//
//

// Pour compiler et tester ce programme, utilisez -
//              g++ String.cpp

#include "String.h"

//#include <sys/va_list.h> pour Format()
//#include <sys/varargs.h> pour Format()

// Variables globales....
//String *String::_global_String = NULL; // variable globale
list<String>                 String::explodeH;

String::String()
{
        debug_("In cstr()", "ok");
        sval = (char *) my_malloc(sizeof(char)* INITIAL_SIZE);

        _pString = NULL;
}

String::String(char *bb)
{
        unsigned long tmpii = strlen(bb);
        sval = (char *) my_malloc(sizeof(char)* tmpii);
        strncpy(sval, bb, tmpii);
        sval[tmpii] = '\0';

        //debug_("In cstr(char *bb) bb", bb);
        debug_("In cstr(char *bb) sval", sval);
        #ifdef DEBUG
                //fprintf(stderr, "\nAddress of sval=%x\n", & sval);
                //fprintf(stderr, "\nAddress of this-pointer=%x\n", this);
        #endif // DEBUG

        _pString = NULL;
}

String::String(char *bb, int start, int slength)
{
        unsigned long tmpii = strlen(bb);
        if (start > (int) tmpii || start < 0)
        {
                cerr << "\nString(char *, int, int) - start is  out of bounds!!\n" << endl;
                exit(1);
        }
        sval = (char *) my_malloc(sizeof(char)* slength);
        strncpy(sval, & bb[start], slength);
        sval[slength] = '\0';

        //debug_("In cstr(char *bb) bb", bb);
        debug_("In cstr(char *bb) sval", sval);
        #ifdef DEBUG
                //fprintf(stderr, "\nAddress of sval=%x\n", & sval);
                //fprintf(stderr, "\nAddress of this-pointer=%x\n", this);
        #endif // DEBUG

        _pString = NULL;
}

String::String(int bb)
{
        sval = (char *) my_malloc(NUMBER_LENGTH); // int avec 70 chiffres max
        sprintf(sval, "%d", bb);
        debug_("In cstr(int bb) sval", sval);

        _pString = NULL;
}

String::String(unsigned long bb)
{
        sval = (char *) my_malloc(NUMBER_LENGTH); // unsigned long avec 70 chiffres max
        sprintf(sval, "%lu", bb);
        debug_("In cstr(unsigned long bb) sval", sval);

        _pString = NULL;
}

String::String(long bb)
{
        sval = (char *) my_malloc(NUMBER_LENGTH); // long avec 70 chiffres max
        sprintf(sval, "%ld", bb);
        debug_("In cstr(long bb) sval", sval);

        _pString = NULL;
}

String::String(float bb)
{
        sval = (char *) my_malloc(NUMBER_LENGTH); // float avec 70 chiffres max
        sprintf(sval, "%f", bb);
        debug_("In cstr(float bb) sval", sval);

        _pString = NULL;
}

String::String(double bb)
{
        sval = (char *) my_malloc(NUMBER_LENGTH); // double avec 70 chiffres max
        sprintf(sval, "%f", bb);
        debug_("In cstr(double bb) sval", sval);

        _pString = NULL;
}

// Constructeur par recopie utilisé par l'opérateur +
String::String(const String & rhs)
{
        // Effectue une copie en profondeur à la place de la copie superficielle par défaut du compilateur
        debug_("In copy-cstr()", "ok");
        unsigned long tmpii = strlen(rhs.sval);
        sval = (char *) my_malloc(sizeof(char)* tmpii);
        strncpy(sval, rhs.sval, tmpii);
        sval[tmpii] = '\0';

        _pString = NULL;
}

// Cette fonction fournit une compatibilité avec le code Java
String::String(StringBuffer sb)
{
        debug_("In String(StringBuffer)", "ok");
        unsigned long tmpii = strlen(sb.sval);
        sval = (char *) my_malloc(sizeof(char)* tmpii);
        strncpy(sval, sb.sval, tmpii);
        sval[tmpii] = '\0';

        _pString = NULL;
}

// Utilisé par la classe StringBuffer. Utilise la variable dummy
// pour différentes signatures.
// La classe StringBuffer imite le StringBuffer de Java
String::String(int size, bool dummy)
{
        sval = (char *) my_malloc(sizeof(char)* size);
        debug_("In cstr(int size, bool dummy) sval", sval);
        #ifdef DEBUG
                //fprintf(stderr, "\nAddress of sval=%x\n", & sval);
                //fprintf(stderr, "\nAddress of this-pointer=%x\n", this);
        #endif // DEBUG

        _pString = NULL;
}

String::~String()
{
        debug_("In dstr sval", sval);
        #ifdef DEBUG
                //fprintf(stderr, "\nAddress of sval=%x\n", & sval);
                //fprintf(stderr, "\nAddress of this-pointer=%x\n", this);
        #endif // DEBUG
        my_free(sval);
        //delete [] sval;
        sval = NULL;

        delete _pString; _pString = NULL;
}

inline void String::_allocpString()
{
        // _pString will be deleted in destructor
        if (!_pString)  // if (_pString == NULL)
                _pString = new String(this->sval); 
        else
                *_pString = this->sval;
}

// DOIT utiliser un pointeur-sur-pointeur **aa, sinon la mémoire utilisée
// par l'argument N'est PAS libérée !
/*
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");
}
*/

// Imite le charAt de java.lang.String
char String::charAt(int where)
{
        verifyIndex(where);
        return (sval[where]);
}

// Imite la fonction getChars de java.lang.String
// sourceStart spécifie l'indice du début de la sous-chaîne
// et sourceEnd spécifie l'indice juste après la fin de la sous-chaîne désirée
// Ainsi la sous-chaîne contient les caractères de sourceStart jusqu'à
// (sourceEnd - 1). Le tableau qui va recevoir les caractères est target.
// targetStart est l'indice dans target à partir duquel la copie sera effectuée.
// Il convient de s'assurer que le tableau target est assez grand pour pouvoir contenir
// le nombre de caractères désiré.
// Par exemple  getChars(3, 6, aa, 0) sur "ABCDEFGHIJK" donne aa ="DEF"
void String::getChars(int sourceStart, int sourceEnd, char target[], int targetStart)
{
        verifyIndex(sourceStart);
        verifyIndex(sourceEnd);

        if (sourceEnd >= sourceStart)
        {
                strncpy(& target[targetStart], & sval[sourceStart], sourceEnd - sourceStart);
                target[targetStart + (sourceEnd - sourceStart)] = 0;
        }
        else
        {
                cerr << "\ngetChars() - SourceEnd is greater than SourceStart!!\n" << endl;
                exit(1);
        }
}

// Imite getChars de java.lang.String
// Retourne un tableau caractères contenant la chaîne entière
char* String::toCharArray()
{
        return (sval);
}

// Imite getBytes de java.lang.String
// Retourne un tableau caractères contenant la chaîne entière
char* String::getBytes()
{
        return (sval);
}

// Imite equals de java.lang.String
bool String::equals(String str2)  // voir aussi l'opérateur ==
{
        return ( _equalto(str2.sval));
}

// Imite equals de java.lang.String
bool String::equals(char *str2)  // voir aussi l'opérateur ==
{
        return ( _equalto(str2));
}

// Imite equalsIgnoreCase de java.lang.String
bool String::equalsIgnoreCase(String str2)
{
        String  aa, bb;
        aa = this->toLowerCase();
        bb = str2.toLowerCase();
        return ( aa._equalto(bb.sval) );
}

// Imite regionMatches de java.lang.String
// startIndex spécifie l'indice à partir duquel débute la région dans l'objet
// String invoquant la méthode. La chaîne est comparée à str2. L'indice à partir
// duquel la comparaison commencera dans str2 est spécifié par str2Index
// La longueur de la sous-chaîne comparée est numChars.
bool String::regionMatches(int startIndex, String str2, int str2StartIndex, int numChars)
{
        verifyIndex(startIndex);
        str2.verifyIndex(str2StartIndex);
        if (strncmp(& this->sval[startIndex], & str2.sval[str2StartIndex], numChars) == 0)
                return true;
        else
                return false;
}

// Imite regionMatches de java.lang.String
// Il s'agit de la version surchargée de regionMatches
// Si ignoreCase vaut true, la casse des caractères est ignorée, sinon
// la casse est significative (i.e. si ignoreCase vaut true alors ignore la 
// casse et compare)
// startIndex spécifie l'indice à partir duquel débute la region dans l'objet
// String invoquant la méthode. La chaîne est comparée à str2. L'indice à partir
// duquel la comparaison commencera dans str2 est spécifié par str2Index
// La longueur de la sous-chaîne comparée est numChars.
bool String::regionMatches(bool ignoreCase, int startIndex, String str2, int str2StartIndex, int numChars)
{
        if (ignoreCase)  // if (ignoreCase == true)
        {
                verifyIndex(startIndex);
                str2.verifyIndex(str2StartIndex);
                String string1, string2;
                string1 = this->toLowerCase();
                string2 = str2.toLowerCase();
                if (strncmp(& string1.sval[startIndex], & string2.sval[str2StartIndex], numChars) == 0)
                        return true;
                else
                        return false;
        }
        else
        {
                return regionMatches(startIndex, str2, str2StartIndex, numChars);
        }
}

// Imite toLowerCase de java.lang.String
//       String  ss("sometest");
//       String  egg = ss.toLowerCase();
String String::toLowerCase()
{
        _allocpString();

        for (long tmpii = strlen(_pString->sval); tmpii >= 0; tmpii--)
        {
                _pString->sval[tmpii] = tolower(_pString->sval[tmpii]);
        }
        return *_pString;  // return the object now
}

// Imite toUpperCase de java.lang.String
//       String  ss("sometest");
//       String  egg = ss.toUpperCase();
String String::toUpperCase()
{
        _allocpString();

        for (long tmpii = strlen(_pString->sval); tmpii >= 0; tmpii--)
        {
                _pString->sval[tmpii] = toupper(_pString->sval[tmpii]);
        }
        return *_pString;  // return the object now
}

// Imite startsWith de java.lang.String
bool String::startsWith(String str2)
{
        if (!strncmp(this->sval, str2.sval, strlen(str2.sval) )) // if (strncmp() == 0)
                return true;
        else
                return false;
}

// Imite startsWith de java.lang.String
// Fonction surchargée
bool String::startsWith(char *str2)
{
        int lenstr2 = strlen(str2);
        if (!strncmp(this->sval, str2, lenstr2)) // if (strncmp() == 0)
                return true;
        else
                return false;
}

// Imite endsWith de java.lang.String
bool String::endsWith(String str2)
{
        // str2 doit être plus courte que la chaîne courante
        if (strlen(str2.sval) > strlen(sval))
                return false;

        if (!strncmp(& this->sval[strlen(sval) - strlen(str2.sval)], str2.sval, strlen(str2.sval) )) // if (strncmp() == 0)
                return true;
        else
                return false;
}

// Imite endsWith de java.lang.String
bool String::endsWith(char *str2)
{
        // str2 doit être plus courte que la chaîne courante
        if (strlen(str2) > strlen(sval))
                return false;

        if (!strncmp(& this->sval[strlen(sval) - strlen(str2)], str2, strlen(str2) ) ) // if (strncmp() == 0)
                return true;
        else
                return false;
}

// Imite compareTo de java.lang.String
// Pour les tris, vous devez savoir si l'un est plus petit, égal ou plus grand que l'autre.
// Une chaîne est plus petite qu'une autre si elle arrive avant l'autre dans l'ordre
// lexicographique. Un chaîne est plus grande qu'une autre si elle arrive après.
//  Négatif  --> la chaîne courante est plus petite que str2
//  Positif  --> la chaîne courante est plus grande que str2
//  Zero  --> les deux chaînes sont égales
int String::compareTo(String str2)
{
        int  flag = 0;
        // Compare les lettres dans la chaîne à chaque lettre de str2
        for (int tmpii = 0, tmpjj = strlen(sval), tmpkk = strlen(str2.sval); tmpii < tmpjj; tmpii++)
        {
                if (tmpii > tmpkk)
                        break;
                if (sval[tmpii] == str2.sval[tmpii])
                        flag = 0;
                else
                if (sval[tmpii] > str2.sval[tmpii])
                {
                        flag = 1;
                        break;
                }
                else // if (sval[tmpii] < str2.sval[tmpii])
                {
                        flag = -1;
                        break;
                }
        }
        return flag;
}

// Imite compareTo de java.lang.String
// Fonction surchargée de compareTo
int String::compareTo(char *str2)
{
        int  flag = 0;
        // Compare les lettres de la chaîne courante avec chaque lettre de str2
        for (int tmpii = 0, tmpjj = strlen(sval), tmpkk = strlen(str2); tmpii < tmpjj; tmpii++)
        {
                if (tmpii > tmpkk)
                        break;
                if (sval[tmpii] == str2[tmpii])
                        flag = 0;
                else
                if (sval[tmpii] > str2[tmpii])
                {
                        flag = 1;
                        break;
                }
                else // if (sval[tmpii] < str2[tmpii])
                {
                        flag = -1;
                        break;
                }
        }
        return flag;
}

// Imite compareToIgnoreCase de java.lang.String
int String::compareToIgnoreCase(String str2)
{
        String tmpaa = this->toLowerCase(),
        tmpbb = str2.toLowerCase();

        return tmpaa.compareTo(tmpbb);
}

// Imite compareToIgnoreCase de java.lang.String
// Version surchargée
int String::compareToIgnoreCase(char *str2)
{
        String tmpaa = this->toLowerCase(),
        tmpcc(str2), tmpbb = tmpcc.toLowerCase();

        return tmpaa.compareTo(tmpbb);
}

// Imite indexOf de java.lang.String
// Cherche la premiere occurrence d'un caractère ou d'une chaîne.
// Retourne l'indice à partir duquel le caractère ou la chaîne
// a été trouvé, ou -1 en cas d'échec.
int String::indexOf(char ch, int startIndex = 0)
{
        verifyIndex(startIndex);
        int ii = startIndex;
        for (; ii < (int) strlen(sval); ii++)
        {
                if (sval[ii] == ch)
                        break;
        }
        if (ii == (int) strlen(sval))
                return -1;
        return ii;
}

// Imite indexOf de java.lang.String
// Version surchargée
int String::indexOf(char *str2, int startIndex = 0)
{
        verifyIndex(startIndex);
        char * tok;
        long res = -1;

        if ( !isNull() )
        {
                tok = strstr(sval + startIndex, str2);
                if (tok == NULL)
                        res = -1;
                else
                        res = (int) (tok - sval);
        }
        return res;
}

// Imite indexOf de java.lang.String
// Version surchargée
int String::indexOf(String str2, int startIndex = 0)
{
        verifyIndex(startIndex);
        char * tok;
        long res = -1;

        if ( !isNull() )
        {
                tok = strstr(sval + startIndex, str2.sval);
                if (tok == NULL)
                        res = -1;
                else
                        res = (int) (tok - sval);
        }
        return res;
}

// Imite lastIndexOf de java.lang.String
// Cherche pour la dernière occurrence d'un caractère ou d'une chaîne.
// Retourne l'indice à partir duquel le caractère ou la chaîne a été trouvé
// ou -1 en cas d'échec.
int String::lastIndexOf(char ch, int startIndex = 0)
{
        verifyIndex(startIndex);
        int ii;

        // Commence la recherche par le dernier caractère de la chaîne
        if (!startIndex) // if (startIndex == 0)
                ii = strlen(sval);
        else
                ii = startIndex;
        for (; ii > -1; ii--)
        {
                if (sval[ii] == ch)
                        break;
        }
        if (!ii && sval[ii] != ch) // if (ii == 0)
                return -1;
        return ii;
}

// Imite lastIndexOf de java.lang.String
// Version surchargée
int String::lastIndexOf(char *str2, int startIndex = 0)
{
        verifyIndex(startIndex);
    char *tok = NULL;
    int res = -1;
 
    register char *tmpaa = strdup(sval);  // ici malloc
    if (!tmpaa) // tmpaa == NULL
    {
        cerr << "\nMemory alloc failed in strdup in lastIndexOf()\n" << endl;
        exit(-1);
    }
 
    if (!startIndex) // if (startIndex == 0)
        startIndex = strlen(sval);
    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; // saute vers l'endroit qui correspond (+1 dans la boucle for)
        }
    }
    free(tmpaa);
        debug_("res", res);
        debug_("indexOf", & sval[res]);

        return res;
}

// Imite lastIndexOf de java.lang.String
// Version surchargée
int String::lastIndexOf(String str2, int startIndex = 0)
{
        verifyIndex(startIndex);
    char *tok = NULL;
    int res = -1;
 
    register char *tmpaa = strdup(sval);  // ici malloc
    if (!tmpaa) // tmpaa == NULL
    {
        cerr << "\nMemory alloc failed in strdup in lastIndexOf()\n" << endl;
        exit(-1);
    }
 
    if (!startIndex) // if (startIndex == 0)
        startIndex = strlen(sval);
    else
        tmpaa[startIndex+1] = 0;
 
    for (int ii = 0; ii <= startIndex; ii++)
    {
        tok = strstr(& tmpaa[ii], str2.sval);
        if (tok == NULL)
            break;
        else
        {
            res = (int) (tok - tmpaa);
                        debug_("res", res);
            ii = res; // saute vers l'endroit qui correspond (+1 dans la boucle for)
        }
    }
    free(tmpaa);
        debug_("res", res);
        debug_("indexOf", & sval[res]);

        return res;
}

// Imite substring de java.lang.String
// startIndex spécifie l'indice de début, et endIndex l'indice de fin.
// La chaîne retournée contient tous les caractères de l'indice de début
// jusqu'à l'indice de fin, mais sans l'inclure.
String String::substring(int startIndex, int endIndex = 0)
{
        String tmpstr = String(sval);
        tmpstr._substring(startIndex, endIndex);
        return tmpstr;
}

// Imite concat de java.lang.String
String String::concat(String str2)
{
        return (*this + str2);
}

// Imite concat de java.lang.String
// Version surchargée
String String::concat(char *str2)
{
        return (*this + str2);
}

// Imite replace de java.lang.String
// Remplace toutes les occurrences de la chaîne 'original' par 
// 'replacement' dans 'sval'
String String::replace(char original, char replacement)
{
        // Par exemple -
        //              replace('A', 'B') dans sval = "des AAA et AAACC"
        //              retourne sval = "des BBB et BBBCC"
        //String *tmpstr = new String(sval); Utilise le constructeur de recopie par défaut
        String tmpstr(sval);
        for (int ii = 0, len = strlen(sval); ii < len; ii++)
        {
                if (tmpstr.sval[ii] == original)
                        tmpstr.sval[ii] = replacement;
        }
        return tmpstr; // utilise le constructeur de recopie pour faire une copie
}

// Imite replace de java.lang.String
// Version surchargée
// Remplace toutes les occurrences de la chaîne 'original' par
// 'replacement' dans 'sval'
String String::replace(char *original, char *replacement)
{
        char *tok = NULL, *bb;
        register char *aa = strdup(sval);
        int lenrepl = strlen(replacement);

        // Alloue l'espace pour bb
        { // portée locale
                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, pas de 'original' trouvé
                        return (String(sval)); // retourne la chaîne originale
                tmpii = strlen(sval) + (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;
}
/*
une autre méthode pour faire le remplacement mais lente...
String String::replace(char *original, char *replacement)
{
        // Par exemple -
        //              replace("AAA", "BB") avec sval = "des AAA et AAACC"
        //              retourne sval = "des BB et BBCC"
        String bb(this->before(original).sval);
        if (strlen(bb.sval) == 0)
                return String(sval); // retourne la chaîne originale
        bb += replacement;

        String tmpaa(this->sval), cc, dd;
        for (;;)
        {
                cc = tmpaa.after(original).sval;
                debug_("cc", cc.sval );
                if (!strlen(cc.sval)) // if (strlen(cc.sval) == 0)
                        break;

                dd = cc.before(original).sval;
                if (strlen(dd.sval) == 0)
                {
                        bb += cc;
                        break;
                }
                else
                {
                        bb += dd;
                        bb += replacement;
                }
                tmpaa = cc;
        }
        debug_("bb.sval", bb.sval );
        return bb;
}
*/

// Imite replace de Java -  StringBuffer 
String String::replace (int startIndex, int endIndex, String str)
{
        verifyIndex(startIndex);
        verifyIndex(endIndex);
        int tmpjj = strlen(str.sval);
        if (tmpjj == 0)
                return *this;
        int tmpii = endIndex-startIndex-1;
        if (tmpjj < tmpii) // la longueur de str est plus petite que les indices specifies.
                tmpii = tmpjj;
        debug_("sval", sval);
        debug_("str.sval", str.sval);
        strncpy(& sval[startIndex], str.sval, tmpii);
        sval[startIndex+tmpii] = 0;
        debug_("sval", sval);
        return *this;
}

// Imite trim de java.lang.String
String String::trim()
{
        //String *tmpstr = new String(sval);
        String tmpstr(sval);
        tmpstr._trim();
        debug_("tmpstr.sval", tmpstr.sval);
        return tmpstr; // utilise le constructeur par recopie pour faire une copie
}

// Imite insert de java.lang.String
String String::insert(int index, String str2)
{
        String tmpstr(this->insert(str2.sval, index).sval);
        debug_("tmpstr.sval", tmpstr.sval);
        return tmpstr;
}

// Imite insert de java.lang.String
String String::insert(int index, char ch)
{
        char aa[2];
        aa[0] = ch;
        aa[1] = 0;
        String tmpstr(this->insert(aa, index).sval);
        debug_("tmpstr.sval", tmpstr.sval);
        return tmpstr;
}

// Imite deleteCharAt de java.lang.String
String String::deleteCharAt(int loc)
{
        String tmpstr(sval);
        tmpstr._deleteCharAt(loc);
        return tmpstr;
}

// Imite delete de java.lang.String
// Note : -->le nom Java est "delete()", mais c'est un mot résérvé inutilisable en C++
// startIndex spécifie l'indice du premier caractère à enlever,
// et endIndex l'indice juste après le dernier caractère à supprimer.
// Ainsi, la sous-chaîne supprimée s'etend de startIndex à (endIndex - 1).
String String::deleteStr(int startIndex, int endIndex)
{
        // Par exemple -
        //      deleteStr(3,3) avec val = 'pokemon' retourne 'poon'
        String tmpstr(sval);
        tmpstr._deleteStr(startIndex, endIndex);
        return tmpstr;
}

// Imite reverse de java.lang.String
String String::reverse()
{
        // Par exemple :
        //              reverse() sur "12345" retourne "54321"
        String tmpstr(sval);
        tmpstr._reverse();
        return tmpstr;
}

// Imite valueOf de java.lang.String
String String::valueOf(char chars[], int startIndex, int numChars)
{
        verifyIndex(startIndex);
        int ii = strlen(chars);
        if (startIndex > ii)
        {
                cerr << "\nvalueOf() - startIndex greater than string length of"
                        << "string passed" << endl;
                exit(0);
        }
        if ( (numChars+startIndex) > ii)
        {
                cerr << "\nvalueOf() - numChars exceeds the string length of"
                        << "string passed" << endl;
                exit(0);
        }

        char *aa = strdup(chars);
        aa[startIndex + numChars] = 0;
        String tmpstr(& aa[startIndex]);
        free(aa);
        return tmpstr;
}

// Imite ensureCapacity de java.lang.String
// Utilisé par la classe StringBuffer. 
// Pré-alloue la place pour un certain nombre de caractères.
// Utile si vous savez à l'avance que vous allez rajouter un grand nombre
// de petites chaînes à un StringBuffer
void String::ensureCapacity(int capacity)
{
        sval = (char *) my_realloc(sval, capacity);
        sval[0] = '\0';
        debug_("In ensureCapacity(int capacity) sval", sval);
}

// Imite setLength de java.lang.String
// Utilise par la classe StringBuffer. 
void String::setLength(int len)
{
        sval = (char *) my_realloc(sval, len);
        sval[0] = '\0';
        debug_("In ensureCapacity(int len) sval", sval);
}

// Imite setCharAt de StringBuffer 
void String::setCharAt(int where, char ch)
{
        verifyIndex(where);
        sval[where] = ch;
        debug_("in StringBuffer dstr()", "ok");
}

// ---- Fin des fonctions imitant java.lang.String -----

// Version surchargée, modifie directement l'objet
// La variable dummy donne une signature différente à la fonction.
void String::substring(int startIndex, int endIndex, bool dummy)
{
        this->_substring(startIndex, endIndex);
}

inline void String::_substring(int startIndex, int endIndex)
{
        verifyIndex(startIndex);
        verifyIndex(endIndex);
        if (!endIndex) // endIndex == 0
                strcpy(sval, & sval[startIndex] ) ;
        else
        {
                if (endIndex > startIndex)
                {
                        strcpy(sval, & sval[startIndex] ) ;
                        sval[endIndex -startIndex] = 0;
                }
                else
                {
                        cerr << "\n_substring() - startIndex is greater than endIndex!!\n" 
                                << endl;
                        exit(-1);
                }
        }
}

// Version surchargée, modifie directement l'objet
String String::deleteStr(int startIndex, int endIndex, bool dummy)
{
        this->_deleteStr(startIndex, endIndex);
        return *this;
}

inline void String::_deleteStr(int startIndex, int endIndex)
{
        verifyIndex(startIndex);
        verifyIndex(endIndex);
        // Par exemple -
        //      deleteStr(3,3) avec val = 'pokemon' retourne 'poon'
        char *tmpaa = strdup(sval); // ici malloc
        strcpy(& tmpaa[startIndex], & tmpaa[endIndex]);
        *this = tmpaa;
        free(tmpaa);
}

// Version surchargée, modifie directement l'objet
String String::deleteCharAt(int loc, bool dummy)
{
        this->_deleteCharAt(loc);
        return *this;
}

inline void String::_deleteCharAt(int loc)
{
        char *tmpaa = strdup(sval); // ici malloc
        strcpy(& tmpaa[loc], & tmpaa[loc+1]);
        *this = tmpaa;
        free(tmpaa);
}

// Retourne la chaîne avant regx. Trouve la première occurrence de regx.
String String::at(char *regx)
{
        char *tok = NULL;
        tok = strstr(sval, regx);
        if (tok == NULL)
                return(String(""));
        else
        {
                int res = (int) (tok - sval);
                char *lefttok = strdup(sval);
                memset(lefttok, 0, strlen(sval));
                strcpy(lefttok, & sval[res]);
                String tmpstr(lefttok);
                free(lefttok);
                return(tmpstr);
        }
}

// Retourne la chaîne avant regx. Trouve la première occurrence de regx.
String String::before(char *regx)
{
        char *tok = NULL;
        tok = strstr(sval, regx);
        if (tok == NULL)
                return(String(""));
        else
        {
                int res = (int) (tok - sval);
                char *lefttok = strdup(sval);
                lefttok[res] = 0;
                String tmpstr(lefttok);
                free(lefttok);
                return(tmpstr);
        }
}

// Retourne la chaîne après regx. Trouve la première occurrence de regx.
String String::after(char *regx)
{
        char *tok = NULL;
        tok = strstr(sval, regx);
        if (tok == NULL)
                return(String(""));
        else
        {
                int res = (int) (tok - sval);
                char *lefttok = strdup(sval);
                memset(lefttok, 0, strlen(sval));
                strcpy(lefttok, & sval[res + strlen(regx)]);
                String tmpstr(lefttok);
                free(lefttok);
                return(tmpstr);
        }
}

// Divise la chaîne et retourne une liste via le pointeur de tête
// de liste explodeH.
// Voir aussi token().
void String::explode(char *seperator)
{
        char *aa = NULL, *bb = NULL;
        aa = (char *) my_malloc(strlen(sval));
        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; // voir 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).sval", (*iter1).sval);
        }
}

// Version surchargée de explode(). Retourne un tableau
// de chaînes et le nombre total dans la référence strcount
// Voir aussi token().
String *String::explode(int & strcount, char seperator = ' ')
{
        String aa(sval);
        aa.trim(true);
        strcount = 0;
        for (int ii = 0, jj = strlen(aa.sval); ii < jj; ii++)
        {
                if (aa.sval[ii] == seperator)
                        strcount++;
        }

        String *tmpstr = new String[strcount+1];
        if (!strcount) // strcount == 0
                tmpstr[0] = aa.sval;
        else
        {
                for (int ii = 0; ii <= strcount; ii++)
                        tmpstr[ii] = aa.token();
        }
        return tmpstr;
}

// Agrège les chaînes pointées par la tête de liste
// explodeH et retourne la classe String.
void String::implode(char *glue)
{
}

// Agrège les chaînes pointées par la tête de liste
// explodeH et retourne la classe String.
void String::join(char *glue)
{
        implode(glue);
}

// Répète la chaîne input n fois.
String String::repeat(char *input, unsigned int multiplier)
{
        // Pour exemple -
        // repeat("k", 4) retourne "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;
}

// Renverse la chaîne.
// Version surchargée de reverse(). Modifie directement l'objet.
void String::reverse(bool dummy)
{
        this->_reverse();
}
inline void String::_reverse()
{
        // Par exemple -
        //              reverse() sur "12345" retourne "54321"
        char aa;
        unsigned long tot_len = strlen(sval);
        unsigned long midpoint = tot_len / 2;
        for (unsigned long tmpjj = 0; tmpjj < midpoint; tmpjj++)
        {
                aa = sval[tmpjj];  // variable temporaire de stockage
                sval[tmpjj] = sval[tot_len - tmpjj - 1];  // permute les valeurs
                sval[tot_len - tmpjj - 1] = aa; // permute les valeurs
        }
}

// Change certain caractères.
// Par exemple ("abcd", "ABC") change toutes les occurrences de chaque
// caractère de 'from' en le caractère correspondant dans 'to'
String String::tr(char *from, char *to)
{
        int lenfrom = strlen(from), lento = strlen(to);
        if (lento > lenfrom)
                lento = lenfrom; // choisit le min
        else
        if (lento < lenfrom)
                lenfrom = lento; // choisit le min 
        debug_("lento", lento);

        register char *aa = strdup(sval);
        for (int ii = 0, jj = strlen(sval); ii < jj; ii++) // pour chaque caractère dans val
        {
                for (int kk = 0; kk < lento; kk++) // pour chaque caractère dans "from"
                {
                        if (aa[ii] == from[kk])
                                aa[ii] = to[kk];
                }
        }
        String tmpstr(aa);
        free(aa);
        return tmpstr;
}

// Centre le texte
String String::center(int padlength, char padchar = ' ')
{
        // Par exemple -
        //              center(10, '*') avec sval="aa" retourne "****aa****"
        //              center(10) avec sval="aa" retourne "    aa    "
        // Le résultat est une chaîne contenant 'padlength' caractères avec sval au milieu.
        int tmpii = sizeof(char) * (padlength + strlen(sval) + 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, sval);
        for (int jj = strlen(aa), kk = jj + (int) padlength/2; jj < kk; jj++)
        {
                aa[jj] = padchar;
        }
        String tmpstr(aa);
        free(aa);
        return tmpstr;
}

// Formate la chaîne originale en plaçant <number> caractères <padchar>
// entre chaque ensemble de mots délimités par des blancs. Les blancs en début et
// en fin sont toujours supprimés. Si <number> est omis ou vaut 0, alors tous les
// espaces de la chaîne sont supprimés. Par défaut, <number> vaut 0 et padchar ' '.
String String::space(int number, char padchar = ' ')
{
        // Par exemple -
        //              space(3) avec sval = "Je ne sais pas"
        //                              retournera "Je   ne   sais   pas"
        //              space(1, '_') avec sval = "Un lieu profondement obscur"  
        //                              retournera "Un_lieu_profondement_obscur"
        //              space() avec sval = "Je   sais     cela"
        //                              retournera "Jesaiscela"

        debug_("this->sval", this->sval );
        String tmpstr = this->trim().sval;
        debug_("tmpstr.sval", tmpstr.sval );

        // compte les espaces
        int spacecount = 0;
        for (int ii = 0, jj = strlen(tmpstr.sval); ii < jj; ii++)
        {
                if (tmpstr.sval[ii] == ' ')
                        spacecount++;
        }
        debug_("spacecount", spacecount);

        char ee[2];
        ee[0] = padchar;
        ee[1] = 0;
        String bb = tmpstr.repeat(ee, spacecount);

        int tmpii = sizeof(char) * (strlen(tmpstr.sval) + (number * spacecount) + 20);
        char *aa = (char *) malloc(tmpii);
        memset(aa, 0, tmpii);
        for (int ii = 0, jj = strlen(tmpstr.sval); ii < jj; ii++)
        {
                if (tmpstr.sval[ii] == ' ')
                        strcat(aa, bb.sval);
                else
                {
                        ee[0] = sval[ii];
                        strcat(aa, ee);
                }
        }
        tmpstr = aa;
        free(aa);
        return tmpstr;
}

// Le résultat est une chaîne comprenant tous les caractères compris
// entre <start> et <end> (inclus).
String String::xrange(char start, char end)
{
        // Par exemple -
        //      xrange('a', 'j') retourne val = "abcdefghij"
        //      xrange(1, 8) retourne val = "12345678"

        if (end < start)
        {
                cerr << "\nThe 'end' character is less than 'start' !!" << endl;
                return String("");
        }

        // Note : 'end' est plus grand que 'start' ! Et ajoute +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;
}

// Supprime tous les caractères contenus dans <list>. Le caractère par défaut pour
// <list> est l'espace ' '.
String String::compress(char *list = " ")
{
        // Par exemple -
        //      compress("$,%") avec sval = "$1,934" retourne "1934"
        //      compress() avec sval = "appelez moi alavoor vasudevan" returns "appelezmoialavoorvasudevan"
        int lenlist = strlen(list);
        register char *aa = strdup(sval);
        for (int ii = 0, jj = strlen(sval); ii < jj; ii++) // pour chaque caractère de sval
        {
                for (int kk = 0; kk < lenlist; kk++) // pour chaque caractère de "from"
                {
                        if (aa[ii] == list[kk])
                        {
                                strcpy(& aa[ii], & aa[ii+1]);
                        }
                }
        }
        String tmpstr(aa);
        free(aa);
        return tmpstr;
}

// <newstr> est insérée dans sval à partir de <start>. <newstr> est
// complétée ou tronquée à <length> caractères. <length> est par défaut la
// longueur de la chaîne <newstr> 
String String::insert(char *newstr, int start = 0, int lengthstr = 0, char padchar = ' ')
{
        // Par exemple -
        //      insert("quelquechose de nouveau", 8, 30, '*') avec sval = "vieille chose"      
        //              retourne "vieille quelquechose de nouveau*******chose"

        int tmplen = sizeof(char) * strlen(sval) + strlen(newstr) + lengthstr + 10;
        char *tmpaa = (char *) malloc (tmplen);
        memset(tmpaa, 0, tmplen);
        if (!start) // start == 0
        {
                strcpy(tmpaa, newstr);
                strcat(tmpaa, this->sval);
        }
        else
        {
                strncpy(tmpaa, this->sval, start);
                strcat(tmpaa, newstr);
                strcat(tmpaa, & this->sval[start]);
        }

        String tmpstr(tmpaa);
        free(tmpaa);
        return tmpstr;
}

// Fonction insert surchargée
String String::insert(int index, String str2, bool dummy)
{
        *this =  this->insert(str2.sval, index).sval;
        //debug_("tmpstr.sval", tmpstr.sval);
        return *this;
}

// Fonction insert surchargée
String String::insert(int index, char ch, bool dummy)
{
        char aa[2];
        aa[0] = ch;
        aa[1] = 0;
        *this = this->insert(aa, index).sval;
        //debug_("tmpstr.sval", tmpstr.sval);
        return *this;
}

// Le résultat est une chaîne de <length> caractères composée des caractères les plus à gauches de sval.
// Méthode rapide pour justifier à gauche une chaîne.
String String::left(int slength = 0, char padchar = ' ')
{
        // Par exemple -
        //      left(15) avec sval = "Wig"       retourne "Wig            "
        //      left(4) avec  sval = "Wighat"    retourne "Wigh"
        //      left() avec   sval = "   Wighat" retourne "Wighat   "
        if (!slength) // slength == 0
                slength = strlen(sval);
        debug_("left() slength", slength);

        int tmpii = slength + 20;
        char *aa = (char *) malloc(tmpii);
        memset(aa, 0, tmpii);
        debug_("this->ltrim().sval ", this->ltrim().sval);
        strcpy(aa, this->ltrim().sval);
        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) ).sval);
        }
        else
        {
                aa[slength] = 0;
        }

        debug_("left() aa", aa );
        String tmpstr(aa);
        free(aa);
        return tmpstr;
}

// Le résultat est une chaîne de <length> caractères composée des caractères les plus à droite de sval.
// Méthode rapide pour justifier à droite un chaîne.
String String::right(int slength = 0, char padchar = ' ')
{
        // Par exemple -
        //      right(10) avec sval = "never to saying   " retourne " to saying"
        //      right(4) avec  sval = "Wighat"             retourne "ghat"
        //      right(8) avec  sval = "4.50"               retourne "    4.50"
        //      right() avec   sval = "  4.50     "        retourne "       4.50"

        if (!slength) // slength == 0
                slength = strlen(sval);
        debug_("right() slength", slength);

        int tmpii = slength + 20;
        char *aa = (char *) malloc(tmpii);
        memset(aa, 0, tmpii);

        int currlen = strlen(this->rtrim().sval);
        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) ).sval);
                strcat(aa, this->rtrim().sval);
                debug_("right() aa", aa );
        }
        else
        {
                strcpy(aa, this->rtrim().sval);
                strcpy(aa, & aa[currlen-slength]);
                aa[slength] = 0;
        }

        debug_("right() aa", aa );
        String tmpstr(aa);
        free(aa);
        return tmpstr;
}

// <newstr> est superposée à sval en commençant à <start>. <newstr> est complétée
// ou tronquée à <length> caractères. Par défaut, la longueur <length> est la
// longueur de la chaîne newstr.
String String::overlay(char *newstr, int start = 0, int slength = 0, char padchar = ' ')
{
        // Par exemple -
        //      overlay("12345678", 4, 10, '*') sur sval = "oldthing is very bad"
        //              retourne "old12345678**ery bad"
        //      overlay("12345678", 4, 5, '*') sur sval = "oldthing is very bad"
        //              retourne "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)
        {
                // remplire maintenant
                strcpy(aa, newstr);
                strcat(aa, this->repeat(ee, (slength-len_newstr)).sval );
        }
        else
        {
                strcpy(aa, newstr);
                aa[slength] = 0;
        }

        // Maintenant recouvrir la chaîne
        String tmpstr(sval);

        debug_("tmpstr.sval", tmpstr.sval);
        for (int ii=start, jj=strlen(tmpstr.sval), kk=start+slength, mm=0; 
                                ii < jj; ii++, mm++)
        {
                if (ii == kk)
                        break;
                if (mm == slength)
                        break;
                tmpstr.sval[ii] = aa[mm];
        }
        free(aa);
        debug_("tmpstr.sval", tmpstr.sval);
        return tmpstr;
}

// Si la chaîne est littéralement égale à ou non égale à
// Si type vaut false alors ==
bool String::_equalto(const String & rhs, bool type = false)
{
        if (type == false) // test ==
        {
                if (strlen(rhs.sval) == strlen(sval))
                {
                        if (!strncmp(rhs.sval, sval, strlen(sval))) //  == 0
                                return true;
                        else
                                return false;
                }
                else
                        return false;
        }
        else // test !=
        {
                if (strlen(rhs.sval) != strlen(sval))
                {
                        if (!strncmp(rhs.sval, sval, strlen(sval))) //  == 0
                                return true;
                        else
                                return false;
                }
                else
                        return false;
        }
}

// Si la chaîne est littéralement égale à ou non égale à
// Si type vaut false alors ==
bool String::_equalto(const char *rhs, bool type = false)
{
        if (type == false) // test ==
        {
                if (strlen(rhs) == strlen(sval))
                {
                        if (!strncmp(rhs, sval, strlen(sval))) //  == 0
                                return true;
                        else
                                return false;
                }
                else
                        return false;
        }
        else // test !=
        {
                if (strlen(rhs) != strlen(sval))
                {
                        if (!strncmp(rhs, sval, strlen(sval))) //  == 0
                                return true;
                        else
                                return false;
                }
                else
                        return false;
        }
}

// Fonction synonyme de vacuum()
void String::clear()
{
        sval = (char *) my_realloc(sval, 10);
        sval[0] = '\0';
}

// Supprime tous les caractères 'ch' en fin de chaîne - voir aussi chop()
// Par exemple : 
//      sval = "abcdef\n\n\n" alors chopall() = "abcdef"
//      sval = "abcdefffff" alors chopall('f') = "abcde"
void String::chopall(char ch='\n')
{
        unsigned long tmpii = strlen(sval) - 1 ;
        for (; tmpii >= 0; tmpii--)
        {
                if (sval[tmpii] == ch)
                        sval[tmpii] = 0;
                else
                        break;
        }
}

// Supprime le caractère de fin de la chaîne - voir aussi chopall()
// chop() est souvent utilisé pour supprimer le caractère de fin de ligne
void String::chop()
{
        sval[strlen(sval)-1] = 0;
}

// Version surchargée de trim(). Modifie directement l'objet.
void String::trim(bool dummy)
{
        this->_trim();
}

inline void String::_trim()
{
        this->rtrim(true);
        this->ltrim(true);
        debug_("this->sval", this->sval);
}

// Version surchargée de ltrim(). Modifie directement l'objet.
void String::ltrim(bool dummy)
{
        this->_ltrim();
}

inline void String::_ltrim()
{
        // Peut causer des problèmes dans my_realloc car 
        // l'emplacement de bb peut être détruit !
        char *bb = sval;

        if (bb == NULL)
                return;

        while (isspace(*bb))
                bb++;
        debug_("bb", bb);

        if (bb != NULL && bb != sval)
        {
                debug_("doing string copy", "done");
                _str_cpy(bb); // cause des problèmes dans my_realloc et bb va être détruit !
        }
        else
                debug_("Not doing string copy", "done");
}

String String::ltrim()
{
        String tmpstr(sval);
        tmpstr._ltrim();
        return tmpstr;
}

// Version surchargée de rtrim(). Modifie directement l'objet.
void String::rtrim(bool dummy)
{
        this->_rtrim();
}

inline void String::_rtrim()
{
        for (long tmpii = strlen(sval) - 1 ; tmpii >= 0; tmpii--)
        {
                if ( isspace(sval[tmpii]) )
                        sval[tmpii] = '\0';
                else
                        break;
        }
}

String String::rtrim()
{
        String tmpstr(sval);
        tmpstr._rtrim();
        return tmpstr;
}

// Utilisé pour arrondir la partie frationnaire de réels.
// Arrondit les réels avec la précision souhaitée et stocke
// le résultat dans le champ sval de la chaîne.
// Retourne aussi le résultat comme un 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) // précision maximale supportée
                precision = MAX_PREC;

        // récupère les parties entière et décimale du réel
        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) );

        sval = (char *) my_malloc(NUMBER_LENGTH); // float 70 chiffres max

        if (deci_int > 999) // (MAX_PREC) chiffres
                sprintf(sval, "%lu.%lu", (unsigned long) integ_flt, deci_int); 
        else
        if (deci_int > 99) // (MAX_PREC - 1) chiffres
                sprintf(sval, "%lu.0%lu", (unsigned long) integ_flt, deci_int); 
        else
        if (deci_int > 9) // (MAX_PREC - 2) chiffres
                sprintf(sval, "%lu.00%lu", (unsigned long) integ_flt, deci_int); 
        else
                sprintf(sval, "%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) // précision maximale supportée
                precision = MAX_PREC;

        debug_("In roundd", "ok");
        // récupère les parties entière et décimale du réel
        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);

        sval = (char *) my_malloc(NUMBER_LENGTH); // double 70 chiffres max

        unsigned long deci_int = (unsigned long) ( rint(deci_flt) );

        if (deci_int > 99999) // (MAX_PREC) chiffres
                sprintf(sval, "%lu.%lu", (unsigned long) integ_flt, deci_int); 
        else
        if (deci_int > 9999) // (MAX_PREC - 1) chiffres
                sprintf(sval, "%lu.0%lu", (unsigned long) integ_flt, deci_int); 
        else
        if (deci_int > 999) // (MAX_PREC - 2) chiffres
                sprintf(sval, "%lu.00%lu", (unsigned long) integ_flt, deci_int); 
        else
        if (deci_int > 99) // (MAX_PREC - 3) chiffres
                sprintf(sval, "%lu.000%lu", (unsigned long) integ_flt, deci_int); 
        else
        if (deci_int > 9) // (MAX_PREC - 4) chiffres
                sprintf(sval, "%lu.0000%lu", (unsigned long) integ_flt, deci_int); 
        else // (MAX_PREC - 5) chiffres
                sprintf(sval, "%lu.00000%lu", (unsigned long) integ_flt, deci_int); 
}

// Fournie seulement pour documenter
// Vous devriez utiliser la fonction indexOf()
bool String::contains(char *str2, int startIndex = 0) 
{
        // Par exemple -
        //              if (indexOf("ohboy") > -1 )
        //                      cout << "\nString contient 'ohboy'" << endl;
        //              if (indexOf("ohboy") < 0 )
        //                      cout << "\nString NE contient PAS 'ohboy'" << endl;
        //              if (indexOf("ohboy", 4) > -1 )
        //                      cout << "\nString contient 'ohboy'" << endl;
        //              if (indexOf("ohboy", 4) < 0 )
        //                      cout << "\nString NE contient PAS 'ohboy'" << endl;
        cerr << "\nYou must use indexOf() function instead of contains()\n" << endl;
        exit(-1);
}

// Fonction synonyme de empty()
bool String::isNull()
{
        if (sval[0] == '\0')
                return true;
        else
        {
                if (sval == NULL)
                        return true;
                else
                        return false;
        }
}

// Les caractères blancs de début et de fin sont ignorés.
bool String::isInteger()
{
        String tmpstr(sval);
        tmpstr.trim(true);
        debug_("tmpstr.sval", tmpstr.sval );
        if ( strspn ( tmpstr.sval, "0123456789" ) != strlen(tmpstr.sval) )
                return ( false ) ;
        else
                return ( true ) ;
}

// Fonction surchargée
bool String::isInteger(int pos) 
{
        verifyIndex(pos);
        return (isdigit(sval[pos]));
}

// Les caractères blancs de début et de fin sont ignorés.
bool String::isNumeric()
{
        String tmpstr(sval);
        tmpstr.trim(true);
        debug_("tmpstr.sval", tmpstr.sval );
        if ( strspn ( tmpstr.sval, "0123456789.+-e" ) != strlen(tmpstr.sval) )
                return ( false ) ;
        else
                return ( true ) ;
}

// Fonction surchargée
bool String::isNumeric(int pos) 
{
        verifyIndex(pos);
        return (isdigit(sval[pos]));
}

bool String::isEmpty()
{
        if (strlen(sval) == 0)
                return true;
        else
                return false;
}

// Voir aussi explode()
//      Attention : l'objet String est modifié et ne contient plus le token renvoyé.
//                  Il est conseillé de sauvegarder la chaîne originale avant d'appeler
//                  cette fonction, comme par exemple ainsi :
//              String savestr = origstr;
//              String aa, bb, cc;
//              aa = origstr.token();
//              bb = origstr.token();
//              cc = origstr.token();
//
//  Cette méthode retourne le premier token non séparateur (par défaut espace) de la chaîne.
String String::token(char seperator = ' ') 
{
        char ee[2];
        ee[0] = seperator;
        ee[1] = 0;
        char *res = strtok(sval, ee);
        if (!res) // if res == NULL
        {
                debug_("token", res);
                debug_("sval", sval);
                return(String(sval));
        }
        else
        {
                String tmpstr(res);

                // Utilise la longueur de la chaîne sval et pas celle de res
                // car strtok() a mis un NULL ('\0') sur l'emplacement et
                // aussi car strtok() ignore les blancs initiaux de sval
                strcpy(sval, & sval[strlen(sval)+1]);
                debug_("token", res);
                debug_("sval", sval);
                return tmpstr;
        }
}

String String::crypt(char *original, char *salt)
{
        return String("");
}

int String::toInteger()
{
        if ( strlen(sval) == 0 ) {
                cerr << "Cannot convert a zero length string "
                << " to a numeric" << endl ;
                abort() ;
        }

        if ( ! isInteger() ) {
                cerr << "Cannot convert string [" << sval
                << "] to an integer numeric string" << endl ;
                abort() ;
        }

        return ( atoi ( sval ) ) ;
}

long String::parseLong()
{
        if ( strlen(sval) == 0 ) {
                cerr << "Cannot convert a zero length string "
                << " to a numeric" << endl ;
                abort() ;
        }

        if ( ! isInteger() ) {
                cerr << "Cannot convert string [" << sval
                << "] to an integer numeric string" << endl ;
                abort() ;
        }

        return ( atol ( sval ) ) ;
}

double String::toDouble()
{
        if ( strlen(sval) == 0 ) {
                cerr << "Cannot convert a zero length string "
                << " to a numeric" << endl ;
                abort() ;
        }

        if ( ! isNumeric() ) {
                cerr << "Cannot convert string [" << sval
                << "] to a double numeric string" << endl ;
                abort() ;
        }

        double d = atof ( sval ) ;

        return ( d ) ;
}

String String::getline(FILE *infp = stdin)
{
        register char ch, *aa = NULL;

        register const short SZ = 100;
        // Valeur initiale de ii > SZ donc aa est de la mémoire allouée
        register int jj = 0;
        for (int ii = SZ+1; (ch = getc(infp)) != EOF; ii++, jj++)
        {
                if (ii > SZ)  // alloue la memoire en paquets de SZ pour la performance
                {
                        aa = (char *) realloc(aa, jj + ii + 15);  // +15 par sécurité
                        ii = 0;
                }
                if (ch == '\n')  // lit jusqu'à rencontrer une nouvelle ligne
                        break;
                aa[jj] = ch;
        }
        aa[jj] = 0;
        _str_cpy(aa);  // met la valeur dans la chaîne
        free(aa);
        return *this;
}

/*
void String::Format(const char *fmt, ... )
{
        va_list iterator;
        va_start(iterator, fmt );
        va_end(iterator);
}
*/

// contrôle qu'un indice se trouve dans les limites
inline void String::verifyIndex(unsigned long index) const
{
        if (index < 0 || index >= strlen(sval) )
        {
                // throw "Index Out Of Bounds Exception";
                cerr << "Index Out Of Bounds Exception at ["
                                << index << "] in:\n" << sval << endl;
                exit(1);
        }
}

// contrôle qu'un indice se trouve dans les limites
inline void String::verifyIndex(unsigned long index, char *aa) const
{
        if (!aa) // aa == NULL
        {
                cerr << "\nverifyIndex(long, char *) str null value\n" << endl;
                exit(-1);
        }
        if (index < 0 || index >= strlen(aa) )
        {
                cerr << "Index Out Of Bounds Exception at ["
                                << index << "] in:\n" << aa << endl;
                exit(1);
        }
}

//////////////////////////////////////////////////////////
// Les fonctions privées commencent à partir d'ici...
//////////////////////////////////////////////////////////
void String::_str_cpy(char bb[])
{
        debug_("In _str_cpy bb", bb);
        if (bb == NULL)
        {
                sval[0] = '\0';
                return;
        }

        unsigned long tmpii = strlen(bb);

        if (tmpii == 0)
        {
                sval[0] = '\0';
                return;
        }

        debug_("In _str_cpy tmpii", tmpii);
        debug_("In _str_cpy sval", sval);
        sval = (char *) my_realloc(sval, tmpii);
        //sval = new char [tmpii + SAFE_MEM_2];
        debug_("In _str_cpy bb", bb);
        
        strncpy(sval, bb, tmpii);
        debug_("In _str_cpy sval", sval);
        sval[tmpii] = '\0';
        debug_("In _str_cpy sval", sval);
}

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(sval);
        sval = (char *) my_realloc(sval, tmpii + tmpjj);
        debug_("sval in _str_cat() ", sval);
        strncat(sval, bb, tmpjj);
}

void String::_str_cat(int bb)
{
        char tmpaa[100];
        sprintf(tmpaa, "%d", bb);

        unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(sval);
        sval = (char *) my_realloc(sval, tmpii + tmpjj);
        strncat(sval, tmpaa, tmpjj);
}

void String::_str_cat(unsigned long bb)
{
        char tmpaa[100];
        sprintf(tmpaa, "%ld", bb);

        unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(sval);
        sval = (char *) my_realloc(sval, tmpii + tmpjj);
        strncat(sval, tmpaa, tmpjj);
}

void String::_str_cat(float bb)
{
        char tmpaa[100];
        sprintf(tmpaa, "%f", bb);

        unsigned long tmpjj = strlen(tmpaa), tmpii = strlen(sval);
        sval = (char *) my_realloc(sval, tmpii + tmpjj);
        strncat(sval, tmpaa, tmpjj);
}

//////////////////////////////////////////////////////////
// Les opérateurs sont définis à partir d'ici...
//////////////////////////////////////////////////////////
String operator+ (const String & lhs, const String & rhs)
{
        /*******************************************************/
        // Note : pour concaténer deux chaînes, transtyper d'abord
        // en String comme ici :
        //aa = (String) "alkja " + " 99djd " ;
        /*******************************************************/

        String tmp(lhs);
        tmp._str_cat(rhs.sval);
        return(tmp);

        /*
        if (String::_global_String == NULL)
        {
                String::_global_String = new String;
                String::_global_String->_str_cpy(lhs.sval);
                String::_global_String->_str_cat(rhs.sval);
                //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.sval);
                String::_global_String1->_str_cat(rhs.sval);
                return *String::_global_String1;
        }
        */
        /*
        else
        {
                fprintf(stderr, "\nError: cannot alloc _global_String\n");
                exit(-1);
        }
        */

        /*
        String *aa = new String;
        aa->_str_cpy(lhs.sval);
        aa->_str_cat(rhs.sval);
        return *aa;
        */
}

String String::operator+ (const String & rhs)
{
        String tmp(*this);
        tmp._str_cat(rhs.sval);
        debug_("rhs.sval in operator+", rhs.sval );
        debug_("tmp.sval in operator+", tmp.sval );
        return (tmp);
}

// L'utilisation d'une référence accélèrera l'opérateur =
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.sval);
        debug_("rhs value", rhs.sval );

        // Libere la memoire des variables globales
        //_free_glob(& String::_global_String);
        //if (String::_global_String == NULL)
                //fprintf(stderr, "\n_global_String is freed!\n");

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

// L'utilisation d'une référence accélèrera l'opérateur =
String& String::operator+= (const String & rhs)
{
        /*******************************************************/
        // Note : pour concaténer deux chaînes, transtyper d'abord
        // en String comme ici :
        //aa = (String) "cccc " + " dddd " ;
        /*******************************************************/

        if (& rhs == this)
        {
                debug_("Fatal error: In operator+= rhs is equals 'this' ptr", "ok");
                return *this;
        }
        this->_str_cat(rhs.sval);
        return *this;
        //return (String(*this));
}

bool String::operator== (const String & rhs)
{
        return(_equalto(rhs.sval));
}

bool String::operator== (const char *rhs)
{
        return(_equalto(rhs));
}

bool String::operator!= (const String & rhs)
{
        return(_equalto(rhs.sval, true));
}

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

char String::operator[] (unsigned long Index) const
{
        verifyIndex(Index);
        return sval[Index];
}

char & String::operator[] (unsigned long Index)
{
        verifyIndex(Index);
        return sval[Index];
}

istream & operator >> (istream & In, String & str2)
{
        // alloue la taille max de 2048 caractères
        static char aa[MAX_ISTREAM_SIZE]; 

        In >> aa;
        str2 = aa; // affecte aa à la référence
        return In; // retourne un istream
}

ostream & operator << (ostream & Out, const String & str2)
{
        Out << str2.sval;
        return Out;
}

////////////////////////////////////////////////////
//  Imite StringBuffer Object
//      MéThodes de StringBuffer
////////////////////////////////////////////////////

// Imite StringBuffer ; le constructeur par défaut
// (celui sans paramètre) réserve de la place pour 16
// caractères.
StringBuffer::StringBuffer()
        :String()   // appelle le constructeur de la classe de base sans paramètres
{
        debug_("in StringBuffer cstr()", "ok");
}

// Imite StringBuffer
StringBuffer::StringBuffer(int size)
        :String(size, true) // appelle le constructeur de la classe de base sans paramètres
{
        // String(size, true) -- ne pas l'appeler ici dans le corps de la
        // fonction mais durant la phase d'initialisation pour éviter un
        // appel supplémentaire du constructeur par défaut de la classe de
        // base et être plus rapide et plus efficace
        debug_("in StringBuffer cstr(int size)", "ok");
}

// Imite StringBuffer  
// appelle le constructeur de la classe de base avec une chaîne en paramètre
StringBuffer::StringBuffer(String str)
        :String(str.val())  // appelle le constructeur de la classe de base
{
        // String(str.val()) -- ne pas l'appeler ici dans le corps de la
        // fonction mais durant la phase d'initialisation pour éviter un
        // appel supplémentaire du constructeur par défaut de la classe de
        // base et être plus rapide et plus efficace
        debug_("in StringBuffer cstr(String str)", "ok");
}

// Imite StringBuffer 
StringBuffer::~StringBuffer()
{
        debug_("in StringBuffer dstr()", "ok");
}

// Imite la classe Float
// appelle le constructeur de la classe de base avec une chaîne en paramètre
Float::Float(String str)
        :String(str.val())  // appelle le constructeur de la classe de base
{
        // String(str.val()) -- ne pas l'appeler ici dans le corps de la
        // fonction mais durant la phase d'initialisation pour éviter un
        // appel supplémentaire du constructeur par défaut de la classe de
        // base et être plus rapide et plus efficace
        debug_("in Float cstr(String str)", "ok");
}

// Imite la classe Double
// appelle le constructeur de la classe de base avec une chaîne en paramètre
Double::Double(String str)
        :String(str.val())  // appelle le constructeur de la classe de base
{
        // String(str.val()) -- ne pas l'appeler ici dans le corps de la
        // fonction mais durant la phase d'initialisation pour éviter un
        // appel supplémentaire du constructeur par défaut de la classe de
        // base et être plus rapide et plus efficace
        debug_("in Double cstr(String str)", "ok");
}

// Imite la classe StringReader
// appelle le constructeur de la classe de base avec une chaîne en paramètre
StringReader::StringReader(String str)
        :String(str.val())  // appelle le constructeur de la classe de base
{
        // String(str.val()) -- ne pas l'appeler ici dans le corps de la
        // fonction mais durant la phase d'initialisation pour éviter un
        // appel supplémentaire du constructeur par défaut de la classe de
        // base et être plus rapide et plus efficace
        debug_("in StringReader cstr(String str)", "ok");
        _curpos = 0;
        _mark_pos = 0;
}

// Imite la méthode read de la classe StringReader
int StringReader::read()
{
        _curpos++;
        if (_curpos > strlen(sval) )
                return -1;
        return sval[_curpos-1];
}

// Lit des caractères dans une portion d'un tableau
// cbuf est le tampon destination, offset est le décalage indiquant où écrire
// les caractères, length est le nombre maximum de caractères à lire
// Retourne le nombre de caractères lus ou -1 en cas de fin du flux
int StringReader::read(char cbuf[], int offset, int length)
{
        if (_curpos > strlen(sval) - 1 )
                return -1;
        strncpy(& cbuf[offset], & sval[_curpos], length);
        _curpos += length;
        return length;
}

// Marque la position courante dans le flux. Les appels suivants
// à reset() repositionneront le flux à ce point.
// Le paramètre 'readAheadLimit' limite le nombre de caractères qui
// pourraient être lus tout en préservant la marque.
// Comme le flux d'entrée provient d'une chaîne, il n'y a pas de
//limite actuellement, donc l'argument est ignoré.
void StringReader::mark(int readAheadLimit)
{
        _mark_pos = _curpos;
}
// réinitialise le flux à la marque la plus récente, ou au début de
// la chaîne si aucun marque n'a été posée
void StringReader::reset()
{
        _curpos = _mark_pos;
}

// Passe des caractères. Cette méthode bloquera jusqu'a ce que des caractères soient
// disponibles, qu'une erreur arrive ou que la fin du flux soit atteinte.
// Paramètre ii : nombre de caractères à passer
// Retourne : le nombre courant de caractères passés
long StringReader::skip(long ii)
{
        long tmpjj = strlen(sval) - _curpos - 1;
        if (ii > tmpjj)
                ii = tmpjj;
        _curpos = ii;
        return ii;
}

// Imite la classe StringWriter
StringWriter::StringWriter()
{
        debug_("in StringWriter cstr()", "ok");
        char *aa = (char *) malloc(300);
        memset(aa, ' ', 299); // remplit avec des blancs
        aa[300] = 0;
        String((char *) aa);
        my_free(aa);
}
StringWriter::StringWriter(int bufferSize)
{
        debug_("in StringWriter cstr(int bufferSize)", "ok");
        char *aa = (char *) malloc(bufferSize);
        memset(aa, ' ', bufferSize-1); // remplit avec des blancs
        aa[bufferSize] = 0;
        String((char *) aa);
        my_free(aa);
}
void StringWriter::write(int bb)
{
        _str_cat(bb);
}
void StringWriter::write(char *bb)
{
        _str_cat(bb);
}
void StringWriter::write(String bb)
{
        _str_cat(bb.val());
}
void StringWriter::write(char *bb, int startIndex, int endIndex)
{
        char *aa = strdup(bb); // teste le null dans verifyIndex
        verifyIndex(startIndex, aa);
        verifyIndex(endIndex, aa);
        aa[endIndex] = 0;
        _str_cat(& aa[startIndex]);
}
void StringWriter::write(String str, int startIndex, int endIndex)
{
        write(str.val(), startIndex, endIndex);
}


Page suivante Page précédente Table des matières