/*
 * asm.cc
 *
 * Turbo Vision - Version 2.0
 *
 * All the assembly functions are converted in C/C++ and placed here.
 * This code was originally written by:
 * - Tommy Andreasen
 * - J”rn Sierwald
 *
 * Modified by Sergio Sigala <sergio@sigala.it>
 *
 * WARNING: very dirty code here... but it works :-)
 */

#define Uses_TEditor
#define Uses_TEvent
#define Uses_TFrame
#define Uses_TGroup
#define Uses_TPoint
#define Uses_TRect
#define Uses_TScreen
#define Uses_TTerminal
#define Uses_TView
#include <tvision/tv.h>

#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <config.h>		/* configuration file */

#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#else
#include <curses.h>
#endif

#ifdef ENABLE_VCS
extern int vcsFd;		/* virtual console system descriptor */
#endif

/*
 * SS: this code is used to refresh the screen only if strictly necessary.
 * Date: Mon Jun 23 10:26:09 MET DST 1997
 */
static int lockRefresh = 0;

inline void doRefresh(TView *p)
{
#ifdef ENABLE_VCS
	if (vcsFd >= 0) return;		/* refresh is not necessary */
#endif
	if (lockRefresh != 0) return;	/* we can't do any refresh */
	if (p->owner != NULL &&
		p->owner->lockFlag) return;	/* the owner is locked */
	refresh();
}

struct StaticVars1 {
  ushort *buf;
};

struct StaticVars2 {
  TView*        target;
  short         offset;
  short         y;
};

static StaticVars2 staticVars2;

int countLines( void *buf, size_t count )
{
  int anzahl=0;
  char *str=(char*) buf;
  for (unsigned int i=0; i<count; i++) {
    if (*(str++)== '\n') anzahl++;
  };
  return anzahl;
}
  
// These Routines are taken from Rogue Wave Tools++
size_t scan( const void *block, size_t size, const char *str )
{
  const	long   q	= 33554393L;
  const	long   q32	= q<<5;

  int	testLength	= size;
  int	patternLength	= strlen(str);

  if (patternLength <= 0) return UINT_MAX; //SS: nothing to search
  if( testLength < patternLength) return UINT_MAX;

  long	patternHash	= 0;
  long	testHash	= 0;

  register const char*  testP= (const char*)block;
  register const char*  patP = str;
  register long   x = 1;
  int             i = patternLength-1;
  while(i--) x =  (x<<5)%q;

  for (i=0; i<patternLength; i++) {
    patternHash = ( (patternHash<<5) + *patP++  ) % q;
    testHash    = ( (testHash   <<5) + *testP++ ) % q;
  }

  testP = (const char*)block;
  const char* end = testP + testLength - patternLength;

  while (1) {

     if(testHash == patternHash)
	 return testP-(const char*)block;

     if (testP >= end) break;

     // Advance & calculate the new hash value:
     testHash = ( testHash + q32 - *testP * x                 ) % q;
     testHash = ( (testHash<<5)  + *(patternLength + testP++) ) % q;
  }
  return UINT_MAX;		// Not found.

};

size_t iScan( const void *block, size_t size, const char *str )
{
  const	long   q	= 33554393L;
  const	long   q32	= q<<5;

  int	testLength	= size;
  int	patternLength	= strlen(str);

  if (patternLength <= 0) return UINT_MAX; //SS: nothing to search
  if( testLength < patternLength) return UINT_MAX;

  long	patternHash	= 0;
  long	testHash	= 0;

  register const unsigned char*  testP= (const unsigned char*)block;
  register const unsigned char*  patP = (const unsigned char*)str;
  register long   x = 1;
  int             i = patternLength-1;
  while(i--) x =  (x<<5)%q;

  for (i=0; i<patternLength; i++) {
    patternHash = ( (patternHash<<5) + toupper(*patP++)  ) % q;
    testHash    = ( (testHash   <<5) + toupper(*testP++) ) % q;
  }

  testP = (const unsigned char*)block;
  const unsigned char* end = testP + testLength - patternLength;

  while (1) {

     if(testHash == patternHash)
	 return testP-(const unsigned char*)block;

     if (testP >= end) break;

     // Advance & calculate the new hash value:
     testHash = ( testHash + q32 - toupper(*testP) * x                 ) % q;
     testHash = ( (testHash<<5)  + toupper(*(patternLength + testP++)) ) % q;
  }
  return UINT_MAX;		// Not found.
};

