Started a test setup
[AXE.git] / src / string.cpp
index 6221f2f..352e638 100644 (file)
@@ -5,7 +5,7 @@
 ***********************
 **      FILE NAME      : string.cpp
 **      SYSTEM NAME    : Andromeda X-Windows Encapsulation
-**      VERSION NUMBER : $Revision: 1.1 $
+**      VERSION NUMBER : $Revision: 1.5 $
 **
 **  DESCRIPTION      :  String class implementation.
 **
 ********************************
 **      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
 **      CREATION DATE   : Nov 17, 1997
-**      LAST UPDATE     : Aug 26, 1999
+**      LAST UPDATE     : Nov 30, 2003
 **      MODIFICATIONS   : 
 **************************************************************************/
 
 /*****************************
    $Log: string.cpp,v $
-   Revision 1.1  2002-07-25 08:01:27  arjen
+   Revision 1.5  2007-05-04 13:55:18  arjen
+   Dynamically allocate more memory if the string buffer runs out of space when
+   reading a String object from an input stream.
+
+   Revision 1.4  2003/03/29 07:18:54  arjen
+   String constructor and assignment from char * are more robust fro NULL pointers.
+
+   Revision 1.3  2002/11/03 13:18:57  arjen
+   New functions - String::escape() and String::unescape()
+
+   Revision 1.2  2002/09/28 06:42:11  arjen
+   A few small bug fixes.
+
+   Revision 1.1  2002/07/25 08:01:27  arjen
    First checkin, AXE release 0.2
 
 *****************************/
 
-static const char RCSID[] = "$Id: string.cpp,v 1.1 2002-07-25 08:01:27 arjen Exp $";
+static const char RCSID[] = "$Id: string.cpp,v 1.5 2007-05-04 13:55:18 arjen Exp $";
 
 #include <stdio.h>
 #include <ctype.h>
@@ -55,9 +68,16 @@ String::String(char c)    //  Create a String from a char
 String::String(const char *s)    //  Create a String from a char *
 {
    p = new srep;
-   p->s = new char[strlen(s)+1];
-   strcpy(p->s, s);
+
+   p->s = 0;
    p->n = 1;
+
+   if (s != 0)
+   {
+      p->s = new char[strlen(s)+1];
+      strcpy(p->s, s);
+      p->n = 1;
+   }
 }
 
 String::String(const String& x)   // Create a String from another String
@@ -116,9 +136,12 @@ String& String::operator=(const char *s)
    else if (p->n == 1)
       delete p->s;
 
-   p->s = new char[strlen(s)+1];
-   strcpy(p->s, s);
-   p->n = 1;
+   if (s != 0)
+   {
+      p->s = new char[strlen(s)+1];
+      strcpy(p->s, s);
+      p->n = 1;
+   }
    return *this;
 }
 
@@ -351,27 +374,48 @@ String& substring::operator=(const String &x)
 
 /*   Input and output   */
 
-ostream& operator<<(ostream& s, const String& x)
+std::ostream& operator<<(std::ostream& s, const String& x)
 {
    if (x.p->s)
       s << x.p->s;
    return s;
 }
 
-istream& operator>>(istream& s, String& x)
+std::istream& operator>>(std::istream& s, String& x)
 {
-   char  buf[1024];
+   char  *buf;
    int   i;
 
+   int   bufsize = 1024;
+
+   buf = new char[bufsize];
+
    i = -1;
    do
    {
+      if (i >= bufsize)
+      {
+         //  Buffer is too small. Allocate some new space.
+
+         char *newbuf = new char[bufsize * 2];
+         memcpy(newbuf, buf, bufsize);
+         delete [] buf;
+         buf = newbuf;
+         bufsize *= 2;
+      }
+
       i++;
       s.get(buf[i]);
    }
-   while (buf[i] != '\n');
-   buf[i] = '\0';
+   while (s && buf[i] != '\n');
+   if (buf[i] == '\n')
+   {
+      buf[i] = '\0';
+   }
    x = buf;
+
+   delete [] buf;
+
    return s;
 }
 
@@ -384,7 +428,7 @@ char& String::operator[](int i)
    return p->s[i];
 }
 
-String String::upper(void)
+String String::upper()
 {
    String  up;
    int     i;
@@ -400,7 +444,7 @@ String String::upper(void)
    return up;
 }
 
