Index: fmtext.c
===================================================================
--- fmtext.c	(revision dd24b6a9702baf822973cf963adfd8b55978b775)
+++ fmtext.c	(revision 9866c3aac7b8bd2779303753d2e1352f405b2baf)
@@ -8,14 +8,11 @@
 void owl_fmtext_init_null(owl_fmtext *f)
 {
-  f->textlen=0;
-  f->bufflen=5;
-  f->textbuff=owl_malloc(5);
-  f->fmbuff=owl_malloc(5);
-  f->fgcolorbuff=owl_malloc(5 * sizeof(short));
-  f->bgcolorbuff=owl_malloc(5 * sizeof(short));
-  f->textbuff[0]=0;
-  f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
-  f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
-  f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
+  f->textlen = 0;
+  f->bufflen = 5;
+  f->textbuff = owl_malloc(5);
+  f->textbuff[0] = 0;
+  f->default_attrs = OWL_FMTEXT_ATTR_NONE;
+  f->default_fgcolor = OWL_COLOR_DEFAULT;
+  f->default_fgcolor = OWL_COLOR_DEFAULT;
 }
 
@@ -24,50 +21,9 @@
 void owl_fmtext_clear(owl_fmtext *f)
 {
-    f->textlen = 0;
-    f->textbuff[0] = 0;
-    f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
-    f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
-    f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
-}
-
-/* Internal function.  Set the attribute 'attr' from index 'first' to
- * index 'last'
- */
-void _owl_fmtext_set_attr(owl_fmtext *f, int attr, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->fmbuff[i]=(unsigned char) attr;
-  }
-}
-
-/* Internal function.  Add the attribute 'attr' to the existing
- * attributes from index 'first' to index 'last'
- */
-void _owl_fmtext_add_attr(owl_fmtext *f, int attr, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->fmbuff[i]|=(unsigned char) attr;
-  }
-}
-
-/* Internal function.  Set the color to be 'color' from index 'first'
- * to index 'last
- */
-void _owl_fmtext_set_fgcolor(owl_fmtext *f, int color, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->fgcolorbuff[i]=(short)color;
-  }
-}
-
-void _owl_fmtext_set_bgcolor(owl_fmtext *f, int color, int first, int last)
-{
-  int i;
-  for (i=first; i<=last; i++) {
-    f->bgcolorbuff[i]=(short)color;
-  }
+  f->textlen = 0;
+  f->textbuff[0] = 0;
+  f->default_attrs = OWL_FMTEXT_ATTR_NONE;
+  f->default_fgcolor = OWL_COLOR_DEFAULT;
+  f->default_fgcolor = OWL_COLOR_DEFAULT;
 }
 
@@ -75,25 +31,54 @@
 {
     if(newlen + 1 > f->bufflen) {
-      f->textbuff=owl_realloc(f->textbuff, newlen+1);
-      f->fmbuff=owl_realloc(f->fmbuff, newlen+1);
-      f->fgcolorbuff=owl_realloc(f->fgcolorbuff, (newlen+1) * sizeof(short));
-      f->bgcolorbuff=owl_realloc(f->bgcolorbuff, (newlen+1) * sizeof(short));
+      f->textbuff = owl_realloc(f->textbuff, newlen + 1);
       f->bufflen = newlen+1;
   }
 }
 
+int _owl_fmtext_is_format_char(gunichar c) /*noproto*/
+{
+  if ((c & ~OWL_FMTEXT_UC_ATTR_MASK) == OWL_FMTEXT_UC_ATTR) return 1;
+  if ((c & ~(OWL_FMTEXT_UC_ALLCOLOR_MASK)) == OWL_FMTEXT_UC_COLOR_BASE) return 1;
+  return 0;
+}
 /* append text to the end of 'f' with attribute 'attr' and color
  * 'color'
  */
