884 lines
25 KiB
C++
884 lines
25 KiB
C++
#include "stdafx.h"
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include "winio.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
#define winio_caret_visible() \
|
|
((yCurrLine <= (yTopOfWin + yWinHeight)) && \
|
|
(xCurrPos <= (xLeftOfWin + xWinWidth)) && \
|
|
(xCurrPos >= xLeftOfWin))
|
|
|
|
#define CHECK_INIT() if (! tWinioVisible) return FALSE
|
|
|
|
#define MAX_X 127
|
|
#define TABSIZE 8
|
|
#define TYPE_AHEAD 256
|
|
#define WINIO_DEFAULT_BUFFER 8192
|
|
#define MIN_DISCARD 256
|
|
#define CARET_WIDTH 2
|
|
|
|
// For scrolling procedures
|
|
#define USE_PARAM 10000
|
|
#define DO_NOTHING 10001
|
|
|
|
|
|
typedef struct {
|
|
int hSB, vSB;
|
|
} recVKtoSB;
|
|
|
|
/* This table defines, by scroll message, what increment to try */
|
|
/* and scroll horizontally. PGUP and PGDN entries are updated */
|
|
/* in the winio_wmsize function. */
|
|
int cScrollLR[SB_ENDSCROLL + 1] =
|
|
//UP DOWN PGUP PGDN POS TRACK TOP BOT ENDSCROLL
|
|
{ -1, +1, -1, +1, USE_PARAM, USE_PARAM, -MAX_X, MAX_X, DO_NOTHING};
|
|
|
|
/* This table defines, by scroll message, what increment to try */
|
|
/* and scroll horizontally. PGUP and PGDN entries are updated */
|
|
/* in the winio_wmsize function, and the TOP & BOTTOM entries */
|
|
/* are updated by addchar function. */
|
|
int cScrollUD[SB_ENDSCROLL + 1] =
|
|
//UP DOWN PGUP PGDN POS TRACK TOP BOT ENDSCROLL
|
|
{ -1, +1, -1, +1, USE_PARAM, USE_PARAM, -1, +1, DO_NOTHING};
|
|
|
|
/* This table associates horizontal and vertical scroll */
|
|
/* messages that should be generated by the arrow and page keys */
|
|
recVKtoSB VKtoSB[VK_DOWN - VK_PRIOR + 1] =
|
|
// VK_PRIOR VK_NEXT
|
|
{ { DO_NOTHING, SB_PAGEUP }, { DO_NOTHING, SB_PAGEDOWN },
|
|
// VK_END VK_HOME
|
|
{ SB_TOP, SB_BOTTOM }, { SB_TOP, SB_TOP },
|
|
// VK_LEFT VK_UP
|
|
{ SB_LINEUP, DO_NOTHING }, { DO_NOTHING, SB_LINEUP },
|
|
// VK_RIGHT VK_DOWN
|
|
{ SB_LINEDOWN, DO_NOTHING },{ DO_NOTHING, SB_LINEDOWN } };
|
|
|
|
|
|
|
|
|
|
/* =================================================================== */
|
|
/* the interface functions themselves..... */
|
|
/* =================================================================== */
|
|
|
|
char * WinIo::gets(char *pchTmp)
|
|
{
|
|
char *pch = pchTmp;
|
|
int c;
|
|
|
|
CHECK_INIT();
|
|
bufSOI = bufused; /* mark beginning of line to limit backspace */
|
|
do {
|
|
switch (c = fgetchar())
|
|
{
|
|
case '\b' : if (pch > pchTmp) pch--; break;
|
|
case 0x1b : pch = pchTmp; break;
|
|
case EOF : bufSOI = (unsigned)-1; return NULL;
|
|
default : *pch = (char) c; pch++;
|
|
}
|
|
} while (c);
|
|
bufSOI = (unsigned)-1;
|
|
return pchTmp;
|
|
}
|
|
|
|
int WinIo::printf(const char *fmt, ...)
|
|
{
|
|
va_list marker;
|
|
va_start(marker, fmt);
|
|
return vprintf(fmt, marker);
|
|
}
|
|
|
|
int WinIo::vprintf(const char *fmt, va_list marker)
|
|
{
|
|
static char s[1024];
|
|
int len;
|
|
|
|
CHECK_INIT();
|
|
len = vsprintf(s, fmt, marker);
|
|
addchars(s,len);
|
|
return len;
|
|
}
|
|
|
|
int WinIo::fgetchar(void)
|
|
{
|
|
CHECK_INIT();
|
|
return _fputchar(chInput());
|
|
}
|
|
|
|
int WinIo::kbhit(void)
|
|
{
|
|
CHECK_INIT();
|
|
return (pchKbIn == pchKbOut);
|
|
}
|
|
|
|
int WinIo::fputchar(int c)
|
|
{
|
|
CHECK_INIT();
|
|
addchars((LPSTR)&c, 1);
|
|
return c;
|
|
}
|
|
|
|
int WinIo::puts(const char *s)
|
|
{
|
|
char c = '\n';
|
|
CHECK_INIT();
|
|
addchars((char *) s, strlen(s));
|
|
addchars(&c, 1);
|
|
return 0;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* USED INTERNALLY - pops up an error window and returns FALSE */
|
|
/* --------------------------------------------------------------- */
|
|
int WinIo::fail(char *s)
|
|
{
|
|
MessageBox(s,"ERROR",MB_OK);
|
|
return FALSE;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* pops up a message window */
|
|
/* --------------------------------------------------------------- */
|
|
BOOL WinIo::winio_warn(BOOL confirm, const char *fmt, ...)
|
|
{
|
|
char s[256];
|
|
va_list marker;
|
|
|
|
va_start(marker, fmt);
|
|
vsprintf(s, fmt, marker);
|
|
va_end(marker);
|
|
|
|
return (MessageBox(s, winio_title,
|
|
confirm? MB_OKCANCEL : MB_OK) == IDOK);
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* The application must call this function before using any of the */
|
|
/* covered stdio type calls. We need the parameter info in order */
|
|
/* to create the window. The function allocates the buffer and */
|
|
/* creates the window. It returns TRUE or FALSE. */
|
|
/* --------------------------------------------------------------- */
|
|
int WinIo::Initialize(void)
|
|
{
|
|
static RECT start;
|
|
int cx, cy, inc;
|
|
|
|
|
|
if (tWinioVisible) {
|
|
return FALSE;
|
|
}
|
|
|
|
Create( NULL, winio_title );
|
|
|
|
set_font();
|
|
|
|
bufsize = 1024 * 100;
|
|
|
|
fpBuffer = (LPSTR)LocalAlloc(LPTR, bufsize);
|
|
if (!fpBuffer) {
|
|
return FALSE;
|
|
}
|
|
|
|
fpKeyboard = (LPSTR)LocalAlloc(LPTR, kbsize);
|
|
if (!fpKeyboard) {
|
|
return FALSE;
|
|
}
|
|
|
|
*fpBuffer = '\0';
|
|
|
|
cx = GetSystemMetrics(SM_CXSCREEN);
|
|
cy = GetSystemMetrics(SM_CYSCREEN);
|
|
inc = GetSystemMetrics(SM_CYCAPTION);
|
|
cxScroll = GetSystemMetrics(SM_CXVSCROLL);
|
|
cyScroll = GetSystemMetrics(SM_CYHSCROLL);
|
|
|
|
start.left = cx >> 3;
|
|
start.right = 3 * (cx >> 2);
|
|
start.top = cy >> 3;
|
|
start.bottom = 3 * (cy >> 2);
|
|
|
|
tWinioVisible = TRUE;
|
|
winio_clear();
|
|
winio_yield();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Clear the contents of the buffer. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::winio_clear(void)
|
|
{
|
|
memset(fpBuffer,0,(int) bufsize - 1);
|
|
fpCurrLine = fpTopOfWin = fpBuffer;
|
|
*fpBuffer = '\0';
|
|
xCurrPos = 0;
|
|
yCurrLine = 0;
|
|
yTopOfWin = 0;
|
|
xLeftOfWin = 0;
|
|
bufused = 0;
|
|
|
|
if (tWinioVisible)
|
|
{
|
|
SetScrollRange(SB_VERT, 1, yCurrLine + 1, FALSE);
|
|
SetScrollPos(SB_VERT, yTopOfWin + 1, TRUE);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* Closes the window by sending it a WM_DESTROY message. Note that it */
|
|
/* does not disable the _onclose defined function. So the user program */
|
|
/* handler will be triggered. Does NOT cause the app. to terminate. */
|
|
/* ------------------------------------------------------------------- */
|
|
void WinIo::winio_close()
|
|
{
|
|
tTerminate = FALSE;
|
|
DestroyWindow();
|
|
tTerminate = TRUE;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* processes any outstanding events waiting. These may be characters */
|
|
/* typed at the keyboard, WM_PAINT messages, etc. It is called */
|
|
/* internally but should also be used liberally by the application */
|
|
/* within loops. */
|
|
/* ------------------------------------------------------------------- */
|
|
void WinIo::winio_yield()
|
|
{
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* This function allows the font of the window to be modified, and may */
|
|
/* be used BEFORE winio_init. Currently, only SYSTEM_, ANSI_, and */
|
|
/* OEM_FIXED_FONTs are supported. */
|
|
/* ------------------------------------------------------------------- */
|
|
BOOL WinIo::winio_setfont(WORD wFont)
|
|
{
|
|
if ((wFont != SYSTEM_FIXED_FONT) &&
|
|
(wFont != ANSI_FIXED_FONT) &&
|
|
(wFont != OEM_FIXED_FONT) )
|
|
return FALSE;
|
|
curr_font = wFont;
|
|
if (tWinioVisible)
|
|
{
|
|
set_font();
|
|
if (tPaint)
|
|
InvalidateRect(NULL, TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* This function allows the title of the window to be modified, and may */
|
|
/* be used BEFORE winio_init. */
|
|
/* ------------------------------------------------------------------- */
|
|
void WinIo::winio_settitle(char *pchTitle)
|
|
{
|
|
strncpy(winio_title, pchTitle, 127);
|
|
winio_title[127] = '\0';
|
|
if (tWinioVisible)
|
|
SetWindowText(winio_title);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* This function allows the caller to specifiy immediate or deferred */
|
|
/* screen updates. The call may not be issued before winio_init(). */
|
|
/* ------------------------------------------------------------------- */
|
|
BOOL WinIo::SetPaint(BOOL on)
|
|
{
|
|
BOOL ret = tPaint;
|
|
|
|
CHECK_INIT();
|
|
if (tPaint = on)
|
|
InvalidateRect(NULL, TRUE);
|
|
return ret;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_PAINT handler. It sends the currrent 'in view' piece of */
|
|
/* the buffer to the window. Note that an embedded NULL character */
|
|
/* signifies an end of line, not '\n'. */
|
|
/* --------------------------------------------------------------- */
|
|
|
|
void WinIo::OnPaint()
|
|
{
|
|
PAINTSTRUCT ps;
|
|
LPSTR pchSOL = fpTopOfWin;
|
|
LPSTR pchEOL;
|
|
int i, j, xStart;
|
|
int xLeft, xRight, yTop, yBottom;
|
|
CDC *cdc;
|
|
|
|
|
|
if (!tWinioVisible) {
|
|
return;
|
|
}
|
|
|
|
cdc = BeginPaint(&ps);
|
|
|
|
xLeft = (ps.rcPaint.left / cxChar) + xLeftOfWin;
|
|
xRight = (ps.rcPaint.right / cxChar) + xLeftOfWin;
|
|
yTop = ps.rcPaint.top / cyChar;
|
|
yBottom = ps.rcPaint.bottom / cyChar;
|
|
SelectObject(cdc->m_hDC, GetStockObject(curr_font));
|
|
|
|
for (i = 0; i < yTop; i++) // lines above repaint region
|
|
{
|
|
while (*pchSOL)
|
|
pchSOL++;
|
|
pchSOL++;
|
|
}
|
|
|
|
if (i <= yCurrLine) // something needs repainting..
|
|
{
|
|
for (i = yTop; i <= yBottom; i++) // lines in repaint region
|
|
{
|
|
for (j = 0; (j < xLeft) && (*pchSOL); j++, pchSOL++)
|
|
; // Scroll right
|
|
pchEOL = pchSOL;
|
|
xStart = j - xLeftOfWin;
|
|
for (j = 0; (*pchEOL) ; j++, pchEOL++) ; // end of line
|
|
TextOut(cdc->m_hDC, cxChar * xStart, cyChar * i, pchSOL,
|
|
min(j, xRight - xLeft + 2));
|
|
if ((unsigned)(pchEOL - fpBuffer) >= bufused)
|
|
break;
|
|
pchSOL = ++pchEOL;
|
|
}
|
|
}
|
|
|
|
EndPaint(&ps);
|
|
adjust_caret();
|
|
return;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_SIZE handler. It updates the internal record of our */
|
|
/* window size, minus the scroll bars, and recalcs the scroll bar */
|
|
/* ranges. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
if (!tWinioVisible) {
|
|
return;
|
|
}
|
|
|
|
cxWidth = cx;
|
|
cyHeight = cy;
|
|
|
|
xWinWidth = (cxWidth - cxScroll ) / cxChar;
|
|
yWinHeight = (cyHeight - cyScroll ) / cyChar;
|
|
|
|
cScrollLR[SB_PAGEUP] = -xWinWidth / 2;
|
|
cScrollLR[SB_PAGEDOWN] = +xWinWidth / 2;
|
|
cScrollUD[SB_PAGEUP] = -yWinHeight + 1;
|
|
cScrollUD[SB_PAGEDOWN] = +yWinHeight - 1;
|
|
|
|
SetScrollRange(SB_HORZ, 1, MAX_X, FALSE);
|
|
SetScrollPos(SB_HORZ, xLeftOfWin + 1, TRUE);
|
|
|
|
SetScrollRange(SB_VERT, 1, yCurrLine + 1, FALSE);
|
|
SetScrollPos(SB_VERT, yTopOfWin + 1, TRUE);
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_DESTROY handler. It frees up storage associated with the */
|
|
/* window, and resets its state to uninitialized. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnDestroy()
|
|
{
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_char handler. It adds the char to the internal kb buffer */
|
|
/* if there is room otherwise it queues a BEEP */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
LPSTR lpchKeybd = fpKeyboard;
|
|
unsigned pchSave = pchKbIn;
|
|
|
|
pchKbIn++;
|
|
if (pchKbIn == TYPE_AHEAD) {
|
|
pchKbIn = 0;
|
|
}
|
|
if (pchKbIn == pchKbOut) {
|
|
MessageBeep(0);
|
|
pchKbIn = pchSave;
|
|
} else {
|
|
*(lpchKeybd + pchSave) = nChar;
|
|
}
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_KEYDOWN handler. This handles what would be called */
|
|
/* function keys in the DOS world. In this case the function keys */
|
|
/* operate as scroll bar controls, so we generate messages to the */
|
|
/* scroll message handlers below. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
int hSB, vSB;
|
|
|
|
if ((nChar < VK_PRIOR) || (nChar > VK_DOWN)) {
|
|
return;
|
|
}
|
|
|
|
hSB = VKtoSB[nChar - VK_PRIOR].hSB;
|
|
vSB = VKtoSB[nChar - VK_PRIOR].vSB;
|
|
if (hSB != DO_NOTHING) {
|
|
SendMessage(WM_HSCROLL, hSB, 0L);
|
|
}
|
|
if (vSB != DO_NOTHING) {
|
|
SendMessage(WM_VSCROLL, vSB, 0L);
|
|
}
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_HSCROLL handler. It adjusts what part of the buffer */
|
|
/* is visible. It operates as left/right arrow keys. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
int cxSave = xLeftOfWin;
|
|
int xInc = cScrollLR[nSBCode];
|
|
|
|
if (xInc == DO_NOTHING) {
|
|
return;
|
|
}
|
|
|
|
if (xInc == USE_PARAM) {
|
|
xLeftOfWin = nPos - 1;
|
|
} else {
|
|
xLeftOfWin += xInc;
|
|
}
|
|
|
|
if ((xLeftOfWin = max(0, min(MAX_X - 1, xLeftOfWin))) == cxSave) {
|
|
return;
|
|
}
|
|
|
|
ScrollWindow((cxSave - xLeftOfWin) * cxChar, 0, NULL, NULL);
|
|
SetScrollPos(SB_HORZ, xLeftOfWin + 1, TRUE);
|
|
UpdateWindow();
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_VSCROLL handler. It adjusts what part of the buffer */
|
|
/* is visible. It operates as page and line up/down keys. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
int cySave = yTopOfWin;
|
|
int yInc = cScrollUD[nSBCode];
|
|
int i;
|
|
|
|
|
|
if (yInc == DO_NOTHING) {
|
|
return;
|
|
}
|
|
|
|
if (yInc == USE_PARAM) {
|
|
yTopOfWin = nPos - 1;
|
|
} else {
|
|
yTopOfWin += yInc;
|
|
}
|
|
|
|
if ((yTopOfWin = max(0, min(yCurrLine, yTopOfWin))) == cySave) {
|
|
return;
|
|
}
|
|
|
|
if (yTopOfWin > cySave) {
|
|
for (i = cySave; i < yTopOfWin; i++) {
|
|
fpTopOfWin = nextline(fpTopOfWin);
|
|
}
|
|
} else {
|
|
for (i = cySave; i > yTopOfWin; i--) {
|
|
fpTopOfWin = prevline(fpTopOfWin);
|
|
}
|
|
}
|
|
|
|
ScrollWindow(0, (cySave - yTopOfWin) * cyChar, NULL, NULL);
|
|
SetScrollPos(SB_VERT, yTopOfWin + 1, TRUE);
|
|
UpdateWindow();
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_SETFOCUS handler. It sets up the text caret. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnSetFocus(CWnd* pOldWnd)
|
|
{
|
|
#if 0
|
|
CreateCaret(CARET_WIDTH, cyChar);
|
|
|
|
if ((tCaret = winio_caret_visible())) {
|
|
SetCaretPos((xCurrPos - xLeftOfWin) * cxChar,
|
|
(yCurrLine - yTopOfWin) * cyChar);
|
|
ShowCaret();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Our WM_KILLFOCUS handler. It destroys the text caret. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::OnKillFocus(CWnd* pNewWnd)
|
|
{
|
|
if (tCaret) {
|
|
HideCaret();
|
|
tCaret = FALSE;
|
|
}
|
|
DestroyCaret();
|
|
}
|
|
|
|
|
|
void WinIo::set_font(void)
|
|
{
|
|
CDC *cdc;
|
|
TEXTMETRIC tm;
|
|
|
|
cdc = GetDC();
|
|
SelectObject(cdc->m_hDC, GetStockObject(curr_font));
|
|
GetTextMetrics(cdc->m_hDC,&tm);
|
|
ReleaseDC(cdc);
|
|
cxChar = tm.tmAveCharWidth;
|
|
cyChar = tm.tmHeight+tm.tmExternalLeading;
|
|
xWinWidth = (cxWidth - cxScroll ) / cxChar;
|
|
yWinHeight = (cyHeight - cyScroll ) / cyChar;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Adjusts the position of the caret, and shows or hides it, as */
|
|
/* appropriate. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::adjust_caret()
|
|
{
|
|
#if 0
|
|
int t = winio_caret_visible();
|
|
|
|
if (t) {
|
|
SetCaretPos((xCurrPos - xLeftOfWin) * cxChar,
|
|
(yCurrLine - yTopOfWin) * cyChar);
|
|
}
|
|
if (t && (! tCaret)) {
|
|
ShowCaret(hwnd);
|
|
}
|
|
if ((! t) && tCaret) {
|
|
HideCaret(hwnd);
|
|
}
|
|
tCaret = t;
|
|
#endif
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Computes, on the basis of what has just been updated, what area */
|
|
/* of the window needs to be repainted. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::compute_repaint(void)
|
|
{
|
|
RECT rc;
|
|
static int xCP = 0, yCL = 0;
|
|
int tWholeWin = FALSE;
|
|
|
|
if (yCurrLine > (yTopOfWin + yWinHeight))
|
|
{
|
|
yTopOfWin = 0;
|
|
fpTopOfWin = fpBuffer;
|
|
while (yTopOfWin < (yCurrLine - ((yWinHeight + 1) / 2)))
|
|
{
|
|
fpTopOfWin = nextline(fpTopOfWin);
|
|
yTopOfWin++;
|
|
}
|
|
tWholeWin = TRUE;
|
|
}
|
|
|
|
if ((xCurrPos < xLeftOfWin) || (xCurrPos > (xLeftOfWin + xWinWidth)))
|
|
{
|
|
xLeftOfWin = 0;
|
|
while (xLeftOfWin < (xCurrPos - ((xWinWidth + 1) / 2)))
|
|
xLeftOfWin++;
|
|
tWholeWin = TRUE;
|
|
}
|
|
|
|
if (tWholeWin)
|
|
InvalidateRect(NULL, TRUE);
|
|
else
|
|
{
|
|
rc.left = ((yCL == yCurrLine) ?
|
|
(min(xCP, xCurrPos) - xLeftOfWin) * cxChar : 0);
|
|
rc.top = (yCL - yTopOfWin) * cyChar;
|
|
rc.right = (xWinWidth + 1) * cxChar;
|
|
rc.bottom = (yCurrLine - yTopOfWin + 1) * cyChar;
|
|
InvalidateRect(&rc, TRUE);
|
|
}
|
|
|
|
yCL = yCurrLine;
|
|
xCP = xCurrPos;
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Adds the supplied cch-long string to the display buffer, and */
|
|
/* ensures any changed part of the window is repainted. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::addchars(char *pch, unsigned cch)
|
|
{
|
|
int ycSave = yCurrLine;
|
|
int ytSave = yTopOfWin;
|
|
int xSave = xLeftOfWin;
|
|
|
|
make_avail(cch);
|
|
|
|
append2buffer(pch, cch);
|
|
|
|
if (ycSave != yCurrLine)
|
|
SetScrollRange(SB_VERT, 1, yCurrLine + 1, FALSE);
|
|
|
|
if (! tPaint)
|
|
return;
|
|
|
|
compute_repaint();
|
|
|
|
cScrollUD[SB_TOP] = -yCurrLine;
|
|
cScrollUD[SB_BOTTOM] = yCurrLine;
|
|
if (ytSave != yTopOfWin)
|
|
SetScrollPos(SB_VERT, yTopOfWin + 1, TRUE);
|
|
|
|
if (xSave != xLeftOfWin)
|
|
SetScrollPos(SB_HORZ, xLeftOfWin + 1, TRUE);
|
|
|
|
winio_yield();
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* Add chars onto the display buffer, wrapping at end of line, */
|
|
/* expanding tabs, etc. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::append2buffer(char *pch, unsigned cch)
|
|
{
|
|
unsigned i;
|
|
|
|
for (i = 0; i < cch; i++, pch++)
|
|
{
|
|
switch (*pch)
|
|
{
|
|
case '\n' :
|
|
*pch = '\0';
|
|
*(fpBuffer + bufused) = '\0';
|
|
bufused++;
|
|
fpCurrLine = fpBuffer + bufused;
|
|
yCurrLine++;
|
|
xCurrPos = 0;
|
|
bufSOI = bufused;
|
|
break;
|
|
case '\t' :
|
|
do {
|
|
*(fpBuffer + bufused) = ' ';
|
|
bufused++;
|
|
xCurrPos++;
|
|
} while ((xCurrPos % TABSIZE) != 0);
|
|
break;
|
|
case EOF :
|
|
break;
|
|
case '\b' :
|
|
if (bufused > bufSOI)
|
|
{
|
|
bufused--;
|
|
xCurrPos--;
|
|
}
|
|
break;
|
|
case 0x1b :
|
|
while (bufused > bufSOI)
|
|
{
|
|
bufused--;
|
|
xCurrPos--;
|
|
}
|
|
break;
|
|
case 0x07 :
|
|
MessageBeep(0);
|
|
break;
|
|
default :
|
|
if (*pch > 0x1a)
|
|
{
|
|
if (xCurrPos >= MAX_X)
|
|
{
|
|
*(fpBuffer + bufused) = '\0';
|
|
bufused++;
|
|
xCurrPos = 0;
|
|
yCurrLine++;
|
|
fpCurrLine = fpBuffer + bufused;
|
|
}
|
|
xCurrPos++;
|
|
*(fpBuffer + bufused) = *pch;
|
|
bufused++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*(fpBuffer + bufused) = '\0'; // '\0' terminator after end of buffer
|
|
}
|
|
|
|
/* --------------------------------------------------------------- */
|
|
/* If we have run out of room in the display buffer, drop whole */
|
|
/* lines, and move the remaining buffer up. */
|
|
/* --------------------------------------------------------------- */
|
|
void WinIo::make_avail(unsigned cch)
|
|
{
|
|
unsigned cDiscard = 0;
|
|
LPSTR fpTmp;
|
|
unsigned i;
|
|
|
|
if ((unsigned long)(bufused + cch + TABSIZE) < bufsize)
|
|
return;
|
|
|
|
fpTmp = fpBuffer;
|
|
cDiscard = ((max(MIN_DISCARD, cch + 1) + MIN_DISCARD - 1)
|
|
/ MIN_DISCARD) // this gives a whole number of
|
|
* MIN_DISCARD; // our allocation units.
|
|
fpTmp += (LONG) cDiscard;
|
|
fpTmp = nextline(fpTmp);
|
|
cDiscard = fpTmp - fpBuffer;
|
|
CopyMemory(fpBuffer, fpTmp, bufused - cDiscard + 1);
|
|
bufused -= cDiscard;
|
|
if ((int) bufSOI != -1) bufSOI -= cDiscard;
|
|
fpTmp = fpBuffer + (LONG) bufused;
|
|
for (i = 0; i < cDiscard; i++) *fpTmp++ = '\0';
|
|
fpCurrLine = fpBuffer;
|
|
xCurrPos = yCurrLine = 0;
|
|
for (i = 0; i < bufused; i++)
|
|
{
|
|
if (*fpCurrLine)
|
|
xCurrPos++;
|
|
else
|
|
{
|
|
xCurrPos = 0;
|
|
yCurrLine++;
|
|
}
|
|
fpCurrLine++;
|
|
}
|
|
xLeftOfWin = yTopOfWin = -9999;
|
|
|
|
InvalidateRect(NULL, TRUE);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* These two routines find the beginning of the next, and previous */
|
|
/* lines relative to their input pointer */
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
LPSTR WinIo::nextline(LPSTR p)
|
|
{
|
|
while (*p) p++; return ++p;
|
|
}
|
|
|
|
LPSTR WinIo::prevline(LPSTR p)
|
|
{
|
|
p--; do p--; while (*p); return ++p;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
/* Waits for a character to appear in the keyboard buffer, yielding */
|
|
/* while nothing is available. Then inserts it into the buffer. */
|
|
/* ------------------------------------------------------------------- */
|
|
int WinIo::chInput(void)
|
|
{
|
|
LPSTR lpchKeyBd;
|
|
char c;
|
|
|
|
CHECK_INIT();
|
|
while (pchKbIn == pchKbOut)
|
|
winio_yield();
|
|
|
|
lpchKeyBd = fpKeyboard;
|
|
c = *(lpchKeyBd + pchKbOut);
|
|
|
|
pchKbOut++;
|
|
if (pchKbOut == TYPE_AHEAD)
|
|
pchKbOut = 0;
|
|
|
|
// Do CR/LF and EOF translation
|
|
return (c == 0x1a) ? EOF : (c == '\r') ? '\n' : c;
|
|
}
|
|
|
|
|
|
IMPLEMENT_DYNCREATE(WinIo, CMDIChildWnd)
|
|
|
|
WinIo::WinIo()
|
|
{
|
|
}
|
|
|
|
WinIo::WinIo(LPCTSTR title)
|
|
{
|
|
bufsize = 0;
|
|
kbsize = 0;
|
|
bufused = 0;
|
|
bufSOI = 0;
|
|
curr_font = 0;
|
|
tWinioVisible = 0;
|
|
tCaret = 0;
|
|
tFirstTime = 0;
|
|
cxChar = 0;
|
|
cyChar = 0;
|
|
cxScroll = 0;
|
|
cyScroll = 0;
|
|
cxWidth = 0;
|
|
cyHeight = 0;
|
|
xWinWidth = 0;
|
|
yWinHeight = 0;
|
|
xCurrPos = 0;
|
|
xLeftOfWin = 0;
|
|
yTopOfWin = 0;
|
|
yCurrLine = 0;
|
|
pchKbIn = 0;
|
|
pchKbOut = 0;
|
|
fpBuffer = NULL;
|
|
fpTopOfWin = NULL;
|
|
fpCurrLine = NULL;
|
|
fpKeyboard = NULL;
|
|
tTerminate = NULL;
|
|
tPaint = NULL;
|
|
|
|
strcpy( winio_class, "winio_class" );
|
|
strcpy( winio_icon, "winio_icon" );
|
|
strcpy( winio_title, title );
|
|
bufsize = WINIO_DEFAULT_BUFFER;
|
|
kbsize = TYPE_AHEAD;
|
|
bufused, bufSOI;
|
|
curr_font = SYSTEM_FIXED_FONT;
|
|
tWinioVisible = FALSE;
|
|
tCaret = FALSE;
|
|
tFirstTime = TRUE;
|
|
tTerminate = TRUE;
|
|
tPaint = TRUE;
|
|
}
|
|
|
|
WinIo::~WinIo()
|
|
{
|
|
tWinioVisible = FALSE;
|
|
LocalFree(fpBuffer);
|
|
LocalFree(fpKeyboard);
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(WinIo, CMDIChildWnd)
|
|
ON_WM_PAINT()
|
|
ON_WM_SIZE()
|
|
ON_WM_DESTROY()
|
|
ON_WM_CHAR()
|
|
ON_WM_HSCROLL()
|
|
ON_WM_VSCROLL()
|
|
ON_WM_SETFOCUS()
|
|
ON_WM_KILLFOCUS()
|
|
ON_WM_KEYDOWN()
|
|
END_MESSAGE_MAP()
|