/*
* textview.cc
*
* Turbo Vision - Version 2.0
*
* Copyright (c) 1994 by Borland International
* All Rights Reserved.
*
* Modified by Sergio Sigala <sergio@sigala.it>
* Modified by Max Okumoto <okumoto@ucsd.edu>
*/
#define Uses_TTextDevice
#define Uses_TTerminal
#define Uses_otstream
#include <tvision/tv.h>
#include <string.h>
using std::ostream;
using std::streamsize;
TTextDevice::TTextDevice( const TRect& bounds,
TScrollBar *aHScrollBar,
TScrollBar *aVScrollBar) :
TScroller(bounds,aHScrollBar,aVScrollBar)
{
}
TTerminal::TTerminal( const TRect& bounds,
TScrollBar *aHScrollBar,
TScrollBar *aVScrollBar,
ushort aBufSize ) :
TTextDevice(bounds, aHScrollBar, aVScrollBar),
queFront( 0 ),
#ifndef __UNPATCHED
queBack( 0 ),
curLineWidth( 0 ) // Added for horizontal cursor tracking.
#else
queBack( 0 )
#endif
{
growMode = gfGrowHiX + gfGrowHiY;
bufSize = min( 32000U, aBufSize );
buffer = new char[ bufSize ];
setLimit( 0, 1 );
setCursor( 0, 0 );
showCursor();
}
TTerminal::~TTerminal()
{
delete buffer;
}
void TTerminal::bufDec( ushort& val )
{
if (val == 0)
val = bufSize - 1;
else
val--;
}
void TTerminal::bufInc( ushort& val )
{
if( ++val >= bufSize )
val = 0;
}
Boolean TTerminal::canInsert( ushort amount )
{
long T = (queFront < queBack) ?
( queFront + amount ) :
( long(queFront) - bufSize + amount); // cast needed so we get
// signed comparison
return Boolean( queBack > T );
}
void TTerminal::draw()
{
short i;
ushort begLine, endLine;
#ifndef __UNPATCHED
char s[ maxViewWidth+1 ]; // KRW: Bug Fix/Enhancement: 95/01/05
// Do *NOT* attempt to display more
// than maxViewWidth chars
// ** assume size.x <= maxViewWidth **
#else
char s[256];
#endif
ushort bottomLine;
bottomLine = size.y + delta.y;
if( limit.y > bottomLine )
{
endLine = prevLines( queFront, limit.y - bottomLine );
bufDec( endLine );
}
else
endLine = queFront;
if( limit.y > size.y )
i = size.y - 1;
else
{
for( i = limit.y; i <= size.y - 1; i++ )
writeChar(0, i, ' ', 1, size.x);
i = limit.y - 1;
}
for( ; i >= 0; i-- )
{
#ifndef __UNPATCHED
// KRW: Bug fix/enhancement - handle any length line by only copying
// to s those characters to be displayed, which we assume will
// be < maxViewWidth
// This whole block rewritten
memset( s, ' ', size.x ); // must display blanks if no characters!
begLine = prevLines(endLine, 1);
if (endLine >= begLine)
{
// Entire string to be displayed is in one fragment, not
// wrapped around the end of the buffer
int fragmentLength = int( endLine - begLine );
if (fragmentLength > delta.x)
{
fragmentLength -= delta.x;
fragmentLength = min( size.x, fragmentLength );
memcpy( s, &buffer[begLine+delta.x], fragmentLength );
}
}
else
{
// Extract first fragment into s
int deltaLeft = delta.x;
int firstFragmentLength = int( bufSize - begLine );
if (firstFragmentLength > delta.x)
{
deltaLeft = 0;
firstFragmentLength -= delta.x;
firstFragmentLength = min( size.x, firstFragmentLength );
memcpy( s, &buffer[begLine+delta.x], firstFragmentLength );
}
else
{
deltaLeft -= firstFragmentLength;
firstFragmentLength = 0;
}
// Extract second fragment into s
if ((endLine > deltaLeft) && (firstFragmentLength < size.x))
{
int secondFragmentLength = endLine - deltaLeft;
secondFragmentLength =
min(size.x-firstFragmentLength,secondFragmentLength);
memcpy( &s[ firstFragmentLength ], &buffer[ deltaLeft ],
secondFragmentLength );
}
}
s[ size.x ] = EOS;
writeStr( 0, i, s, 1 );
endLine = begLine;
bufDec( endLine );
#else
begLine = prevLines(endLine, 1);
if (endLine >= begLine)
{
int T = int( endLine - begLine );
memcpy( s, &buffer[begLine], T );
s[T] = EOS;
}
else
{
int T = int( bufSize - begLine);
memcpy( s, &buffer[begLine], T );
memcpy( s+T, buffer, endLine );
s[T+endLine] = EOS;
}
if( delta.x >= strlen(s) )
*s = EOS;
else
strcpy( s, &s[delta.x] );
writeStr( 0, i, s, 1 );
writeChar( strlen(s), i, ' ', 1, size.x );
endLine = begLine;
bufDec( endLine );
#endif
}
}
ushort TTerminal::nextLine( ushort pos )
{
if( pos != queFront )
{
while( buffer[pos] != '\n' && pos != queFront )
bufInc(pos);
if( pos != queFront )
bufInc( pos );
}
return pos;
}
int TTerminal::do_sputn( const char *s, int count )
{
#ifndef __UNPATCHED
ushort screenWidth = limit.x;
ushort screenLines = limit.y;
// BUG FIX - Mon 07/25/94 - EFW: Made TTerminal adjust horizontal
// scrollbar limit too.
/* SS: stupid thing */
ushort i;
for(i = 0; i < count; i++, curLineWidth++)
if(s[i] == '\n')
{
screenLines++;
// Check width when an LF is seen.
if(curLineWidth > screenWidth)
screenWidth = curLineWidth;
// Reset width for the next line.
curLineWidth = 0;
}
// One last check for width for cases where whole lines aren't
// received, maybe just a character or two.
if(curLineWidth > screenWidth)
screenWidth = curLineWidth;
#else
ushort screenLines = limit.y;
for( ushort i = 0; i < count; i++ )
if( s[i] == '\n' )
screenLines++;
#endif
while( !canInsert( count ) )
{
queBack = nextLine( queBack );
screenLines--;
}
if( queFront + count >= bufSize )
{
i = bufSize - queFront;
memcpy( &buffer[queFront], s, i );
memcpy( buffer, &s[i], count - i );
queFront = count - i;
}
else
{
memcpy( &buffer[queFront], s, count );
queFront += count;
}
#ifndef __UNPATCHED
setLimit( screenWidth, screenLines );
#else
setLimit( limit.x, screenLines );
#endif
scrollTo( 0, screenLines + 1 );
i = prevLines( queFront, 1 );
if( i <= queFront )
i = queFront - i;
else
i = bufSize - (i - queFront);
setCursor( i, screenLines - delta.y - 1 );
drawView();
return count;
}
Boolean TTerminal::queEmpty()
{
return Boolean( queBack == queFront );
}
TerminalBuf::TerminalBuf(TTerminal *tt): term(tt)
{
}
int TerminalBuf::overflow(int c)
{
streamsize n = pptr() - pbase();
if (n > 0 && sync() == EOF) return EOF;
if (c != EOF)
{
char b = c;
term->do_sputn(&b, sizeof(b));
}
pbump(-n);
return 0;
}
int TerminalBuf::sync()
{
streamsize n = pptr() - pbase();
if (n > 0) term->do_sputn(pbase(), n);
return 0;
}
otstream::otstream( TTerminal *tt ):
ostream(&buf),
buf(tt)
{
}
syntax highlighted by Code2HTML, v. 0.9.1