Index: fmtext.c
===================================================================
--- fmtext.c	(revision d3c318b302b614e2dd871854e076ea0455477083)
+++ fmtext.c	(revision 7e111f4408b99cd75667d6a99ec6e061fdfbd546)
@@ -6,8 +6,5 @@
 void owl_fmtext_init_null(owl_fmtext *f)
 {
-  f->textlen = 0;
-  f->bufflen = 5;
-  f->textbuff = owl_malloc(5);
-  f->textbuff[0] = 0;
+  f->buff = g_string_new("");
   f->default_attrs = OWL_FMTEXT_ATTR_NONE;
   f->default_fgcolor = OWL_COLOR_DEFAULT;
@@ -19,17 +16,8 @@
 void owl_fmtext_clear(owl_fmtext *f)
 {
-  f->textlen = 0;
-  f->textbuff[0] = 0;
+  g_string_truncate(f->buff, 0);
   f->default_attrs = OWL_FMTEXT_ATTR_NONE;
   f->default_fgcolor = OWL_COLOR_DEFAULT;
   f->default_bgcolor = OWL_COLOR_DEFAULT;
-}
-
-static void _owl_fmtext_realloc(owl_fmtext *f, int newlen)
-{
-    if(newlen + 1 > f->bufflen) {
-      f->textbuff = owl_realloc(f->textbuff, newlen + 1);
-      f->bufflen = newlen+1;
-  }
 }
 
@@ -45,6 +33,5 @@
 void owl_fmtext_append_attr(owl_fmtext *f, const char *text, char attr, short fgcolor, short bgcolor)
 {
-  char attrbuff[6];
-  int newlen, a = 0, fg = 0, bg = 0;
+  int a = 0, fg = 0, bg = 0;
   
   if (attr != OWL_FMTEXT_ATTR_NONE) a=1;
@@ -52,26 +39,18 @@
   if (bgcolor != OWL_COLOR_DEFAULT) bg=1;
 
-  /* Plane-16 characters in UTF-8 are 4 bytes long. */
-  newlen = strlen(f->textbuff) + strlen(text) + (8 * (a + fg + bg));
-  _owl_fmtext_realloc(f, newlen);
-
   /* Set attributes */
   if (a)
-    strncat(f->textbuff, attrbuff,
-	    g_unichar_to_utf8(OWL_FMTEXT_UC_ATTR | attr, attrbuff));
+    g_string_append_unichar(f->buff, OWL_FMTEXT_UC_ATTR | attr);
   if (fg)
-    strncat(f->textbuff, attrbuff,
-	    g_unichar_to_utf8(OWL_FMTEXT_UC_FGCOLOR | fgcolor, attrbuff));
+    g_string_append_unichar(f->buff, OWL_FMTEXT_UC_FGCOLOR | fgcolor);
   if (bg)
-    strncat(f->textbuff, attrbuff,
-	    g_unichar_to_utf8(OWL_FMTEXT_UC_BGCOLOR | bgcolor, attrbuff));
-  
-  strcat(f->textbuff, text);
+    g_string_append_unichar(f->buff, OWL_FMTEXT_UC_BGCOLOR | bgcolor);
+
+  g_string_append(f->buff, text);
 
   /* Reset attributes */
-  if (bg) strcat(f->textbuff, OWL_FMTEXT_UTF8_BGDEFAULT);
-  if (fg) strcat(f->textbuff, OWL_FMTEXT_UTF8_FGDEFAULT);
-  if (a)  strcat(f->textbuff, OWL_FMTEXT_UTF8_ATTR_NONE);
-  f->textlen=newlen;
+  if (bg) g_string_append(f->buff, OWL_FMTEXT_UTF8_BGDEFAULT);
+  if (fg) g_string_append(f->buff, OWL_FMTEXT_UTF8_FGDEFAULT);
+  if (a)  g_string_append(f->buff, OWL_FMTEXT_UTF8_ATTR_NONE);
 }
 
@@ -168,6 +147,6 @@
 {
   const char *p;
-  p = strchr(f->textbuff, OWL_FMTEXT_UC_STARTBYTE_UTF8);
-  while (p && p < f->textbuff + start) {
+  p = strchr(f->buff->str, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  while (p && p < f->buff->str + start) {
     _owl_fmtext_update_attributes(g_utf8_get_char(p), attr, fgcolor, bgcolor);
     p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
@@ -181,6 +160,5 @@
 static void _owl_fmtext_append_fmtext(owl_fmtext *f, const owl_fmtext *in, int start, int stop)
 {
-  char attrbuff[6];
-  int newlen, a = 0, fg = 0, bg = 0;
+  int a = 0, fg = 0, bg = 0;
   char attr = 0;
   short fgcolor = OWL_COLOR_DEFAULT;
@@ -192,28 +170,17 @@
   if (bgcolor != OWL_COLOR_DEFAULT) bg=1;
 
-  /* We will reset to defaults after appending the text. We may need
-     to set initial attributes. */
-  newlen=strlen(f->textbuff)+(stop-start) + (4 * (a + fg + bg)) + 12;
-  _owl_fmtext_realloc(f, newlen);
-
   if (a)
-    strncat(f->textbuff, attrbuff,
-	    g_unichar_to_utf8(OWL_FMTEXT_UC_ATTR | attr, attrbuff));
+    g_string_append_unichar(f->buff, OWL_FMTEXT_UC_ATTR | attr);
   if (fg)
-    strncat(f->textbuff, attrbuff,
-	    g_unichar_to_utf8(OWL_FMTEXT_UC_FGCOLOR | fgcolor, attrbuff));
+    g_string_append_unichar(f->buff, OWL_FMTEXT_UC_FGCOLOR | fgcolor);
   if (bg)
-    strncat(f->textbuff, attrbuff,
-	    g_unichar_to_utf8(OWL_FMTEXT_UC_BGCOLOR | bgcolor, attrbuff));
-
-  strncat(f->textbuff, in->textbuff+start, stop-start);
+    g_string_append_unichar(f->buff, OWL_FMTEXT_UC_BGCOLOR | bgcolor);
+
+  g_string_append_len(f->buff, in->buff->str+start, stop-start);
 
   /* Reset attributes */
-  strcat(f->textbuff, OWL_FMTEXT_UTF8_BGDEFAULT);
-  strcat(f->textbuff, OWL_FMTEXT_UTF8_FGDEFAULT);
-  strcat(f->textbuff, OWL_FMTEXT_UTF8_ATTR_NONE);
-
-  f->textbuff[newlen]='\0';
-  f->textlen=newlen;
+  g_string_append(f->buff, OWL_FMTEXT_UTF8_BGDEFAULT);
+  g_string_append(f->buff, OWL_FMTEXT_UTF8_FGDEFAULT);
+  g_string_append(f->buff, OWL_FMTEXT_UTF8_ATTR_NONE);
 }
 
@@ -221,5 +188,5 @@
 void owl_fmtext_append_fmtext(owl_fmtext *f, const owl_fmtext *in)
 {
-  _owl_fmtext_append_fmtext(f, in, 0, in->textlen);
+  _owl_fmtext_append_fmtext(f, in, 0, in->buff->len);
 
 }
@@ -239,5 +206,5 @@
 char *owl_fmtext_print_plain(const owl_fmtext *f)
 {
-  return owl_strip_format_chars(f->textbuff);
+  return owl_strip_format_chars(f->buff->str);
 }
 
@@ -281,5 +248,5 @@
   }
 
-  s = f->textbuff;
+  s = f->buff->str;
   /* Set default attributes. */
   attr = f->default_attrs;
@@ -375,6 +342,6 @@
   out->default_bgcolor = in->default_bgcolor;
 
-  for (ptr = in->textbuff;
-       ptr < in->textbuff + in->textlen;
+  for (ptr = in->buff->str;
+       ptr < in->buff->str + in->buff->len;
        ptr = g_utf8_next_char(ptr)) {
     gunichar c = g_utf8_get_char(ptr);
@@ -382,10 +349,10 @@
     if (c == '\t') {
       /* Copy up to this tab */
-      _owl_fmtext_append_fmtext(out, in, numcopied, ptr - in->textbuff);
+      _owl_fmtext_append_fmtext(out, in, numcopied, ptr - in->buff->str);
       /* and then copy spaces for the tab. */
       chwidth = OWL_TAB_WIDTH - (col % OWL_TAB_WIDTH);
       owl_fmtext_append_spaces(out, chwidth);
       col += chwidth;
-      numcopied = g_utf8_next_char(ptr) - in->textbuff;
+      numcopied = g_utf8_next_char(ptr) - in->buff->str;
     } else {
       /* Just update col. We'll append later. */
@@ -398,6 +365,6 @@
   }
   /* Append anything we've missed. */
-  if (numcopied < in->textlen)
-    _owl_fmtext_append_fmtext(out, in, numcopied, in->textlen);
+  if (numcopied < in->buff->len)
+    _owl_fmtext_append_fmtext(out, in, numcopied, in->buff->len);
 }
 
@@ -411,5 +378,5 @@
   
   /* find the starting line */
-  ptr1 = in->textbuff;
+  ptr1 = in->buff->str;
   for (i = 0; i < aline; i++) {
     ptr1 = strchr(ptr1, '\n');
@@ -429,9 +396,9 @@
 
   for (i = 0; i < lines; i++) {
-    offset = ptr1 - in->textbuff;
+    offset = ptr1 - in->buff->str;
     ptr2 = strchr(ptr1, '\n');
     if (!ptr2) {
       /* Copy to the end of the buffer. */
-      _owl_fmtext_append_fmtext(out, in, offset, in->textlen);
+      _owl_fmtext_append_fmtext(out, in, offset, in->buff->len);
       return(-1);
     }
@@ -454,6 +421,6 @@
   out->default_bgcolor = in->default_bgcolor;
 
-  last=in->textbuff+in->textlen-1;
-  ptr_s=in->textbuff;
+  last = in->buff->str + in->buff->len - 1;
+  ptr_s = in->buff->str;
   while (ptr_s <= last) {
     ptr_e=strchr(ptr_s, '\n');
@@ -497,9 +464,9 @@
       if (ptr_c == ptr_e) {
 	/* We made it to the newline. Append up to, and including it. */
-	_owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff + 1);
+	_owl_fmtext_append_fmtext(out, in, ptr_s - in->buff->str, ptr_c - in->buff->str + 1);
       }
       else if (chwidth > 1) {
         /* Last char is wide, truncate. */
-        _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+        _owl_fmtext_append_fmtext(out, in, ptr_s - in->buff->str, ptr_c - in->buff->str);
         owl_fmtext_append_normal(out, "\n");
       }
@@ -508,5 +475,5 @@
 	 * sure we get it all. */
         ptr_c = g_utf8_next_char(ptr_c);
-        _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+        _owl_fmtext_append_fmtext(out, in, ptr_s - in->buff->str, ptr_c - in->buff->str);
       }
     }
@@ -535,5 +502,5 @@
 
   /* _owl_fmtext_truncate_cols_internal cannot handle tabs. */
-  if (strchr(in->textbuff, '\t')) {
+  if (strchr(in->buff->str, '\t')) {
     owl_fmtext_init_null(&notabs);
     owl_fmtext_expand_tabs(in, &notabs, 0);
@@ -552,8 +519,8 @@
 
   lines=0;
-  lastbreak = f->textbuff;
-  for (i=0; i<f->textlen; i++) {
-    if (f->textbuff[i]=='\n') {
-      lastbreak = f->textbuff + i;
+  lastbreak = f->buff->str;
+  for (i = 0; i < f->buff->len; i++) {
+    if (f->buff->str[i]=='\n') {
+      lastbreak = f->buff->str + i;
       lines++;
     }
@@ -562,5 +529,5 @@
   /* Check if there's a trailing line; formatting characters don't count. */
   for (p = g_utf8_next_char(lastbreak);
-       p < f->textbuff + f->textlen;
+       p < f->buff->str + f->buff->len;
        p = g_utf8_next_char(p)) {
     if (!owl_fmtext_is_format_char(g_utf8_get_char(p))) {
@@ -581,8 +548,8 @@
 {
   int i, lineno = 0;
-  if (offset >= f->textlen)
-    offset = f->textlen - 1;
+  if (offset >= f->buff->len)
+    offset = f->buff->len - 1;
   for (i = 0; i < offset; i++) {
-    if (f->textbuff[i] == '\n')
+    if (f->buff->str[i] == '\n')
       lineno++;
   }
@@ -596,11 +563,11 @@
   int start, end;
   char *newline;
-  for (start = 0; lineno > 0 && start < f->textlen; start++) {
-    if (f->textbuff[start] == '\n')
+  for (start = 0; lineno > 0 && start < f->buff->len; start++) {
+    if (f->buff->str[start] == '\n')
       lineno--;
   }
-  newline = strchr(f->textbuff + start, '\n');
+  newline = strchr(f->buff->str + start, '\n');
   /* Include the newline, if it is there. */
-  end = newline ? newline - f->textbuff + 1 : f->textlen;
+  end = newline ? newline - f->buff->str + 1 : f->buff->len;
   if (o_start) *o_start = start;
   if (o_end) *o_end = end;
@@ -609,10 +576,10 @@
 const char *owl_fmtext_get_text(const owl_fmtext *f)
 {
-  return(f->textbuff);
+  return f->buff->str;
 }
 
 int owl_fmtext_num_bytes(const owl_fmtext *f)
 {
-  return(f->textlen);
+  return f->buff->len;
 }
 
@@ -622,8 +589,8 @@
 void owl_fmtext_set_char(owl_fmtext *f, int index, char ch)
 {
-  if ((index < 0) || (index > f->textlen-1)) return;
+  if ((index < 0) || (index > f->buff->len - 1)) return;
   /* NOT ASCII*/
-  if (f->textbuff[index] & 0x80 || ch & 0x80) return; 
-  f->textbuff[index]=ch;
+  if (f->buff->str[index] & 0x80 || ch & 0x80) return;
+  f->buff->str[index] = ch;
 }
 
@@ -631,15 +598,5 @@
 void owl_fmtext_copy(owl_fmtext *dst, const owl_fmtext *src)
 {
-  int mallocsize;
-
-  if (src->textlen==0) {
-    mallocsize=5;
-  } else {
-    mallocsize=src->textlen+2;
-  }
-  dst->textlen=src->textlen;
-  dst->bufflen=mallocsize;
-  dst->textbuff=owl_malloc(mallocsize);
-  memcpy(dst->textbuff, src->textbuff, src->textlen+1);
+  dst->buff = g_string_new(src->buff->str);
   dst->default_attrs = src->default_attrs;
   dst->default_fgcolor = src->default_fgcolor;
@@ -654,6 +611,6 @@
 {
   int offset;
-  if (start > f->textlen ||
-      owl_regex_compare(re, f->textbuff + start, &offset, NULL) != 0)
+  if (start > f->buff->len ||
+      owl_regex_compare(re, f->buff->str + start, &offset, NULL) != 0)
     return -1;
   return offset + start;
@@ -897,5 +854,6 @@
 void owl_fmtext_cleanup(owl_fmtext *f)
 {
-  if (f->textbuff) owl_free(f->textbuff);
+  if (f->buff) g_string_free(f->buff, true);
+  f->buff = NULL;
 }
 
Index: owl.h
===================================================================
--- owl.h	(revision b03c7147a8486f42fba33d386e40bd48c26950c5)
+++ owl.h	(revision 7e111f4408b99cd75667d6a99ec6e061fdfbd546)
@@ -279,7 +279,5 @@
 
 typedef struct _owl_fmtext {
-  int textlen;
-  int bufflen;
-  char *textbuff;
+  GString *buff;
   char default_attrs;
   short default_fgcolor;
