home *** CD-ROM | disk | FTP | other *** search
- /*
- WINIO.C
- Stdio (e.g. printf) functionality for Windows - implementation
- Dave Maxey - 1991
- */
-
- #include <windows.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <malloc.h>
- #include <string.h>
- #include "wmhandlr.h"
- #include "winio.h"
-
- /* PROTOTYPES in alphabetic order */
-
- void addchars(char *, unsigned);
- void adjust_caret(void);
- void append2buffer(char *, unsigned);
- int chInput(void);
- void compute_repaint(void);
- int initialize_buffers(unsigned);
- int initialize_class(HANDLE);
- void initialize_state(void);
- int initialize_window(HANDLE, HANDLE, int);
- void make_avail(unsigned);
- char far * nextline(char far *);
- char far * prevline(char far *);
- void set_font(void);
- long winio_wmpaint(HWND, unsigned, WORD, LONG);
- long winio_wmsize(HWND, unsigned, WORD, LONG);
- long winio_wmdestroy(HWND, unsigned, WORD, LONG);
- long winio_wmchar(HWND, unsigned, WORD, LONG);
- long winio_wmkeydown(HWND, unsigned, WORD, LONG);
- long winio_wmhscroll(HWND, unsigned, WORD, LONG);
- long winio_wmvscroll(HWND, unsigned, WORD, LONG);
- long winio_wmsetfocus(HWND, unsigned, WORD, LONG);
- long winio_wmkillfocus(HWND, unsigned, WORD, LONG);
-
- // this doesn't get declared in stdio.h if _WINDOWS is defined
- // although it is in the Windows libraries!
- int vsprintf(char *, const char *, va_list);
-
- #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
-
- char winio_class[15] = "winio_class";
- char winio_icon[15] = "winio_icon";
- char winio_title[128] = "Console I/O";
- unsigned long bufsize = WINIO_DEFAULT_BUFFER;
- unsigned long kbsize = TYPE_AHEAD;
- int bufused, bufSOI;
- int curr_font = SYSTEM_FIXED_FONT;
- int tWinioVisible = FALSE;
- int tCaret = FALSE, tFirstTime = TRUE;
- int cxChar, cyChar, cxScroll, cyScroll, cxWidth, cyHeight;
- int xWinWidth, yWinHeight, xCurrPos;
- int xLeftOfWin, yTopOfWin, yCurrLine;
- unsigned pchKbIn, pchKbOut;
- static char far *fpBuffer, far *fpTopOfWin, far *fpCurrLine;
- static char far *fpKeyboard;
- static HANDLE hBuffer, hKeyboard;
- HWND hWnd;
- BOOL tTerminate = TRUE,
- tPaint = TRUE;
- DESTROY_FUNC destroy_func;
-
- 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 *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 = -1; return NULL;
- default : *pch = (char) c; pch++;
- }
- } while (c);
- bufSOI = -1;
- return pchTmp;
- }
-
- int printf(const char *fmt, ...)
- {
- va_list marker;
- va_start(marker, fmt);
- return vprintf(fmt, marker);
- }
-
- int 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 fgetchar(void)
- {
- CHECK_INIT();
- return fputchar(chInput());
- }
-
- int kbhit(void)
- {
- CHECK_INIT();
- return (pchKbIn == pchKbOut);
- }
-
- int fputchar(int c)
- {
- CHECK_INIT();
- addchars(&((char) c), 1);
- return c;
- }
-
- int 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 fail(char *s)
- {
- MessageBox(NULL,s,"ERROR",MB_OK);
- return FALSE;
- }
-
- /* --------------------------------------------------------------- */
- /* pops up a message window */
- /* --------------------------------------------------------------- */
- BOOL 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(NULL, 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_init(HANDLE hInstance, HANDLE hPrevInstance,
- int nCmdShow, unsigned wBufSize)
- {
- if (tWinioVisible)
- return FALSE;
-
- if (! initialize_buffers(wBufSize))
- return FALSE;
-
- initialize_state();
-
- if (! initialize_window(hInstance, hPrevInstance, nCmdShow))
- return FALSE;
-
- tWinioVisible = TRUE;
-
- atexit(winio_end); /* hook into exit chain */
-
- winio_yield();
- return TRUE;
- }
-
- /* --------------------------------------------------------------- */
- /* Clear the contents of the buffer. */
- /* --------------------------------------------------------------- */
- void winio_clear(void)
- {
- _fmemset(fpBuffer,0,(int) bufsize - 1);
- fpCurrLine = fpTopOfWin = fpBuffer;
- *fpBuffer = '\0';
- xCurrPos = 0;
- yCurrLine = 0;
- yTopOfWin = 0;
- xLeftOfWin = 0;
- bufused = 0;
-
- if (tWinioVisible)
- {
- SetScrollRange(hWnd, SB_VERT, 1, yCurrLine + 1, FALSE);
- SetScrollPos(hWnd, SB_VERT, yTopOfWin + 1, TRUE);
- }
- }
-
- /* --------------------------------------------------------------- */
- /* Return the window handle of the underlying Windows object. */
- /* Can be used by an application to customize the WINIO window */
- /* --------------------------------------------------------------- */
- HWND winio_hwnd(void)
- {
- return hWnd;
- }
-
- /* --------------------------------------------------------------- */
- /* This function is called by winio_init(). It initializes a number */
- /* of global variables, including the WM_ handler table. */
- /* --------------------------------------------------------------- */
- void initialize_state()
- {
- winio_clear();
- destroy_func = 0;
-
- /* set up our message handlers */
- wmhandler_init();
- wmhandler_set(WM_PAINT, winio_wmpaint);
- wmhandler_set(WM_SIZE, winio_wmsize);
- wmhandler_set(WM_DESTROY, winio_wmdestroy);
- wmhandler_set(WM_CHAR, winio_wmchar);
- wmhandler_set(WM_HSCROLL, winio_wmhscroll);
- wmhandler_set(WM_VSCROLL, winio_wmvscroll);
- wmhandler_set(WM_SETFOCUS, winio_wmsetfocus);
- wmhandler_set(WM_KILLFOCUS, winio_wmkillfocus);
- wmhandler_set(WM_KEYDOWN, winio_wmkeydown);
- }
-
- /* --------------------------------------------------------------- */
- /* This function is called by winio_init(). It initializes our */
- /* Windows class, and some global variables */
- /* --------------------------------------------------------------- */
- int initialize_window(HANDLE hInst, HANDLE hPrev, int nCmdShow)
- {
- static RECT start;
- int cx, cy, inc;
-
- cx = GetSystemMetrics(SM_CXSCREEN);
- cy = GetSystemMetrics(SM_CYSCREEN);
- inc = GetSystemMetrics(SM_CYCAPTION);
- cxScroll = GetSystemMetrics(SM_CXVSCROLL);
- cyScroll = GetSystemMetrics(SM_CYHSCROLL);
-
- if (hPrev)
- {
- // note: other WINIO apps are NOT other instances!
- GetInstanceData(hPrev, (NPSTR) &start, sizeof(RECT));
- start.top += inc;
- start.left += inc;
- if (start.top > (cy >> 2))
- start.top = cy >> 3;
- if (start.left > (cx >> 2))
- start.left = cx >> 3;
- }
- else
- {
- if (! initialize_class(hInst))
- return fail("Could not create class");
-
- start.left = cx >> 3;
- start.right = 3 * (cx >> 2);
- start.top = cy >> 3;
- start.bottom = 3 * (cy >> 2);
- }
-
- hWnd = CreateWindow(winio_class, winio_title,
- WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
- start.left, start.top, start.right, start.bottom,
- NULL, NULL, hInst, NULL);
- if (! hWnd)
- return fail("Could not create window");
-
- set_font();
-
- ShowWindow(hWnd, nCmdShow);
- UpdateWindow(hWnd);
-
- return TRUE;
- }
-
- /* ----------------------------------------------------------------------- */
- /* Initializes Window Class */
- /* ----------------------------------------------------------------------- */
- int initialize_class(HANDLE hInst)
- {
- WNDCLASS wc;
-
- wc.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNCLIENT;
- wc.lpfnWndProc = (WNDPROC) WndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInst;
- wc.hIcon = LoadIcon(hInst, winio_icon);
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = GetStockObject(WHITE_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = winio_class;
-
- return RegisterClass(&wc);
- }
-
- /* ----------------------------------------------------------------------- */
- /* Uses GlobalAlloc() to allocate the display and keyboard buffers */
- /* ----------------------------------------------------------------------- */
- int initialize_buffers(unsigned wBufSize)
- {
- if (wBufSize)
- bufsize = max(wBufSize, 1024);
-
- if (! (hBuffer = GlobalAlloc(GMEM_MOVEABLE, bufsize)))
- return fail("Could not allocate\nconsole I/O buffer");
-
- fpBuffer = GlobalLock(hBuffer); // keep locked; assume protected mode
-
- if (! (hKeyboard = GlobalAlloc(GMEM_MOVEABLE, kbsize)))
- return fail("Could not allocate\ntype ahead buffer");
-
- fpKeyboard = GlobalLock(hKeyboard);
-
- *fpBuffer = '\0';
- fpBuffer++;
-
- return TRUE;
- }
-
- /* ----------------------------------------------------------------------- */
- /* Undoes the work of the above. Allows an application to close the window */
- /* Terminates the prog. */
- /* ----------------------------------------------------------------------- */
- void winio_end()
- {
- while (tWinioVisible)
- winio_yield();
- }
-
- /* ------------------------------------------------------------------- */
- /* 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_close()
- {
- tTerminate = FALSE;
- DestroyWindow(hWnd);
- 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_yield()
- {
- MSG msg;
- while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
-
- /* ------------------------------------------------------------------- */
- /* Let the application install an exit routine, called back from */
- /* winio_wmdestroy(). Deinstall by winio_onclose(NULL) */
- /* ------------------------------------------------------------------- */
- void winio_onclose(DESTROY_FUNC exitfunc)
- {
- destroy_func = exitfunc;
- }
-
- /* ------------------------------------------------------------------- */
- /* 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_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(hWnd, NULL, TRUE);
- }
- return TRUE;
- }
-
- /* ------------------------------------------------------------------- */
- /* This function allows the title of the window to be modified, and may */
- /* be used BEFORE winio_init. */
- /* ------------------------------------------------------------------- */
- void winio_settitle(char *pchTitle)
- {
- strncpy(winio_title, pchTitle, 127);
- winio_title[127] = '\0';
- if (tWinioVisible)
- SetWindowText(hWnd, 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(hWnd, 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'. */
- /* --------------------------------------------------------------- */
- long winio_wmpaint(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- HDC hdc;
- PAINTSTRUCT ps;
- char far *pchSOL = fpTopOfWin;
- char far *pchEOL;
- int i, j, xStart;
- int xLeft, xRight, yTop, yBottom;
-
- hdc = BeginPaint(hwnd, &ps);
-
- xLeft = (ps.rcPaint.left / cxChar) + xLeftOfWin;
- xRight = (ps.rcPaint.right / cxChar) + xLeftOfWin;
- yTop = ps.rcPaint.top / cyChar;
- yBottom = ps.rcPaint.bottom / cyChar;
- SelectObject(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(hdc, cxChar * xStart, cyChar * i, pchSOL,
- min(j, xRight - xLeft + 2));
- if ((pchEOL - fpBuffer) >= bufused)
- break;
- pchSOL = ++pchEOL;
- }
- }
-
- EndPaint(hwnd, &ps);
- adjust_caret();
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_SIZE handler. It updates the internal record of our */
- /* window size, minus the scroll bars, and recalcs the scroll bar */
- /* ranges. */
- /* --------------------------------------------------------------- */
- long winio_wmsize(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- cxWidth = LOWORD(lParam);
- cyHeight = HIWORD(lParam);
-
- 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(hwnd, SB_HORZ, 1, MAX_X, FALSE);
- SetScrollPos(hwnd, SB_HORZ, xLeftOfWin + 1, TRUE);
-
- SetScrollRange(hwnd, SB_VERT, 1, yCurrLine + 1, FALSE);
- SetScrollPos(hwnd, SB_VERT, yTopOfWin + 1, TRUE);
-
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_DESTROY handler. It frees up storage associated with the */
- /* window, and resets its state to uninitialized. */
- /* --------------------------------------------------------------- */
- long winio_wmdestroy(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- if (destroy_func)
- (*destroy_func)();
- GlobalUnlock(hBuffer);
- GlobalUnlock(hKeyboard);
- GlobalFree(hBuffer);
- GlobalFree(hKeyboard);
- tWinioVisible = FALSE;
- if (tTerminate) exit(0);
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_BYTE handler. It adds the char to the internal kb buffer */
- /* if there is room otherwise it queues a BEEP */
- /* --------------------------------------------------------------- */
- long winio_wmchar(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- char far *lpchKeybd = fpKeyboard;
- unsigned pchSave = pchKbIn;
-
- pchKbIn++;
- if (pchKbIn == TYPE_AHEAD)
- pchKbIn = 0;
- if (pchKbIn == pchKbOut)
- {
- MessageBeep(0);
- pchKbIn = pchSave;
- }
- else
- *(lpchKeybd + pchSave) = LOBYTE(wParam);
-
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* 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. */
- /* --------------------------------------------------------------- */
- long winio_wmkeydown(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- int hSB, vSB;
-
- if ((wParam < VK_PRIOR) || (wParam > VK_DOWN))
- return 0;
-
- hSB = VKtoSB[wParam - VK_PRIOR].hSB;
- vSB = VKtoSB[wParam - VK_PRIOR].vSB;
- if (hSB != DO_NOTHING)
- SendMessage(hwnd, WM_HSCROLL, hSB, 0L);
- if (vSB != DO_NOTHING)
- SendMessage(hwnd, WM_VSCROLL, vSB, 0L);
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_HSCROLL handler. It adjusts what part of the buffer */
- /* is visible. It operates as left/right arrow keys. */
- /* --------------------------------------------------------------- */
- long winio_wmhscroll(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- int cxSave = xLeftOfWin,
- xInc = cScrollLR[wParam];
-
- if (xInc == DO_NOTHING)
- return 0;
- else if (xInc == USE_PARAM)
- xLeftOfWin = LOWORD(lParam) - 1;
- else
- xLeftOfWin += xInc;
-
- if ((xLeftOfWin = max(0, min(MAX_X - 1, xLeftOfWin))) == cxSave)
- return 0;
-
- ScrollWindow(hwnd, (cxSave - xLeftOfWin) * cxChar, 0, NULL, NULL);
- SetScrollPos(hwnd, SB_HORZ, xLeftOfWin + 1, TRUE);
- UpdateWindow(hwnd);
-
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_VSCROLL handler. It adjusts what part of the buffer */
- /* is visible. It operates as page and line up/down keys. */
- /* --------------------------------------------------------------- */
- long winio_wmvscroll(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- int cySave = yTopOfWin,
- yInc = cScrollUD[wParam],
- i;
-
- if (yInc == DO_NOTHING)
- return 0;
- else if (yInc == USE_PARAM)
- yTopOfWin = LOWORD(lParam) - 1;
- else
- yTopOfWin += yInc;
-
- if ((yTopOfWin = max(0, min(yCurrLine, yTopOfWin))) == cySave)
- return 0;
-
- if (yTopOfWin > cySave)
- for (i = cySave; i < yTopOfWin; i++)
- fpTopOfWin = nextline(fpTopOfWin);
- else
- for (i = cySave; i > yTopOfWin; i--)
- fpTopOfWin = prevline(fpTopOfWin);
-
- ScrollWindow(hwnd, 0, (cySave - yTopOfWin) * cyChar, NULL, NULL);
- SetScrollPos(hwnd, SB_VERT, yTopOfWin + 1, TRUE);
- UpdateWindow(hwnd);
-
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_SETFOCUS handler. It sets up the text caret. */
- /* --------------------------------------------------------------- */
- long winio_wmsetfocus(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- CreateCaret(hwnd, NULL, CARET_WIDTH, cyChar);
-
- if ((tCaret = winio_caret_visible()))
- {
- SetCaretPos((xCurrPos - xLeftOfWin) * cxChar,
- (yCurrLine - yTopOfWin) * cyChar);
- ShowCaret(hwnd);
- }
-
- return 0;
- }
-
- /* --------------------------------------------------------------- */
- /* Our WM_KILLFOCUS handler. It destroys the text caret. */
- /* --------------------------------------------------------------- */
- long winio_wmkillfocus(HWND hwnd, unsigned message, WORD wParam, LONG lParam)
- {
- if (tCaret)
- {
- HideCaret(hwnd);
- tCaret = FALSE;
- }
- DestroyCaret();
- return 0;
- }
-
- void set_font(void)
- {
- HDC hdc;
- TEXTMETRIC tm;
-
- hdc = GetDC(hWnd);
- SelectObject(hdc, GetStockObject(curr_font));
- GetTextMetrics(hdc,&tm);
- ReleaseDC(hWnd,hdc);
- 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 adjust_caret()
- {
- 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;
- }
-
- /* --------------------------------------------------------------- */
- /* Computes, on the basis of what has just been updated, what area */
- /* of the window needs to be repainted. */
- /* --------------------------------------------------------------- */
- void 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(hWnd, 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(hWnd, &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 addchars(char *pch, unsigned cch)
- {
- int ycSave = yCurrLine;
- int ytSave = yTopOfWin;
- int xSave = xLeftOfWin;
-
- make_avail(cch);
-
- append2buffer(pch, cch);
-
- if (ycSave != yCurrLine)
- SetScrollRange(hWnd, SB_VERT, 1, yCurrLine + 1, FALSE);
-
- if (! tPaint)
- return;
-
- compute_repaint();
-
- cScrollUD[SB_TOP] = -yCurrLine;
- cScrollUD[SB_BOTTOM] = yCurrLine;
- if (ytSave != yTopOfWin)
- SetScrollPos(hWnd, SB_VERT, yTopOfWin + 1, TRUE);
-
- if (xSave != xLeftOfWin)
- SetScrollPos(hWnd, SB_HORZ, xLeftOfWin + 1, TRUE);
-
- winio_yield();
- }
-
- /* --------------------------------------------------------------- */
- /* Add chars onto the display buffer, wrapping at end of line, */
- /* expanding tabs, etc. */
- /* --------------------------------------------------------------- */
- void 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 make_avail(unsigned cch)
- {
- int cDiscard = 0;
- char far *fpTmp;
- int 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;
- _fmemcpy(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(hWnd, NULL, TRUE);
- }
-
-
- /* ------------------------------------------------------------------- */
- /* These two routines find the beginning of the next, and previous */
- /* lines relative to their input pointer */
- /* ------------------------------------------------------------------- */
-
- char far *nextline(char far *p) { while (*p) p++; return ++p; }
- char far *prevline(char far *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 chInput(void)
- {
- char far *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;
- }
-
-