-String String::lower(void)
+String String::lower()
 {
    String  low;
    int     i;
@@ -416,6 +460,208 @@ String String::lower(void)
    return low;
 }
 
+String String::escape()
+{
+   const int BUFSIZE = 500;
+
+   char   buffer[BUFSIZE];
+   String escaped = "";
+   int    i;              //  Index in buffer[]
+   int    j;              //  Index in *this
+
+   i = 0;
+   for (j = 0; p->s[j] != '\0'; j++)
+   {
+      if (i + 5 > BUFSIZE)
+      {
+         escaped += buffer;
+         i = 0;
+      }
+
+      switch (p->s[j])
+      {
+      case '\a':
+         buffer[i++] = '\\';
+         buffer[i++] = 'a';
+         break;
+
+      case '\b':
+         buffer[i++] = '\\';
+         buffer[i++] = 'b';
+         break;
+
+      case '\f':
+         buffer[i++] = '\\';
+         buffer[i++] = 'f';
+         break;
+
+      case '\n':
+         buffer[i++] = '\\';
+         buffer[i++] = 'n';
+         break;
+
+      case '\r':
+         buffer[i++] = '\\';
+         buffer[i++] = 'r';
+         break;
+
+      case '\t':
+         buffer[i++] = '\\';
+         buffer[i++] = 't';
+         break;
+
+      case '\v':
+         buffer[i++] = '\\';
+         buffer[i++] = 'v';
+         break;
+
+      case '\'':
+         buffer[i++] = '\\';
+         buffer[i++] = '\'';
+         break;
+
+      case '"':
+         buffer[i++] = '\\';
+         buffer[i++] = '"';
+         break;
+
+      case '\\':
+         buffer[i++] = '\\';
+         buffer[i++] = '\\';
+         break;
+
+      default:
+         if (p->s[j] > '\x20' && p->s[j] < '\x7F')
+         {
+            buffer[i++] = p->s[j];
+         }
+         else
+         {
+            short   nibble;
+
+            //  Turn into hexadecimal representation
+
+            buffer[i++] = '\\';
+            buffer[i++] = 'x';
+            nibble = (p->s[j] >> 4) & 0x0f;
+            buffer[i++] = nibble < 10 ? nibble + '0' : nibble - 10 + 'A';
+            nibble = p->s[j] & 0x0f;
+            buffer[i++] = nibble < 10 ? nibble + '0' : nibble - 10 + 'A';
+         }
+         break;
+      }
+   }
+
+   buffer[i] = '\0';
+   escaped += buffer;
+
+   return escaped;
+}
+
+String String::unescape()
+{
+   String unescaped;
+   char   *s, *d;
+
+   unescaped.p->s = new char[strlen(p->s)+1];
+   s = p->s;
+   d = unescaped.p->s;
+
+   while (*s != '\0')
+   {
+      if (*s == '\\')
+      {
+         s++;
+
+         switch (*s)
+         {
+         case 'a':
+            *d = '\a';
+            break;
+
+         case 'b':
+            *d = '\b';
+            break;
+
+         case 'f':
+            *d = '\f';
+            break;
+
+         case 'n':
+            *d = '\n';
+            break;
+
+         case 'r':
+            *d = '\r';
+            break;
+
+         case 't':
+            *d = '\t';
+            break;
+
+         case 'v':
+            *d = '\v';
+            break;
+
+         case '\'':
+            *d = '\'';
+            break;
+
+         case '"':
+            *d = '"';
+            break;
+
+         case '\\':
+            *d = '\\';
+            break;
+
+         case '0':
+         case '1':
+         case '2':
+         case '3':
+         case '4':
+         case '5':
+         case '6':
+         case '7':
+            *d = 0;
+            while (*s >= '0' && *s <= '7')
+            {
+               *d *= 8;
+               *d += *s - '0';
+               s++;
+            }
+            s--;
+            break;
+
+         case 'x':
+            *d = 0;
+            s++;           //  Skip the initial 'x'
+            while (isxdigit(*s))
+            {
+               *d *= 16;
+               *d += *s > '9' ? toupper(*s) - 'A' + 10 : *s - '0';
+               s++;
+            }
+            s--;
+            break;
+
+         default:
+            *d = *s;
+            break;
+         }
+      }
+      else
+      {
+         *d = *s;
+      }
+      s++;
+      d++;
+   }
+
+   return unescaped;
+}
+
+
 // Find the first occurance of 'c'
 
 int String::index(char c)