// edits.cpp defines functions previously found in edits.asm
//
// This file written by J”rn Sierwald based on a file
// written by Tommy Andreasen

char TEditor::bufChar( uint p )
{
    return buffer[p + ((p >= curPtr) ? gapLen : 0)];
}

uint TEditor::bufPtr( uint p )
{
    return (p >= curPtr) ? p + gapLen : p;
}

#if 0
void TEditor::formatLine( void *DrawBuf, uint LinePtr,
                          int Width, ushort Color )
{
    uint p = LinePtr;
    while ((p < curPtr) && (buffer[p] != 0x0D) && (p - LinePtr <= Width))
    {
        ((ushort *) DrawBuf) [p - LinePtr] = buffer[p] + ((Color & 0xFF) << 8);
        p++;
    }

    if (p >= curPtr)
    {
    p += gapLen;

    while ((p < bufSize) && (buffer[p] != 0x0D) &&
           (p - gapLen - LinePtr <= Width))
    {
        ((ushort *) DrawBuf) [p - gapLen - LinePtr] =
                                        buffer[p] + ((Color & 0xFF) << 8);
        p++;
    }
    } else 
        p += gapLen;

    while (p - gapLen - LinePtr <= Width)
    {
        ((ushort *) DrawBuf) [p - gapLen - LinePtr] =
                                        ' ' + ((Color & 0xFF) << 8);
        p++;
    }
}
#endif

void TEditor::formatLine( void *DrawBuf, uint LinePtr,
                          int Width, ushort Color )
{
  ushort i = 0;       // index in the DrawBuf
  size_t p = LinePtr; // index in the Buffer
  ushort curColor;

  /* draw the first part of the buffer */

  while ((p < curPtr) && (buffer[p] != '\n') && (i <= Width)) {
    curColor = (p>=selStart && p<selEnd) ? (Color & 0xFF00) :
	((Color & 0xFF) << 8);
    if (buffer[p] == 0x9) {
      do {
        ((ushort *) DrawBuf) [i] = ' ' + curColor;
        i++;
      } while ((i % 8) && (i <= Width));
      p++;
    } else {
      ((ushort *) DrawBuf) [i] = curColor | (uchar)buffer[p];
      p++; i++;
    }
  }

  /* draw the second part of the buffer */

  if (p >= curPtr)
  {
    p += gapLen;
  
    while ((p < bufSize) && (buffer[p] != '\n') && (i <= Width))
    {
      curColor = (p>=selStart && p<selEnd) ? (Color & 0xFF00) :
	((Color & 0xFF) << 8);
      if (buffer[p] == 0x9) {
        do {
          ((ushort *) DrawBuf) [i] = ' ' + curColor;
          i++;
        } while ((i % 8) && (i <= Width));
        p++;
      } else {
        ((ushort *) DrawBuf) [i] = curColor | (uchar)buffer[p];
        p++; i++;
      }
    }
  }
//  } else
//    p += gapLen; /* XXX */

  /* add some trailing spaces to fill the last part of the line */

  while (i < Width)	//buffer overflow problem fixed
  {
    curColor = (p>=selStart && p<selEnd) ? (Color & 0xFF00) :
	((Color & 0xFF) << 8);
    ((ushort *) DrawBuf) [i] = ' ' + curColor;
//    p++; i++; /* XXX */
    i++;
  }
}

uint TEditor::lineEnd( uint p )
{
/*
    while (p < curPtr)
        if (buffer[p] == 0x0D)
            return p;
        else
            p++;

    if (curPtr == bufLen)
        return curPtr;

    while (p + gapLen < bufLen)
        if (buffer[p + gapLen] == 0x0D)
            return p;
        else
            p++;

    return p;
*/
    if (p < curPtr)
    {
	/* SS: changed */

        while (p < curPtr)
            if (buffer[p] == '\n')
                return p;
            else
                p++;

        if (curPtr == bufLen)
            return bufLen;
 
 
    }
    else
    {
        if (p == bufLen)
            return bufLen;
    }

/* SS: changed */

    while (p + gapLen < bufSize)
        if (buffer[p + gapLen] == '\n')
            return p;
        else
            p++;

    return p;
 
}

uint TEditor::lineStart( uint p )
{
/*
    while (p - gapLen > curPtr)
        if (buffer[--p + gapLen] == 0x0D)
            return p + 2;

    if (curPtr == 0)
        return 0;

    while (p > 0)
        if (buffer[--p] == 0x0D)
            return p + 2;

    return 0;
*/
/* SS: changed */

    while (p > curPtr)
        if (buffer[--p + gapLen] == '\n')
                return p + 1;

    if (curPtr == 0)
        return 0;

/* SS: changed */

    while (p > 0)
        if (buffer[--p] == '\n')
                return p + 1;

    return 0;
}

