text: /* ------------- editor.c ------------ */
  #include "dflat.h"
  
  #define pTab ('\t' + 0x80)
  #define sTab ('\f' + 0x80)
  
  /* ---------- SETTEXT Message ------------ */
  static int SetTextMsg(WINDOW wnd, char *Buf)
  {
     	unsigned char *tp, *ep, *ttp;
     	int x = 0;
     	int sz = 0;
  	int rtn;
  
  	tp = Buf;
      /* --- compute the buffer size based on tabs in the text --- */
      while (*tp)    {
          if (*tp == '\t')    {
              /* --- tab, adjust the buffer length --- */
              int sps = cfg.Tabs - (x % cfg.Tabs);
              sz += sps;
              x += sps;
          }
          else    {
              /* --- not a tab, count the character --- */
              sz++;
              x++;
          }
          if (*tp == '\n')
              x = 0;    /* newline, reset x --- */
          tp++;
      }
      /* --- allocate a buffer --- */
      ep = DFcalloc(1, sz+1);
      /* --- detab the input file --- */
      tp = Buf;
      ttp = ep;
      x = 0;
      while (*tp)    {
          /* --- put the character (\t, too) into the buffer --- */
          x++;
          /* --- expand tab into subst tab (\f + 0x80)
  						and expansions (\t + 0x80) --- */
          if (*tp == '\t')	{
  	        *ttp++ = sTab;	/* --- substitute tab character --- */
              while ((x % cfg.Tabs) != 0)
                  *ttp++ = pTab, x++;
  		}
  		else	{
  	        *ttp++ = *tp;
          	if (*tp == '\n')
              	x = 0;
  		}
          tp++;
      }
      *ttp = '\0';
  	rtn = BaseWndProc(EDITOR, wnd, SETTEXT, (PARAM) ep, 0);
      free(ep);
  	return rtn;
  }
  void CollapseTabs(WINDOW wnd)
  {
  	unsigned char *cp = wnd->text, *cp2;
  	while (*cp)	{
  		if (*cp == sTab)	{
  			*cp = '\t';
  			cp2 = cp;
  			while (*++cp2 == pTab)
  				;
  			memmove(cp+1, cp2, strlen(cp2)+1);
  		}
  		cp++;
  	}
  }
  
  void ExpandTabs(WINDOW wnd)
  {
  	int Holdwtop = wnd->wtop;
  	int Holdwleft = wnd->wleft;
  	int HoldRow = wnd->CurrLine;
  	int HoldCol = wnd->CurrCol;
  	int HoldwRow = wnd->WndRow;
  	SendMessage(wnd, SETTEXT, (PARAM) wnd->text, 0);
  	wnd->wtop = Holdwtop;
  	wnd->wleft = Holdwleft;
  	wnd->CurrLine = HoldRow;
  	wnd->CurrCol = HoldCol;
  	wnd->WndRow = HoldwRow;
  	SendMessage(wnd, PAINT, 0, 0);
  	SendMessage(wnd, KEYBOARD_CURSOR, 0, wnd->WndRow);
  }
  
  /* --- When inserting or deleting, adjust next following tab, same line --- */
  static void AdjustTab(WINDOW wnd)
  {
      /* ---- test if there is a tab beyond this character ---- */
  	int col = wnd->CurrCol;
      while (*CurrChar && *CurrChar != '\n')    {
  		if (*CurrChar == sTab)	{
  			int exp = (cfg.Tabs - 1) - (wnd->CurrCol % cfg.Tabs);
  	        wnd->CurrCol++;
  			while (*CurrChar == pTab)
  				BaseWndProc(EDITOR, wnd, KEYBOARD, DEL, 0);
  			while (exp--)
  				BaseWndProc(EDITOR, wnd, KEYBOARD, pTab, 0);
  			break;
  		}
          wnd->CurrCol++;
      }
  	wnd->CurrCol = col;
  }
  
  static void TurnOffDisplay(WINDOW wnd)
  {
  	SendMessage(NULL, HIDE_CURSOR, 0, 0);
      ClearVisible(wnd);
  }
  
  static void TurnOnDisplay(WINDOW wnd)
  {
      SetVisible(wnd);
  	SendMessage(NULL, SHOW_CURSOR, 0, 0);
  }
  
  static void RepaintLine(WINDOW wnd)
  {
  	SendMessage(wnd, KEYBOARD_CURSOR, WndCol, wnd->WndRow);
  	WriteTextLine(wnd, NULL, wnd->CurrLine, FALSE);
  }
  
  /* --------- KEYBOARD Message ---------- */
  static int KeyboardMsg(WINDOW wnd, PARAM p1, PARAM p2)
  {
      int c = (int) p1;
  	BOOL delnl;
  	PARAM pn = p1;
      if (WindowMoving || WindowSizing || ((int)p2 & ALTKEY))
          return FALSE;
      switch (c)    {
  		case PGUP:
  		case PGDN:
  		case UP:
  		case DN:
  			pn = (PARAM) BS;
  		case FWD:
  		case BS:
  			BaseWndProc(EDITOR, wnd, KEYBOARD, p1, p2);
  		    TurnOffDisplay(wnd);
  			while (*CurrChar == pTab)
  				BaseWndProc(EDITOR, wnd, KEYBOARD, pn, p2);
  			TurnOnDisplay(wnd);
  			return TRUE;
  		case DEL:
  		    TurnOffDisplay(wnd);
  			delnl = *CurrChar == '\n' || TextBlockMarked(wnd);
  			BaseWndProc(EDITOR, wnd, KEYBOARD, p1, p2);
  			while (*CurrChar == pTab)
  				BaseWndProc(EDITOR, wnd, KEYBOARD, p1, p2);
  			AdjustTab(wnd);
  			TurnOnDisplay(wnd);
  			RepaintLine(wnd);
  			if (delnl)
  				SendMessage(wnd, PAINT, 0, 0);
  			return TRUE;
  		case '\t':
  		    TurnOffDisplay(wnd);
  			BaseWndProc(EDITOR, wnd, KEYBOARD, (PARAM) sTab, p2);
      	    while ((wnd->CurrCol % cfg.Tabs) != 0)
  				BaseWndProc(EDITOR, wnd, KEYBOARD, pTab, p2);
  			TurnOnDisplay(wnd);
  			RepaintLine(wnd);
  			return TRUE;
  		default:
  			if (((c & OFFSET) == 0) && (isprint(c) || c == '\r'))	{
  			    TurnOffDisplay(wnd);
  				BaseWndProc(EDITOR, wnd, KEYBOARD, p1, p2);
  				AdjustTab(wnd);
  				TurnOnDisplay(wnd);
  				RepaintLine(wnd);
  				if (c == '\r')
  					SendMessage(wnd, PAINT, 0, 0);
  				return TRUE;
  			}
  			break;
  	}
      return FALSE;
  }
  
  /* ------- Window processing module for EDITBOX class ------ */
  int EditorProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  {
      switch (msg)    {
  		case KEYBOARD:
              if (KeyboardMsg(wnd, p1, p2))
                  return TRUE;
              break;
  		case SETTEXT:
  			return SetTextMsg(wnd, (char *) p1);
          default:
              break;
      }
      return BaseWndProc(EDITOR, wnd, msg, p1, p2);
  }
  