-void owl_fmtext_append_attr(owl_fmtext *f, char *text, int attr, int fgcolor, int bgcolor)
-{
-  int newlen;
-  newlen=strlen(f->textbuff)+strlen(text);
+void owl_fmtext_append_attr(owl_fmtext *f, char *text, char attr, short fgcolor, short bgcolor)
+{
+  char attrbuff[6];
+  int newlen, a = 0, fg = 0, bg = 0;
+  
+  if (attr != OWL_FMTEXT_ATTR_NONE) a=1;
+  if (fgcolor != OWL_COLOR_DEFAULT) fg=1;
+  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) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_ATTR | attr, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (fg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_FGCOLOR | fgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (bg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_BGCOLOR | bgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
   
   strcat(f->textbuff, text);
-  _owl_fmtext_set_attr(f, attr, f->textlen, newlen);
-  _owl_fmtext_set_fgcolor(f, fgcolor, f->textlen, newlen);
-  _owl_fmtext_set_bgcolor(f, bgcolor, f->textlen, newlen);
+
+  /* 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;
 }
@@ -129,58 +114,101 @@
 }
 
-/* Add the attribute 'attr' to all text in 'f' */
-void owl_fmtext_addattr(owl_fmtext *f, int attr)
+/* Add the attribute 'attr' to the default atts for the text in 'f' */
+void owl_fmtext_addattr(owl_fmtext *f, char attr)
 {
   /* add the attribute to all text */
-  int i, j;
-
-  j=f->textlen;
-  for (i=0; i<j; i++) {
-    f->fmbuff[i] |= attr;
-  }
-}
-
-/* Anywhere the color is NOT ALREDY SET, set the color to 'color'.
- * Other colors are left unchanged
+  f->default_attrs |= attr;
+}
+
+/* Set the default foreground color for this fmtext to 'color'.
+ * Only affects text that is colored default.
  */
 void owl_fmtext_colorize(owl_fmtext *f, int color)
 {
-  /* everywhere the fgcolor is OWL_COLOR_DEFAULT, change it to be 'color' */
-  int i, j;
-
-  j=f->textlen;
-  for(i=0; i<j; i++) {
-    if (f->fgcolorbuff[i]==OWL_COLOR_DEFAULT) f->fgcolorbuff[i] = (short)color;
-  }
-}
-
+  f->default_fgcolor = color;
+}
+
+/* Set the default foreground color for this fmtext to 'color'.
+ * Only affects text that is colored default.
+ */
 void owl_fmtext_colorizebg(owl_fmtext *f, int color)
 {
-  /* everywhere the bgcolor is OWL_COLOR_DEFAULT, change it to be 'color' */
-  int i, j;
-
-  j=f->textlen;
-  for(i=0; i<j; i++) {
-    if (f->bgcolorbuff[i]==OWL_COLOR_DEFAULT) f->bgcolorbuff[i] = (short)color;
-  }
-}
+  f->default_bgcolor = color;
+}
+
+/* Internal function. Parse attrbute character. */
+void _owl_fmtext_update_attributes(gunichar c, char *attr, short *fgcolor, short *bgcolor) /*noproto*/
+{
+  if ((c & OWL_FMTEXT_UC_ATTR) == OWL_FMTEXT_UC_ATTR) {
+    *attr = c & OWL_FMTEXT_UC_ATTR_MASK;
+  }
+  else if ((c & OWL_FMTEXT_UC_FGCOLOR) == OWL_FMTEXT_UC_FGCOLOR) {
+    *fgcolor = (c == OWL_FMTEXT_UC_FGDEFAULT
+		? OWL_COLOR_DEFAULT
+		: c & OWL_FMTEXT_UC_COLOR_MASK);
+  }
+  else if ((c & OWL_FMTEXT_UC_BGCOLOR) == OWL_FMTEXT_UC_BGCOLOR) {
+    *bgcolor = (c == OWL_FMTEXT_UC_BGDEFAULT
+		? OWL_COLOR_DEFAULT
+		: c & OWL_FMTEXT_UC_COLOR_MASK);
+  }
+}
+
+/* Internal function. Scan for attribute characters. */
+void _owl_fmtext_scan_attributes(owl_fmtext *f, int start, char *attr, short *fgcolor, short *bgcolor) /*noproto*/
+{
+  char *p;
+  p = strchr(f->textbuff, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  while (p && p < f->textbuff + start) {
+    _owl_fmtext_update_attributes(g_utf8_get_char(p), attr, fgcolor, bgcolor);
+    p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  }
+}  
 
 /* Internal function.  Append text from 'in' between index 'start' and
  * 'stop' to the end of 'f'
  */
-void _owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop)
-{
-  int newlen, i;
-
-  newlen=strlen(f->textbuff)+(stop-start+1);
+void _owl_fmtext_append_fmtext(owl_fmtext *f, owl_fmtext *in, int start, int stop) /*noproto*/
+{
+  char attrbuff[6];
+  int newlen, a = 0, fg = 0, bg = 0;
+  char attr = 0;
+  short fgcolor = OWL_COLOR_DEFAULT;
+  short bgcolor = OWL_COLOR_DEFAULT;
+
+  _owl_fmtext_scan_attributes(in, start, &attr, &fgcolor, &bgcolor);
+  if (attr != OWL_FMTEXT_ATTR_NONE) a=1;
+  if (fgcolor != OWL_COLOR_DEFAULT) fg=1;
+  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+1) + (4 * (a + fg + bg)) + 12;
   _owl_fmtext_realloc(f, newlen);
 
+  if (a) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_ATTR | attr, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (fg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_FGCOLOR | fgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+  if (bg) {
+    memset(attrbuff,0,6);
+    g_unichar_to_utf8(OWL_FMTEXT_UC_BGCOLOR | bgcolor, attrbuff);
+    strcat(f->textbuff, attrbuff);      
+  }
+
   strncat(f->textbuff, in->textbuff+start, stop-start+1);
+
+  /* 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';
-  for (i=start; i<=stop; i++) {
-    f->fmbuff[f->textlen+(i-start)]=in->fmbuff[i];
-    f->fgcolorbuff[f->textlen+(i-start)]=in->fgcolorbuff[i];
-    f->bgcolorbuff[f->textlen+(i-start)]=in->bgcolorbuff[i];
-  }
   f->textlen=newlen;
 }
@@ -207,15 +235,49 @@
 char *owl_fmtext_print_plain(owl_fmtext *f)
 {
-  return(owl_strdup(f->textbuff));
-}
-
+  char *r, *s, *p;
+  r = owl_malloc(f->bufflen);
+  r[0] = '\0';
+  s = f->textbuff;
+  /* Find next possible format character. */
+  p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  while(p) {
+    /* If it's a format character, copy up to it, and skip all
+       immediately following format characters. */
+    if (_owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+      strncat(r, s, p-s);
+      p = g_utf8_next_char(p);
+      while (p && _owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+	p = g_utf8_next_char(p);
+      }
+      s = p;
+      p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    }
+    else {
+      p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    }
+  }
+  if (s) strcat(r,s);
+  return(r);
+}
+
+void _owl_fmtext_wattrset(WINDOW *w, int attrs) /*noproto*/
+{
+  wattrset(w, A_NORMAL);
+  if (attrs & OWL_FMTEXT_ATTR_BOLD) wattron(w, A_BOLD);
+  if (attrs & OWL_FMTEXT_ATTR_REVERSE) wattron(w, A_REVERSE);
+  if (attrs & OWL_FMTEXT_ATTR_UNDERLINE) wattron(w, A_UNDERLINE);
+}
 /* add the formatted text to the curses window 'w'.  The window 'w'
  * must already be initiatlized with curses
  */
-void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w)
-{
-  char *tmpbuff;
-  int position, trans1, trans2, trans3, len, lastsame;
-
+void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w, int do_search)
+{
+  /* char *tmpbuff; */
+  /* int position, trans1, trans2, trans3, len, lastsame; */
+  char *s, *p;
+  char attr;
+  short fg, bg;
+  int search_results, search_len;
+  
   if (w==NULL) {
     owl_function_debugmsg("Hit a null window in owl_fmtext_curs_waddstr.");
@@ -223,51 +285,90 @@
   }
 
-  tmpbuff=owl_malloc(f->textlen+10);
-
-  position=0;
-  len=f->textlen;
-  while (position<=len) {
-    /* find the last char with the current format and color */
-    trans1=owl_util_find_trans(f->fmbuff+position, len-position);
-    trans2=owl_util_find_trans_short(f->fgcolorbuff+position, len-position);
-    trans3=owl_util_find_trans_short(f->bgcolorbuff+position, len-position);
-
-    lastsame = (trans1 < trans2) ? trans1 : trans2;
-    lastsame = (lastsame < trans3) ? lastsame : trans3;
-    lastsame += position;
-
-    /* set the format */
-    wattrset(w, A_NORMAL);
-    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_BOLD) {
-      wattron(w, A_BOLD);
-    }
-    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_REVERSE) {
-      wattron(w, A_REVERSE);
-    }
-    if (f->fmbuff[position] & OWL_FMTEXT_ATTR_UNDERLINE) {
-      wattron(w, A_UNDERLINE);
-    }
-
-    /* set the color */
-    /* warning, this is sort of a hack */
-    if (owl_global_get_hascolors(&g)) {
-      short fg, bg, pair;
-      fg = f->fgcolorbuff[position];
-      bg = f->bgcolorbuff[position];
-
-      pair = owl_fmtext_get_colorpair(fg, bg);
-      if (pair != -1) {
-        wcolor_set(w,pair,NULL);
-      }
-    }
-
-    /* add the text */
-    strncpy(tmpbuff, f->textbuff + position, lastsame-position+1);
-    tmpbuff[lastsame-position+1]='\0';
-    waddstr(w, tmpbuff);
-
-    position=lastsame+1;
-  }
-  owl_free(tmpbuff);
+  search_results = (do_search
+		    ? owl_fmtext_search(f, owl_global_get_search_string(&g))
+		    : NULL);
+  if (search_results) search_len = strlen(owl_global_get_search_string(&g));
+  s = f->textbuff;
+  /* Set default attributes. */
+  attr = f->default_attrs;
+  fg = f->default_fgcolor;
+  bg = f->default_bgcolor;
+  _owl_fmtext_wattrset(w, attr);
+  if (owl_global_get_hascolors(&g)) {
+    short pair;
+    pair = owl_fmtext_get_colorpair(fg, bg);
+    if (pair != -1) {
+      wcolor_set(w,pair,NULL);
+    }
+  }
+
+  /* Find next possible format character. */
+  p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+  while(p) {
+    if (_owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+      /* Deal with all text from last insert to here. */
+      char tmp;
+   
+      tmp = p[0];
+      p[0] = '\0';
+      if (search_results) {
+	/* Search is active, so highlight search results. */
+	char tmp2, *ss;
+	ss = stristr(s, owl_global_get_search_string(&g));
+	while (ss) {
+	  /* Found search string, highlight it. */
+
+	  tmp2 = ss[0];
+	  ss[0] = '\0';
+	  waddstr(w, s);
+	  ss[0] = tmp2;
+
+	  _owl_fmtext_wattrset(w,attr ^ A_REVERSE);
+
+	  tmp2 = ss[search_len];
+	  ss[search_len] = '\0';
+	  waddstr(w, ss);
+	  ss[search_len] = tmp2;
+
+	  _owl_fmtext_wattrset(w,attr);
+
+	  s = ss + search_len;
+	  ss = stristr(s, owl_global_get_search_string(&g));
+	}
+      }
+      /* Deal with remaining part of string. */
+      waddstr(w, s);
+      p[0] = tmp;
+
+      /* Deal with new attributes. Initialize to defaults, then
+	 process all consecutive formatting characters. */
+      attr = f->default_attrs;
+      fg = f->default_fgcolor;
+      bg = f->default_bgcolor;
+      while (p && _owl_fmtext_is_format_char(g_utf8_get_char(p))) {
+	_owl_fmtext_update_attributes(g_utf8_get_char(p), &attr, &fg, &bg);
+	p = g_utf8_next_char(p);
+      }
+      _owl_fmtext_wattrset(w, attr | f->default_attrs);
+      if (owl_global_get_hascolors(&g)) {
+	if (fg == OWL_COLOR_DEFAULT) fg = f->default_fgcolor;
+	if (bg == OWL_COLOR_DEFAULT) bg = f->default_bgcolor;
+	short pair;
+	pair = owl_fmtext_get_colorpair(fg, bg);
+	if (pair != -1) {
+	  wcolor_set(w,pair,NULL);
+	}
+      }
+      /* Advance to next non-formatting character. */
+      s = p;
+      p = strchr(s, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    }
+    else {
+      p = strchr(p+1, OWL_FMTEXT_UC_STARTBYTE_UTF8);
+    }
+  }
+  if (s) {
+    waddstr(w, s);
+  }
 }
 