uint TEditor::nextChar( uint p )
{
    if (p == bufLen)   return p;

    /* SS: changed */

    return ++p;
}

uint TEditor::prevChar( uint p )
{
    if (p == 0)   return p;

    /* SS: changed */

    return --p;
}

/*------------------------------------------------------------*/
/* filename -       exposed.cpp                               */
/*                                                            */
/* function(s)                                                */
/*                  Tview exposed member function             */
/*------------------------------------------------------------*/

/*------------------------------------------------------------*/
/*                                                            */
/*    Turbo Vision -  Version 1.0                             */
/*    Copyright (c) 1991 by Borland International             */
/*    All Rights Reserved.                                    */
/*                                                            */
/*    This file Copyright (c) 1993 by J”rn Sierwald           */
/*                                                            */
/*                                                            */
/*------------------------------------------------------------*/

int TView::exposedRec1(short x1, short x2, TView* p ) {
  while (1) {
/*20*/
    p=p->next;
    if (p==staticVars2.target) { // alle durch
      return exposedRec2( x1, x2, p->owner );
    };
    if ( !(p->state & sfVisible) || staticVars2.y<p->origin.y) continue; // keine Verdeckung

    if ( staticVars2.y<p->origin.y+p->size.y ) {
      // šberdeckung m”glich.
      if (x1<p->origin.x) { // f„ngt links vom Object an.
        if (x2<=p->origin.x) continue; // links vorbei
        if (x2>p->origin.x+p->size.x) {
          if (exposedRec1( x1, p->origin.x, p )) return 1;
          x1=p->origin.x+p->size.x;
        }
        else
          x2=p->origin.x;
      } else {
        if ( x1<p->origin.x+p->size.x ) x1=p->origin.x+p->size.x;
        if ( x1>=x2 ) return 0; // komplett verdeckt.
      };
    };

  }; // while

}

int TView::exposedRec2( short x1, short x2, TView* p ) {

  if (!(p->state & sfVisible)) return 0;
  if ( !p->owner || p->owner->buffer ) return 1;

  StaticVars2 savedStatics = staticVars2;

  staticVars2.y += p->origin.y;
  x1 += p->origin.x;
  x2 += p->origin.x;
  staticVars2.target=p;

  TGroup* g=p->owner;
  if (staticVars2.y<g->clip.a.y || staticVars2.y >= g->clip.b.y) {
    staticVars2 = savedStatics;
    return 0;
  };
  if (x1<g->clip.a.x) x1 = g->clip.a.x;
  if (x2>g->clip.b.x) x2 = g->clip.b.x;
  if (x1>=x2) {
    staticVars2 = savedStatics;
    return 0;
  };

  int retValue = exposedRec1( x1, x2, g->last );
  staticVars2 = savedStatics;
  return retValue;
}

Boolean TView::exposed() {
  if ( !(state & sfExposed) || size.x <= 0 || size.y <= 0 ) return Boolean(0);
  for (short y=0; y<size.y; y++) {
    staticVars2.y=y;
    if (exposedRec2( 0, size.x, this )) return Boolean(1);
  };
  return Boolean(0);
}

/*------------------------------------------------------------*/
/* filename -       framelin.cpp                              */
/*                                                            */
/* function(s)                                                */
/*                  TFrame frameLine member function          */
/*------------------------------------------------------------*/

/*------------------------------------------------------------*/
/*                                                            */
/*    Turbo Vision -  Version 1.0                             */
/*    Copyright (c) 1991 by Borland International             */
/*    All Rights Reserved.                                    */
/*                                                            */
/*    This file Copyright (c) 1993 by J”rn Sierwald           */
/*                                                            */
/*                                                            */
/*------------------------------------------------------------*/

/* Erkl„rung der Mask:

       Bit 0
         |
  Bit 3 - - Bit 1
         |
       Bit 2

Wenn z.B. sichergestellt werden soll, dass eine linke obere Ecke im
Muster vorhanden ist, nimmt man :
  mask |= 0x06 .
*/

void TFrame::frameLine( TDrawBuffer& frameBuf, short y, short n, uchar color )
{
  unsigned char frameMask[maxViewWidth];
  short int i;
  frameMask[0]=initFrame[n];
  for (i=1; i+1<size.x; i++) {
    frameMask[i]=initFrame[n+1];
  };
  frameMask[size.x-1]=initFrame[n+2];

  TView* p;
  p=owner->last;
  while (1) {
    p=p->next;
    if (p==this) break;
    if ((p->options & ofFramed) && (p->state & sfVisible)) {
      unsigned char mask1, mask2;
      if (y+1<p->origin.y) continue;
      else if (y+1==p->origin.y) { mask1=0x0A; mask2=0x06;}
      else if (y==p->origin.y+p->size.y) { mask1=0x0A; mask2=0x03;}
      else if (y<p->origin.y+p->size.y) { mask1=0; mask2=0x05;}
      else continue;
      unsigned short xMin=p->origin.x;
      unsigned short xMax=p->origin.x+p->size.x;
      if (xMin<1) xMin=1;
      if (xMax>size.x-1) xMax=size.x-1;
      if (xMax>xMin) {
        if (mask1==0) {
          frameMask[xMin-1] |= mask2;
          frameMask[xMax]   |= mask2;
        } else {
          frameMask[xMin-1] |= mask2;
          frameMask[xMax]   |= (mask2 ^ mask1);
          for (i=xMin; i< xMax; i++) {
            frameMask[i] |= mask1;
          }
        };
      };
    };
  }; // while
  unsigned short* dest=frameBuf.data;
  i=size.x;
  short int i1=0;
  while (i--) {
    *dest++= ( ((unsigned short)color) << 8 ) + (unsigned char) frameChars[frameMask[i1]];
    i1++;
  } /* endwhile */
};

/*------------------------------------------------------------*/
/* filename -       tgrmv.cpp                                 */
/*                                                            */
/* function(s)                                                */
/*                  TGroup removeView member function         */
/*------------------------------------------------------------*/

/*------------------------------------------------------------*/
/*                                                            */
/*    Turbo Vision -  Version 1.0                             */
/*    Copyright (c) 1991 by Borland International             */
/*    All Rights Reserved.                                    */
/*                                                            */
/*    This file Copyright (c) 1993 by J”rn Sierwald           */
/*                                                            */
/*                                                            */
/*------------------------------------------------------------*/

void TGroup::removeView( TView *p ) {
  if (last) {
    TView *cur=last;
    while (1) {
      if (p==cur->next) {
        cur->next=p->next;
        if (last==p) {
          if (cur->next==p) last=0;
          else last=cur;
          break;
        };
      };
      if (cur->next==last) break;
      cur=cur->next;
    };
  }; // endif
};

/*------------------------------------------------------------*/
/* filename -       tvcursor.cpp                              */
/*                                                            */
/* function(s)                                                */
/*                  Tview resetCursor member function         */
/*------------------------------------------------------------*/

/*------------------------------------------------------------*/
/*                                                            */
/*    Turbo Vision -  Version 1.0                             */
/*    Copyright (c) 1991 by Borland International             */
/*    All Rights Reserved.                                    */
/*                                                            */
/*    This file Copyright (c) 1993 by J”rn Sierwald           */
/*                                                            */
/*                                                            */
/*------------------------------------------------------------*/

void TView::resetCursor() {
  TView *p,*p2;
  TGroup *g;
  TPoint cur;
  if  ((state & (sfVisible | sfCursorVis | sfFocused))
             == (sfVisible | sfCursorVis | sfFocused) )
  {
    p=this;
    cur=cursor;
    while (1) {
      if (!(cur.x>=0 && cur.x<p->size.x
          && cur.y>=0 && cur.y<p->size.y)) {
        break;
      };
      cur.x += p->origin.x;
      cur.y += p->origin.y;
      p2 =p;
      g=p->owner;
      if (g==0) {
        //cursor setzen

	/*
	 * SS: we should change the cursor size according to the sfCursorIns
	 * flag in the state variable:
	 *
	 * if (state & sfCursorIns) {
         *     setBigCursor
         * } else {
         *     setSmallCursor
         * }
	 *
	 * Is there a way to do it under linux ?
	 */
	TScreen::moveCursor(cur.x, cur.y);
	TScreen::drawCursor(1);
        return;
      };
      if (!(g->state & sfVisible)) break;
      p=g->last;
      {
        label1:
        p=p->next;
        if (p==p2) { // alle durchgesucht.
          p=p->owner;
          continue;
        };
        if ((p->state & sfVisible) 
            && cur.x>=p->origin.x 
            && cur.x<p->size.x+p->origin.x
            && cur.y>=p->origin.y 
            && cur.y<p->size.y+p->origin.y) {
          break; // Cursor wird verdeckt.
        };
        goto label1;
      };
    };
  } 
  // no cursor, please.
  TScreen::drawCursor(0);
}