@@ -282,26 +383,25 @@
   
   /* find the starting line */
-  ptr1=in->textbuff;
-  if (aline!=0) {
-    for (i=0; i<aline; i++) {
-      ptr1=strchr(ptr1, '\n');
-      if (!ptr1) return(-1);
-      ptr1++;
-    }
-  }
+  ptr1 = in->textbuff;
+  for (i = 0; i < aline; i++) {
+    ptr1 = strchr(ptr1, '\n');
+    if (!ptr1) return(-1);
+    ptr1++;
+  }
+  
   /* ptr1 now holds the starting point */
 
   /* copy in the next 'lines' lines */
-  if (lines<1) return(-1);
-
-  for (i=0; i<lines; i++) {
-    offset=ptr1-in->textbuff;
-    ptr2=strchr(ptr1, '\n');
+  if (lines < 1) return(-1);
+
+  for (i = 0; i < lines; i++) {
+    offset = ptr1 - in->textbuff;
+    ptr2 = strchr(ptr1, '\n');
     if (!ptr2) {
-      _owl_fmtext_append_fmtext(out, in, offset, (in->textlen)-1);
+      _owl_fmtext_append_fmtext(out, in, offset, (in->textlen) - 1);
       return(-1);
     }
-    _owl_fmtext_append_fmtext(out, in, offset, (ptr2-ptr1)+offset);
-    ptr1=ptr2+1;
+    _owl_fmtext_append_fmtext(out, in, offset, (ptr2 - ptr1) + offset);
+    ptr1 = ptr2 + 1;
   }
   return(0);
@@ -316,9 +416,9 @@
 {
   char *ptr_s, *ptr_e, *ptr_c, *last;
-  int col, cnt, padding;
+  int col, st, padding, chwidth;
 
   last=in->textbuff+in->textlen-1;
   ptr_s=in->textbuff;
-  while (ptr_s<=last) {
+  while (ptr_s <= last) {
     ptr_e=strchr(ptr_s, '\n');
     if (!ptr_e) {
@@ -327,61 +427,50 @@
     }
     
-    if (ptr_e==ptr_s) {
+    if (ptr_e == ptr_s) {
       owl_fmtext_append_normal(out, "\n");
-      ptr_s++;
+      ++ptr_s;
       continue;
     }
 
     col = 0;
-    cnt = 0;
+    st = 0;
     padding = 0;
     ptr_c = ptr_s;
-    while(col < bcol && ptr_c < ptr_e) {
+    while(col <= bcol && ptr_c < ptr_e) {
       gunichar c = g_utf8_get_char(ptr_c);
-      if (col + wcwidth(c) > bcol) break;
-      col += wcwidth(c);
+      if (!_owl_fmtext_is_format_char(c)) {
+	chwidth = wcwidth(c);
+      
+	if (col + chwidth > bcol)
+	  break;
+	if (col >= acol) {
+	  if (st == 0) {
+	    ptr_s = ptr_c;
+	    padding = col - acol;
+	    ++st;
+	  }
+	}
+	col += chwidth;
+	chwidth = 0;
+      }
       ptr_c = g_utf8_next_char(ptr_c);
-      if (col >= acol) {
-	if (cnt == 0) {
-	  ptr_s = ptr_c;
-	  padding = col - acol;
-	}
-	++cnt;
-      }
-    }
-    if (cnt) {
-      while(padding-- > 0) {
-	owl_fmtext_append_normal(out, " ");
-      }
-      _owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+    }
+    if (st) {
+      /* lead padding */
+      owl_fmtext_append_spaces(out, padding);
+      if (ptr_c[0] & 0x80) {
+	if (col + chwidth == bcol)
+	  ptr_c = g_utf8_next_char(ptr_c);
+	_owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - 1 - in->textbuff);	
+	owl_fmtext_append_normal(out, "\n");
+      }
+      else {
+	_owl_fmtext_append_fmtext(out, in, ptr_s - in->textbuff, ptr_c - in->textbuff);
+      }
     }
     else {
       owl_fmtext_append_normal(out, "\n");
     }
-    ptr_s=ptr_e+1;
-      
-#if 0
-    /* we need to check that we won't run over here */
-    len=bcol-acol;
-    if (len > (ptr_e-(ptr_s+acol))) {
-      /* the whole line fits with room to spare, don't take a full 'len' */
-      len=ptr_e-(ptr_s+acol);
-    }
-    if (len>last-ptr_s) {
-      /* the whole rest of the text fits with room to spare, adjust for it */
-      len-=(last-ptr_s);
-    }
-    if (len<=0) {
-      /* saftey check */
-      owl_fmtext_append_normal(out, "\n");
-      ptr_s=ptr_e+1;
-      continue;
-    }
-
-    offset = ptr_s - in->textbuff;
-    _owl_fmtext_append_fmtext(out, in, offset+acol, offset+acol+len);
-
-    ptr_s=ptr_e+1;
-#endif
+    ptr_s = g_utf8_next_char(ptr_e);
   }
 }
@@ -411,8 +500,11 @@
 
 /* set the charater at 'index' to be 'char'.  If index is out of
- * bounds don't do anything */
-void owl_fmtext_set_char(owl_fmtext *f, int index, int ch)
+ * bounds don't do anything. If c or char at index is not ASCII, don't
+ * do anything because it's not UTF-8 safe. */
+void owl_fmtext_set_char(owl_fmtext *f, int index, char ch)
 {
   if ((index < 0) || (index > f->textlen-1)) return;
+  /* NOT ASCII*/
+  if (f->textbuff[index] & 0x80 || ch & 0x80) return; 
   f->textbuff[index]=ch;
 }
@@ -430,37 +522,8 @@
   dst->textlen=src->textlen;
   dst->textbuff=owl_malloc(mallocsize);
-  dst->fmbuff=owl_malloc(mallocsize);
-  dst->fgcolorbuff=owl_malloc(mallocsize * sizeof(short));
-  dst->bgcolorbuff=owl_malloc(mallocsize * sizeof(short));
   memcpy(dst->textbuff, src->textbuff, src->textlen+1);
-  memcpy(dst->fmbuff, src->fmbuff, src->textlen);
-  memcpy(dst->fgcolorbuff, src->fgcolorbuff, src->textlen * sizeof(short));
-  memcpy(dst->bgcolorbuff, src->bgcolorbuff, src->textlen * sizeof(short));
-}
-
-/* highlight all instances of "string".  Return the number of
- * instances found.  This is a case insensitive search.
- */
-int owl_fmtext_search_and_highlight(owl_fmtext *f, char *string)
-{
-
-  int found, len;
-  char *ptr1, *ptr2;
-
-  len=strlen(string);
-  found=0;
-  ptr1=f->textbuff;
-  while (ptr1-f->textbuff <= f->textlen) {
-    ptr2=stristr(ptr1, string);
-    if (!ptr2) return(found);
-
-    found++;
-    _owl_fmtext_add_attr(f, OWL_FMTEXT_ATTR_REVERSE,
-                         ptr2 - f->textbuff,
-                         ptr2 - f->textbuff + len - 1);
-
-    ptr1=ptr2+len;
-  }
-  return(found);
+  dst->default_attrs = src->default_attrs;
+  dst->default_fgcolor = src->default_fgcolor;
+  dst->default_bgcolor = src->default_bgcolor;
 }
 
@@ -470,5 +533,4 @@
 int owl_fmtext_search(owl_fmtext *f, char *string)
 {
-
   if (stristr(f->textbuff, string)) return(1);
   return(0);
@@ -711,7 +773,4 @@
 {
   if (f->textbuff) owl_free(f->textbuff);
-  if (f->fmbuff) owl_free(f->fmbuff);
-  if (f->fgcolorbuff) owl_free(f->fgcolorbuff);
-  if (f->bgcolorbuff) owl_free(f->bgcolorbuff);
 }
 
Index: message.c
===================================================================
--- message.c	(revision 34509d514dfa9ee441febffc6d61e108962d1507)
+++ message.c	(revision 9866c3aac7b8bd2779303753d2e1352f405b2baf)
@@ -537,16 +537,8 @@
   owl_fmtext_truncate_lines(&(m->fmtext->fmtext), aline, bline-aline+1, &a);
   owl_fmtext_truncate_cols(&a, acol, bcol, &b);
-  if (fgcolor!=OWL_COLOR_DEFAULT) {
-    owl_fmtext_colorize(&b, fgcolor);
-  }
-  if (bgcolor!=OWL_COLOR_DEFAULT) {
-    owl_fmtext_colorizebg(&b, bgcolor);
-  }
-
-  if (owl_global_is_search_active(&g)) {
-    owl_fmtext_search_and_highlight(&b, owl_global_get_search_string(&g));
-  }
-      
-  owl_fmtext_curs_waddstr(&b, win);
+  owl_fmtext_colorize(&b, fgcolor);
+  owl_fmtext_colorizebg(&b, bgcolor);
+
+  owl_fmtext_curs_waddstr(&b, win, owl_global_is_search_active(&g));
 
   owl_fmtext_free(&a);
Index: owl.h
===================================================================
--- owl.h	(revision dd24b6a9702baf822973cf963adfd8b55978b775)
+++ owl.h	(revision 9866c3aac7b8bd2779303753d2e1352f405b2baf)
@@ -101,4 +101,24 @@
 #define OWL_FMTEXT_ATTR_UNDERLINE 4
 
+#define OWL_FMTEXT_UC_BASE 0x100000 /* Unicode Plane 16 - Supplementary Private Use Area-B*/
+#define OWL_FMTEXT_UC_ATTR ( OWL_FMTEXT_UC_BASE | 0x800 )
+#define OWL_FMTEXT_UC_ATTR_MASK 0x7
+#define OWL_FMTEXT_UC_COLOR_BASE ( OWL_FMTEXT_UC_BASE | 0x400 )
+#define OWL_FMTEXT_UC_FGCOLOR OWL_FMTEXT_UC_COLOR_BASE
+#define OWL_FMTEXT_UC_BGCOLOR ( OWL_FMTEXT_UC_COLOR_BASE | 0x200 )
+#define OWL_FMTEXT_UC_DEFAULT_COLOR 0x100
+#define OWL_FMTEXT_UC_FGDEFAULT ( OWL_FMTEXT_UC_FGCOLOR | OWL_FMTEXT_UC_DEFAULT_COLOR )
+#define OWL_FMTEXT_UC_BGDEFAULT ( OWL_FMTEXT_UC_BGCOLOR | OWL_FMTEXT_UC_DEFAULT_COLOR )
+#define OWL_FMTEXT_UC_COLOR_MASK 0xFF
+#define OWL_FMTEXT_UC_ALLCOLOR_MASK ( OWL_FMTEXT_UC_COLOR_MASK | OWL_FMTEXT_UC_DEFAULT_COLOR | 0x200)
+#define OWL_FMTEXT_UC_STARTBYTE_UTF8 '\xf4'
+
+#define OWL_FMTEXT_UTF8_ATTR_NONE "\xf4\x80\xa0\x80"
+#define OWL_FMTEXT_UTF8_FGDEFAULT "\xf4\x80\x94\x80"
+#define OWL_FMTEXT_UTF8_BGDEFAULT "\xf4\x80\x96\x80"
+
+
+
+
 #define OWL_COLOR_BLACK     0
 #define OWL_COLOR_RED       1
@@ -256,7 +276,7 @@
   int bufflen;
   char *textbuff;
-  char *fmbuff;
-  short *fgcolorbuff;
-  short *bgcolorbuff;
+  char default_attrs;
+  short default_fgcolor;
+  short default_bgcolor;
 } owl_fmtext;
 
Index: viewwin.c
===================================================================
--- viewwin.c	(revision 8721756cdb2a0ef8c380c35ec3bf73d2c0e1508a)
+++ viewwin.c	(revision 9866c3aac7b8bd2779303753d2e1352f405b2baf)
@@ -73,5 +73,5 @@
   owl_fmtext_truncate_cols(&fm1, v->rightshift, v->wincols-1+v->rightshift, &fm2);
 
-  owl_fmtext_curs_waddstr(&fm2, v->curswin);
+  owl_fmtext_curs_waddstr(&fm2, v->curswin, 0);
 
   /* print the message at the bottom */