// TTPRVLNS.CPP
// Copyright 1994 by J”rn Sierwald
//
// C++ Version of ttprvlns.asm
// implementation of TTerminal::prevLines(...)
//
// "You don't need assembler to write obfuscated code."

ushort TTerminal::prevLines(ushort pos, ushort lines ) {
  if (lines==0) { bufInc(pos); bufInc(pos); return pos; };
  // I don't see the logic in the previous line. But that's what
  // the .asm file says.

  if (pos==queBack) return queBack; // Nothing to do

  bufDec(pos); // pos might be pointing to a '\n'

  if (pos<queBack) {
    while ( !( buffer[pos]=='\n' && !--lines ) && pos-- );
    if (lines) pos=bufSize-1;
  };

  if (lines)
/* SS: we should check if there is an available character before read it */
	while (pos > queBack && !( buffer[pos]=='\n' && !--lines ))
	{
		pos--;
	}

  if (lines)
    return queBack;
  else 
    bufInc(pos);

  return pos;
};

// TVWRITE.CPP
// Copyright 1993,1994 by J”rn Sierwald
//
// C++ Version of tvwrite.asm
//
// It doesn't look beautiful, but what the heck..

extern TPoint shadowSize;
extern uchar shadowAttr;

static StaticVars1 staticVars1;

void TView::writeViewRec1(short x1, short x2, TView* p, int shadowCounter ) {
  while (1) {
/*20*/
    p=p->next;
    if (p==staticVars2.target) { // alle durch
      // printit!
      if (p->owner->buffer) {

/* 
 * SS: now we should remove the mouse pointer from the screen.  This is
 * not necessary because we have a copy of the screen.
 *
 * if (p->owner->buffer == TScreen::screenBuffer) TScreen::drawMouse(0);
 */

	if (shadowCounter == 0)
	{
		/* SS: writes a row of data to the screen */

		if (p->owner->buffer == TScreen::screenBuffer)
			TScreen::writeRow(
			p->owner->size.x * staticVars2.y + x1,
			staticVars1.buf + (x1 - staticVars2.offset),
			x2 - x1);
		memmove(p->owner->buffer + p->owner->size.x * staticVars2.y +
			x1, staticVars1.buf + x1 - staticVars2.offset,
			(x2 - x1) * 2);
	} else { // paint with shadowAttr
		int l = x2 - x1;
		int dst1 = p->owner->size.x * staticVars2.y + x1;
		ushort *dst = p->owner->buffer + dst1;
		ushort *src= staticVars1.buf + (x1 - staticVars2.offset);
		while (l--)
		{
			ushort d = *src++ & 0xff | (shadowAttr << 8);

			/* SS: writes a character on the screen */

			if (p->owner->buffer == TScreen::screenBuffer)
				TScreen::writeRow(dst1++, &d, 1);
			*dst++ = d;
	        }
	}

/* SS: draws mouse pointer */

if (p->owner->buffer == TScreen::screenBuffer) TScreen::drawMouse(1);
      };
      if (p->owner->lockFlag==0) writeViewRec2( x1, x2, p->owner, shadowCounter );
      return ; // (p->owner->lockFlag==0);
    };
    if ( !(p->state & sfVisible) || staticVars2.y<p->origin.y) continue; // keine Verdeckung

    if ( staticVars2.y<p->origin.y+p->size.y ) {
      // šberdeckung m”glich.
      if (x1<p->origin.x) { // f„ngt links vom Object an.
        if (x2<=p->origin.x) continue; // links vorbei
        writeViewRec1( x1, p->origin.x, p, shadowCounter );
        x1=p->origin.x;
      };
                   //  if (x1>=p->origin.x) {
      if ( x2<=p->origin.x+p->size.x ) return; // komplett verdeckt.
      if ( x1<p->origin.x+p->size.x ) x1=p->origin.x+p->size.x;
                  // if ( x1>=p->origin.x+p->size.x ) { // k”nnte h”chstens im Schatten liegen
      if ( (p->state & sfShadow) && (staticVars2.y>=p->origin.y+shadowSize.y)) {
        if (x1>=p->origin.x+p->size.x+shadowSize.x) {
          continue; // rechts vorbei
        } else {
          shadowCounter++;
          if (x2<=p->origin.x+p->size.x+shadowSize.x) {
            continue; // alles im Schatten
          } else { // aufteilen Schattenteil, rechts daneben
            writeViewRec1( x1, p->origin.x+p->size.x+shadowSize.x, p, shadowCounter );
            x1=p->origin.x+p->size.x+shadowSize.x;
            shadowCounter--;
            continue;
          };
        };
      } else {
        continue; // rechts vorbei, 1.Zeile hat keinen Schatten
      };
    };
    if ( (p->state & sfShadow) && (staticVars2.y < p->origin.y+p->size.y+shadowSize.y) ) {
      // im y-Schatten von Object?
      if (x1<p->origin.x+shadowSize.x) {
        if (x2<= p->origin.x+shadowSize.x) continue; // links vorbei
        writeViewRec1( x1, p->origin.x+shadowSize.x, p, shadowCounter );
        x1 = p->origin.x+shadowSize.x;
      };
      if (x1>=p->origin.x+shadowSize.x+p->size.x) continue;
      shadowCounter++;
      if (x2<=p->origin.x+p->size.x+shadowSize.x) {
        continue; // alles im Schatten
      } else { // aufteilen Schattenteil, rechts daneben
        writeViewRec1( x1, p->origin.x+p->size.x+shadowSize.x, p, shadowCounter );
        x1=p->origin.x+p->size.x+shadowSize.x;
        shadowCounter--;
        continue;
      };

    } else { // zu weit unten
      continue;
    };

  }; // while
      
}

void TView::writeViewRec2( short x1, short x2, TView* p, int shadowCounter ) {
  if (!(p->state & sfVisible) || p->owner==0 ) return;

  StaticVars2 savedStatics = staticVars2;

  staticVars2.y += p->origin.y;
  x1 += p->origin.x;
  x2 += p->origin.x;
  staticVars2.offset += p->origin.x;
  staticVars2.target=p;

  TGroup* g=p->owner;
  if (staticVars2.y<g->clip.a.y || staticVars2.y >= g->clip.b.y) {
    staticVars2 = savedStatics;
    return;
  };
  if (x1<g->clip.a.x) x1 = g->clip.a.x;
  if (x2>g->clip.b.x) x2 = g->clip.b.x;
  if (x1>=x2) {
    staticVars2 = savedStatics;
    return;
  };

  writeViewRec1( x1, x2, g->last, shadowCounter );
  staticVars2 = savedStatics;
}

void TView::writeView( short x1, short x2, short y, const void* buf ) {
//  cerr << "Output ";
  if (y<0 || y>=size.y) return;
  if (x1<0) x1=0;
  if (x2>size.x) x2=size.x;
  if (x1>=x2) return;
  staticVars2.offset=x1;
  staticVars1.buf= (ushort*) buf;
  staticVars2.y=y;
  writeViewRec2( x1, x2, this, 0 );
	doRefresh(this);
}

void TView::writeBuf( short x, short y, short w, short h, const void *buf) {
	lockRefresh++;		/* stop the refresh */
  for (int i=0; i<h; i++) {
    writeView( x,x+w,y+i,(ushort*) buf + w*i );
  } /* endfor */
	lockRefresh--;		/* allow the refresh */
	doRefresh(this);
}

void TView::writeChar( short x, short y, char c, uchar color, short count) {
  ushort b[maxViewWidth];
  ushort myChar= ( ((ushort)mapColor(color))<<8 ) + (unsigned char) c;
  short count2=count;
  if (x<0) x=0;
  if (x+count>maxViewWidth) return;
  ushort* p = b;
  while ( count-- ) *p++ = myChar;
  writeView( x, x+count2, y, b);
}

void TView::writeLine( short x, short y, short w, short h, const void *buf) {
  if (h==0) return;
	lockRefresh++;		/* stop the refresh */
  for (int i=0; i<h; i++) {
    writeView ( x, x+w, y+i, buf );
  };
	lockRefresh--;		/* allow the refresh */
	doRefresh(this);
}

void TView::writeStr( short x, short y, const char *str, uchar color) {
  if (!str) return;
  ushort l= strlen(str);
  if (l==0) return;
  if (l>maxViewWidth) l=maxViewWidth;
  ushort l2=l;
  ushort myColor=( (ushort)mapColor(color) ) << 8;
  ushort b[maxViewWidth];
  ushort* p = b;
  while ( *p++ = myColor+(*(const unsigned char*)str++), --l );
  writeView ( x, x+l2, y, b );
}


syntax highlighted by Code2HTML, v. 0.9.1