/*
 * Smart terminal module
 * 
 * Copyright (c) 1990, 1991 by
 * William S. Hall
 * 3665 Benton Street  #66
 * Santa Clara, CA 95051
 *
 */

#define NOSOUND
#define NOCOMM
#define NOKANJI
#define NOATOM
#include <windows.h>
#if defined(WIN2)
#define SYMBOL_CHARSET	2
#include <winexp.h>
#endif 
#include <string.h>
#include <ascii.h>
#ifdef COLUMBIA
#include "wktsmt.h"
#else
#include "smterm.h"
#endif

static void NEAR TermWndPaint(PSMT pSmt, LPPAINTSTRUCT lpps);
static int NEAR SmartTermDisplay(PSMT pSmt, BYTE *str, short len);
static void NEAR ComputeVisibleWindow(PSMT pSmt, short right, short bottom);
static void NEAR DoCR(PSMT pSmt);
static void NEAR DoLF(PSMT pSmt);
static void NEAR DoBS(PSMT pSmt);
static void NEAR AdjustWindowToCursor(PSMT pSmt);
static void NEAR CursorUp(PSMT pSmt, int count);
static void NEAR CursorDown(PSMT pSmt, int count);
static void NEAR CursorRight(PSMT pSmt, int count);
static void NEAR CursorLeft(PSMT pSmt, int count);
static void NEAR ClearToEndOfLine(PSMT pSmt);
static void NEAR ClearToEndOfPage(PSMT pSmt);
static void NEAR PositionCursor(PSMT pSmt, short r, short c);
static void NEAR ReverseIndex(PSMT pSmt);
static void NEAR DoHT(PSMT pSmt);
static void NEAR AlignScreen(PSMT pSmt);
static void NEAR ClearScreen(PSMT pSmt);
static void NEAR SaveCursor(PSMT pSmt, BOOL flag);
static void NEAR ClearToTopOfPage(PSMT pSmt);
static void NEAR ClearToLineStart(PSMT pSmt);
static void NEAR ClearLine(PSMT pSmt);
static void NEAR ShowLineOfText(PSMT pSmt, HDC hDC, BYTE *str, short len,
			short xpos, short ypos, BYTE attrib);
static void NEAR InsertLine(PSMT pSmt, int count);
static void NEAR DeleteLine(PSMT pSmt, int count);
static void NEAR DeleteChar(PSMT pSmt, WORD count);
static void NEAR SetTabStop(PSMT pSmt, LONG param);
static void NEAR ChangeColors(PSMT pSmt, LONG *pColors);
static void NEAR SetVideoAttrib(PSMT pSmt, WORD index);
static void NEAR SetScrollRegion(PSMT pSmt, int top, int bottom);
static void NEAR FillScreen(PSMT pSmt);
static void NEAR SetScreen(PSMT pSmt, WORD rows, WORD cols);
static long NEAR CalcScrollRange(PSMT pSmt, short xsize, short ysize);
static void NEAR CopyLines(PSMT pSmt, short start, short end, LPSTR pbuf);
static void NEAR FlipScreen(PSMT pSmt, short top, short bottom);
static void NEAR SetCharSet(PSMT pSmt, WORD index);
static void NEAR wordmemset(WORD *dest, WORD val, int count);
static void NEAR scrollindex(PSMT pSmt, BOOL direction);
static void NEAR SetOriginMode(PSMT pSmt, BOOL param);
static void NEAR SmartTermCommand(register PSMT pSmt, 
				  register WORD wParam, LONG lParam);
static void NEAR SetFont(PSMT pSmt, SETFONT FAR *lplf);
static void NEAR ScrollBack(PSMT pSmt, int lines, BOOL direction);

long FAR PASCAL SmartTermWndProc(HWND hWnd, unsigned message, 
				 WORD wParam, LONG lParam)
{

    register PSMT pSmt = (PSMT)GetWindowWord(hWnd,0);
    PAINTSTRUCT ps;
    long numrem;

    switch(message) {

	case SMT_STRINGINPUT:
	    HideCaret(hWnd);
	    numrem = SmartTermDisplay(pSmt,(BYTE *)LOWORD(lParam),(short)wParam);
	    SetCaretPos(pSmt->Pos.x, pSmt->Pos.y + pSmt->CharHeight);
	    ShowCaret(hWnd);
	    return ((LONG)numrem);
	    break;
	    
	case SMT_COMMAND:
	    HideCaret(hWnd);
	    SmartTermCommand(pSmt, wParam, lParam);
	    SetCaretPos(pSmt->Pos.x, pSmt->Pos.y + pSmt->CharHeight);
	    ShowCaret(hWnd);
	    break;

	case SMT_SIZEPARENT:
	    ComputeVisibleWindow(pSmt, LOWORD(lParam), HIWORD(lParam));
	    MoveWindow(pSmt->hStatic, pSmt->vrect.left,
				      pSmt->vrect.top,
				      pSmt->vrect.right, 
			              pSmt->vrect.bottom, TRUE);
	    pSmt->rect.left = pSmt->rect.top = 0;
	    MoveWindow(pSmt->hWnd,pSmt->rect.left, pSmt->rect.top,
		       pSmt->rect.right, pSmt->rect.bottom,TRUE);
	    AdjustWindowToCursor(pSmt);
	    return(CalcScrollRange(pSmt,(short)LOWORD(lParam),
				   (short)HIWORD(lParam)));
	    break;	

	case SMT_CARETFUNCTION:
	    switch(wParam) {
	    	case SM_CREATECARET:
		    if (HIWORD(lParam))
		        CreateCaret(pSmt->hWnd,(HBITMAP)NULL,
					pSmt->CharWidth,-pSmt->CharHeight);
		    else
		        CreateCaret(pSmt->hWnd,(HBITMAP)NULL,
							pSmt->CharWidth,-2);
		    SetCaretPos(pSmt->Pos.x, pSmt->Pos.y + pSmt->CharHeight);
		    if (LOWORD(lParam))
	    	        ShowCaret(pSmt->hWnd);
	    	    break;
		case SM_DESTROYCARET:
		    HideCaret(pSmt->hWnd);
		    DestroyCaret();
		    break;
		case SM_HIDECARET:
		    HideCaret(pSmt->hWnd);
		    break;
		case SM_SHOWCARET:
		    ShowCaret(pSmt->hWnd);
		    break;
		case SM_GETCARETPOS:
		    return(MAKELONG(1 + pSmt->Pos.y / pSmt->CharHeight,
						pSmt->CurLineOffset + 1));
	    }	
	    break;

        case SMT_SETATTRIBUTE:
	    switch(wParam) {
		case SM_COLORCHANGE:
		    ChangeColors(pSmt, (LONG *)LOWORD(lParam));
		    break;
		case SM_AUTOWRAP:
		    pSmt->Wrap = LOWORD(lParam);
		    break;
		case SM_MARGINBELL:
		    pSmt->MarginBell = LOWORD(lParam);
		    break;
		case SM_SMOOTHSCROLL:
		    pSmt->SmoothScroll = LOWORD(lParam);
		    break;
		case SM_INSERT:
		    pSmt->ICToggle = LOWORD(lParam);
		    break;
		case SM_SCROLLUNITS:
		    pSmt->ScrollUnits = LOWORD(lParam);
		    break;
	    }
	    break;

	case SMT_GETATTRIBUTE:
	    switch(wParam) {
		case SM_AUTOWRAP:
		    return((LONG)pSmt->Wrap);
		    break;
		case SM_MARGINBELL:
		    return((LONG)pSmt->MarginBell);
		    break;
		case SM_SMOOTHSCROLL:
		    return((LONG)pSmt->SmoothScroll);
		    break;
		case SM_SCREENSIZE:
		    return(MAKELONG(pSmt->MaxLines, pSmt->MaxCols));
		    break;
		case SM_FONTFACE:
		    lstrcpy((LPSTR)lParam, pSmt->lfnt.lfFaceName);
		    return lstrlen(pSmt->lfnt.lfFaceName);
		case SM_NORMALFONT:
		    return MAKELONG(pSmt->NFontWidth, pSmt->NFontHeight);
		case SM_SMALLFONT:
		    return MAKELONG(pSmt->SFontWidth, pSmt->SFontHeight);
		case SM_SCROLLUNITS:
		    return (LONG)pSmt->ScrollUnits;
	    }
	    break;

	case SMT_SHOWWINDOW:
	    ShowWindow(pSmt->hStatic, wParam);
	    break;

	case SMT_INVERT:
	    FlipScreen(pSmt, LOWORD(lParam), HIWORD(lParam));
	    break;

	case SMT_COPYLINES:
	    CopyLines(pSmt, (int)LOBYTE(wParam), (int)HIBYTE(wParam),
					(LPSTR)lParam);
	    break;

	case WM_CREATE:
	    SmartTermWndCreate(hWnd, lParam);
	    break;

	case WM_PAINT:
            BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
	    TermWndPaint(pSmt, (LPPAINTSTRUCT)&ps);
            EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
            break;

	case WM_ERASEBKGND:
	    SelectObject((HDC)wParam, pSmt->hbr);
	    FillRect((HDC)wParam, (LPRECT)&pSmt->rect, pSmt->hbr);
	    return (LONG)TRUE;

	case WM_DESTROY:
	    if (pSmt->hbr)
		DeleteObject(pSmt->hbr);
	    if (pSmt->hFont)
		DeleteObject(pSmt->hFont);
	    break;

 	default:
	    return ((long)DefWindowProc(hWnd,message,wParam,lParam));
	    break;
    }
    return(0L);
}    

static void NEAR SmartTermCommand(register PSMT pSmt, 
				  register WORD wParam, LONG lParam)
{

    switch(wParam) {
	case SM_CURSORHOME:
	    pSmt->HaveToWrap = FALSE;
	    PositionCursor(pSmt, 0, 0);
	    break;
	case SM_CURSORUP:
	    CursorUp(pSmt, LOWORD(lParam));
	    break;
	case SM_CURSORDOWN:
	    CursorDown(pSmt, LOWORD(lParam));
	    break;
	case SM_CURSORRIGHT:
	    CursorRight(pSmt, LOWORD(lParam));
	    break;
	case SM_CURSORLEFT:
	    CursorLeft(pSmt, LOWORD(lParam));
	    break;
	case SM_CLRTOENDOFLINE:
	    ClearToEndOfLine(pSmt);
	    break;
	case SM_CLRTOENDOFPAGE:
	    ClearToEndOfLine(pSmt);
	    ClearToEndOfPage(pSmt);
	    break;
	case SM_POSITIONCURSOR:
	    pSmt->HaveToWrap = FALSE;
	    PositionCursor(pSmt,(short)LOWORD(lParam) - 1,
					(short)HIWORD(lParam) - 1);
	    break;
	case SM_REVERSEINDEX:
	    while (lParam--)
	        ReverseIndex(pSmt);
	    break;
	case SM_INDEX:
	    while (lParam--)
	        DoLF(pSmt);
	    break;
	case SM_NEXTLINE:
	    while (lParam--) {
	        DoCR(pSmt);
	        DoLF(pSmt);
	    }
	    break;
	case SM_ALIGNSCREEN:
	    AlignScreen(pSmt);
	    break;
	case SM_SAVECURSOR:
	    SaveCursor(pSmt, LOWORD(lParam));
	    break;
	case SM_CLEARSCREEN:
	    ClearScreen(pSmt);
	    break;
	case SM_CLEARTOTOPOFPAGE:
	    ClearToTopOfPage(pSmt);
	    ClearToLineStart(pSmt);
	    break;
	case SM_CLEARTOLINESTART:
	    ClearToLineStart(pSmt);
	    break;
	case SM_CLEARLINE:
	    ClearLine(pSmt);
	    break;
	case SM_DELETECHAR:
	    DeleteChar(pSmt, LOWORD(lParam));
	    break;
	case SM_INSERTLINE:
	    InsertLine(pSmt, LOWORD(lParam));
	    break;
	case SM_DELETELINE:
	    DeleteLine(pSmt, LOWORD(lParam));
	    break;
	case SM_SETTAB:
	    SetTabStop(pSmt, lParam);
	    break;
	case SM_VIDEOATTRIB:
	    SetVideoAttrib(pSmt, LOWORD(lParam));
	    break;
	case SM_SCROLLREGION:
	    SetScrollRegion(pSmt, LOWORD(lParam), HIWORD(lParam));
	    break;
	case SM_FILLSCREEN:
	    FillScreen(pSmt);
	    break;
	case SM_HSCROLL:
	    pSmt->rect.left = -LOWORD(lParam) * pSmt->CharWidth;
	    MoveWindow(pSmt->hWnd, pSmt->rect.left, pSmt->rect.top,
		 pSmt->rect.right, pSmt->rect.bottom, TRUE);
	    break;
	case SM_SETCOLS:
	    SetScreen(pSmt, pSmt->MaxLines, LOWORD(lParam));
	    break;
	case SM_LEFTMARGIN:
	    while (lParam--)
	        DoCR(pSmt);
	    break;
	case SM_TAB:
	    while (lParam--)
	        DoHT(pSmt);
	    break;
	case SM_BKSP:
	    while (lParam--)
	        DoBS(pSmt);
	    break;
	case SM_SETCHARSET:
	    SetCharSet(pSmt, LOWORD(lParam));
	    break;
	case SM_ORIGINMODE:
	    SetOriginMode(pSmt, LOWORD(lParam));
	    break;
	case SM_SETFONT:
	    SetFont(pSmt, (SETFONT FAR *)lParam);
	    break;
	case SM_SCROLLBACK:
	    ScrollBack(pSmt, LOWORD(lParam), (BOOL)HIWORD(lParam));
	    break;
	case SM_PAGEBACK:
	    ScrollBack(pSmt, pSmt->MaxLines, (BOOL)HIWORD(lParam));
	    break;
	case SM_HOMEEND:
	    ScrollBack(pSmt, pSmt->MaxTextLines, (BOOL)HIWORD(lParam));
	    break;
    }
}

static void NEAR ScrollBack(PSMT pSmt, int numlines, BOOL direction)
{

    register int buflines = pSmt->MaxTextLines;
    WORD *temp;
    register int i;
    
    if (direction) {
	numlines = min(numlines, pSmt->scrollback);
        if (numlines > 0) {
	    for (i = 0; i < numlines; i++) {
                temp = pSmt->lines[buflines - 1];
	        memmove(&pSmt->lines[1],
		        &pSmt->lines[0],
		        (buflines - 1) * sizeof(WORD *));
	        pSmt->lines[0] = temp;
	    }
	    pSmt->scrollback -= numlines;
	    pSmt->scrollforward += numlines;
            ScrollWindow(pSmt->hWnd,0,numlines * pSmt->CharHeight,
			 NULL,&pSmt->srect);
            UpdateWindow(pSmt->hWnd);
	}
    }
    else {
	numlines = min(numlines, pSmt->scrollforward);
	if (numlines > 0) {
	    for (i = 0; i < numlines; i++) {
		temp = pSmt->lines[0];
		memmove(&pSmt->lines[0],
			&pSmt->lines[1],
			(buflines - 1) * sizeof(WORD *));
		pSmt->lines[buflines - 1] = temp;
	    }
	    pSmt->scrollback += numlines;
	    pSmt->scrollforward -= numlines;
            ScrollWindow(pSmt->hWnd, 0, -numlines * pSmt->CharHeight, 
			 NULL, &pSmt->srect);
            UpdateWindow(pSmt->hWnd);
	}
    }
}

static void NEAR SetFont(PSMT pSmt, SETFONT FAR *lpsf)
{

    RECT size;

    pSmt->NFontWidth = lpsf->nwidth;
    pSmt->NFontHeight = lpsf->nheight;
    pSmt->SFontWidth = lpsf->swidth;
    pSmt->SFontHeight = lpsf->sheight;
    lstrcpy(pSmt->lfnt.lfFaceName, lpsf->FaceName);
    pSmt->hFont = SetFontData(pSmt);
    pSmt->srect.right = pSmt->rect.right = pSmt->CharWidth * pSmt->MaxCols;
    pSmt->srect.bottom = pSmt->rect.bottom = pSmt->CharHeight * pSmt->MaxLines;
    PositionCursor(pSmt, pSmt->CurLine, pSmt->CurLineOffset);
    GetClientRect(pSmt->hMain, &size);
    PostMessage(pSmt->hMain, WM_SIZE, SIZENORMAL,
		MAKELONG(size.right, size.bottom));

}

static void NEAR SetCharSet(PSMT pSmt, WORD index)
{

    register BYTE hattrib = (BYTE)HIBYTE((int)pSmt->Attrib);

    if (index)
	hattrib |= VA_SPECIAL;
    else
        hattrib &= ~VA_SPECIAL;

    pSmt->Attrib = 256 * hattrib;
}

/* character deletion */
static void NEAR DeleteChar(PSMT pSmt, WORD count)
{

    RECT rect;
    short offset = pSmt->CurLineOffset;
    WORD *dest = pSmt->lines[pSmt->CurLine] + offset;
    register short copycount;
    register WORD maxdelchars;

    if (count > (maxdelchars = pSmt->MaxCols - offset))
	count = maxdelchars;
    copycount = maxdelchars - count;
    memmove((BYTE *)dest, (BYTE *)(dest + count), copycount * sizeof (WORD));
    wordmemset(dest + copycount, SP, count);

    SetRect(&rect, pSmt->Pos.x, pSmt->Pos.y,
	    pSmt->rect.right, pSmt->Pos.y + pSmt->CharHeight);
    ScrollWindow(pSmt->hWnd,-pSmt->CharWidth * count, 0, &rect, &rect);
    UpdateWindow(pSmt->hWnd);
}

static void NEAR FlipScreen(PSMT pSmt, short top, short bottom)
{

    register int i, j;
    WORD mask = 256 * VA_MARK;
    short cols = pSmt->MaxCols;
    RECT rect;

    if ((top < 0) || (bottom > pSmt->MaxLines))
	return;

    for (i = top; i <= bottom; i++)
	for (j = 0; j < cols; j++)    
	    *(pSmt->lines[i] + j) ^= mask;

    rect.left = 0;
    rect.right = pSmt->rect.right;
    rect.top = top * pSmt->CharHeight;
    rect.bottom = (bottom + 1) * pSmt->CharHeight;

    InvalidateRect(pSmt->hWnd, &rect, FALSE);
}

static void NEAR CopyLines(PSMT pSmt, short start, short end, LPSTR pbuf)
{

    register int i, j;
    short cols = pSmt->MaxCols;
    int count;

    for (i = start; i <= end; i++) {
	for (j = cols - 1; (j >= 0) && (LOBYTE(*(pSmt->lines[i] + j)) == SP); j--)
	    ;
	count = j + 1;
	for (j = 0; j < count; j++)
	    *pbuf++ = LOBYTE(*(pSmt->lines[i] + j));
	*pbuf++ = '\r';
	*pbuf++ = '\n';
    }
}

static long NEAR CalcScrollRange(PSMT pSmt, short xsize, short ysize)
{

    register short xrange, yrange;
    short diff;

    diff = pSmt->rect.right - xsize;
    if (diff > 0) {
	xrange = diff / pSmt->CharWidth;
	if (diff % pSmt->CharWidth)
	    xrange += 1;
    }
    else
	xrange = 0;

    yrange = pSmt->rect.bottom - ysize;
    yrange = (yrange > 0 ? (yrange / pSmt->CharHeight) : 0);
    return MAKELONG(xrange, yrange);
}

static void NEAR SetScreen(PSMT pSmt, WORD rows, WORD cols)
{
    short size = rows * cols;
    HFONT hfont, holdfont;
    HDC hDC;
    TEXTMETRIC TM;
    register int i,j;
    
    if (cols == MAXCOLUMNS) {
	pSmt->lfnt.lfWidth = pSmt->SFontWidth;
	pSmt->lfnt.lfHeight = pSmt->SFontHeight;
	pSmt->Bold = pSmt->SBold;
	pSmt->Symbol = pSmt->SSymbol;
    }
    else {
	pSmt->lfnt.lfWidth = pSmt->NFontWidth;
	pSmt->lfnt.lfHeight = pSmt->NFontHeight;
	pSmt->Bold = pSmt->NBold;
	pSmt->Symbol = pSmt->NSymbol;
    }
    hDC = GetDC(pSmt->hWnd);
    hfont = CreateFontIndirect(&pSmt->lfnt);
    holdfont = SelectObject(hDC, hfont);
    GetTextMetrics(hDC, &TM);
    pSmt->CharHeight = TM.tmHeight + TM.tmExternalLeading;
    pSmt->CharWidth = TM.tmAveCharWidth;
    SelectObject(hDC, holdfont);
    ReleaseDC(pSmt->hWnd, hDC);

    if (pSmt->hFont)
	DeleteObject(pSmt->hFont);
    pSmt->hFont = hfont;

    pSmt->MaxCols = cols;
    pSmt->MaxLines = rows;

    for (i = 0; i < MAXTEXTBUFFERS * pSmt->MaxLines; i++) {
        pSmt->lines[i] = (pSmt->pVidBuffer + i * MAXCOLUMNS);
        for (j = 0; j < MAXCOLUMNS; j++)
	    *(pSmt->lines[i] + j) = SP;
    }
    pSmt->scrollback = 0;
    pSmt->scrollforward = 0;

    pSmt->TopScroll = pSmt->TopOrgLine = 0;
    pSmt->BottomScroll = pSmt->BottomOrgLine = pSmt->MaxLines - 1;
    pSmt->CurLine = 0;
    pSmt->CurLineOffset = 0;
    pSmt->Pos.x = pSmt->Pos.y = 0;
    pSmt->rect.left = pSmt->rect.top = 0;
    pSmt->srect.right = pSmt->rect.right = pSmt->CharWidth * pSmt->MaxCols;
    pSmt->srect.bottom = pSmt->rect.bottom = pSmt->CharHeight * pSmt->MaxLines;
    InvalidateRect(pSmt->hWnd, (LPRECT)NULL, TRUE);
}

static void NEAR SetVideoAttrib(PSMT pSmt, WORD index)
{
    register BYTE hattrib = (BYTE)HIBYTE((int)pSmt->Attrib);
    register BYTE special = (BYTE)(hattrib & VA_SPECIAL);

    switch(index) {
	case 0:
	    hattrib = (BYTE)(VA_NORMAL | special);
	    break;
	case 1:
	    hattrib |= VA_BOLD;
	    break;
	case 4:
	    hattrib |= VA_UNDERLINE;
	    break;
	case 5:
	    hattrib |= VA_BLINK;
	    break;
	case 7:
	    hattrib |= VA_REVERSE;
	    break;
	case 8:
	    hattrib |= VA_DIM;
	    break;
	case 22:
	    hattrib &= ~VA_BOLD;
	    break;
	case 24:
	    hattrib &= ~VA_UNDERLINE;
	    break;
	case 25:
	    hattrib &= ~VA_BLINK;
	    break;
	case 27:
	    hattrib &= ~VA_REVERSE;
	    break;
	case 28:
	    hattrib &= ~VA_DIM;
	    break;
    }    
    pSmt->Attrib = 256 * hattrib;
}

static void NEAR SetScrollRegion(PSMT pSmt, int top, int bottom)
{

    register short max = pSmt->MaxLines;
    register short cheight = pSmt->CharHeight;

    if ((top <= max) && (bottom <= max)) {
        if (top == 0)
	    top = 1;
        if (bottom == 0)
	    bottom = max;
        if (top < bottom) {
	    pSmt->srect.top = cheight *  (top - 1);
	    pSmt->srect.bottom = cheight * bottom;
	    pSmt->TopScroll = top - 1;
	    pSmt->BottomScroll = bottom - 1;
	    if (pSmt->OriginMode)
		SetOriginMode(pSmt, TRUE);
	    else
	       PositionCursor(pSmt, 0, 0);
	}
    }
}

static void NEAR ChangeColors(register PSMT pSmt, LONG *pColors)
{
    pSmt->TextColor = pColors[0];
    pSmt->BGColor = pColors[1];

    DeleteObject(pSmt->hbr);
    pSmt->hbr = CreateSolidBrush(pSmt->BGColor);

    InvalidateRect(pSmt->hWnd, (LPRECT)NULL, TRUE);
}

static void NEAR InsertLine(register PSMT pSmt, int count)
{

    register int i;
    WORD *save[MAXROWS];
    RECT rect;
    short top = pSmt->TopScroll;
    short cur = pSmt->CurLine;
    short bottom = pSmt->BottomScroll;
    short len;

    if ((top <= cur) && (cur <= bottom)) {
	count = min(bottom - cur + 1, count);
	len = bottom - count + 1;
	for (i = 0; i < count; i++) 
	    save[cur + i] = pSmt->lines[len + i];
	for (i = bottom; i >= cur + count; i--) 
	    pSmt->lines[i] = pSmt->lines[i - count];
	for (i = cur; i < cur + count; i++) {
	    pSmt->lines[i] = save[i];
	    wordmemset(pSmt->lines[i], SP, pSmt->MaxCols);
	}	    
	DoCR(pSmt);
        SetRect(&rect, 0, pSmt->Pos.y, pSmt->srect.right, pSmt->srect.bottom);
        ScrollWindow(pSmt->hWnd, 0, count * pSmt->CharHeight, &rect, &rect);
        UpdateWindow(pSmt->hWnd);
    }
}

static void NEAR DeleteLine(PSMT pSmt, int count)
{

    register int i;
    WORD *save[MAXROWS];
    RECT rect;
    short top = pSmt->TopScroll;
    short cur = pSmt->CurLine;
    short bottom = pSmt->BottomScroll;
    short len;

    if ((top <= cur) && (cur <= bottom)) {
	count = min(bottom - cur + 1, count);
	len = bottom - count + 1;
	for (i = 0; i < count; i++) 
	    save[len + i] = pSmt->lines[cur + i];
	for (i = cur + count; i <= bottom; i++) 
	    pSmt->lines[i - count] = pSmt->lines[i];
	for (i = len; i <= bottom; i++) {
	    pSmt->lines[i] = save[i];
	    wordmemset(pSmt->lines[i], SP, pSmt->MaxCols);
	}	    
	DoCR(pSmt);
        SetRect(&rect, 0, pSmt->Pos.y, pSmt->srect.right, pSmt->srect.bottom);
	ScrollWindow(pSmt->hWnd, 0, -count * pSmt->CharHeight, &rect, &rect);
        UpdateWindow(pSmt->hWnd);
    }
}

static void NEAR SaveCursor(PSMT pSmt, BOOL flag)
{

    if (flag) {
	pSmt->CurSaveX = pSmt->CurLineOffset;
	pSmt->CurSaveY = pSmt->CurLine;
	pSmt->SaveAttrib = pSmt->Attrib;
//	pSmt->SaveCharSet = lfnt.lfCharSet;
    }
    else {
	PositionCursor(pSmt, pSmt->CurSaveY, pSmt->CurSaveX);
	pSmt->Attrib = pSmt->SaveAttrib;
//	lfnt.lfCharSet = pSmt->SaveCharSet;
    }
}

static void NEAR SetTabStop(PSMT pSmt, LONG param)
{
    register BOOL set = LOWORD(param);
    register WORD val = HIWORD(param);

    if (set)
	pSmt->TabStops[pSmt->CurLineOffset] = 'T';
    else {
	if (val == 3)
	    memset(pSmt->TabStops, SP, MAXCOLUMNS); 
	else if (val == 0)
	    pSmt->TabStops[pSmt->CurLineOffset] = SP;
    }
}

static void NEAR ClearToEndOfLine(PSMT pSmt)
{
    RECT rect;
    register short offset = pSmt->CurLineOffset;
    register short ypos = pSmt->Pos.y;

    wordmemset(pSmt->lines[pSmt->CurLine] + offset,SP,pSmt->MaxCols - offset);

    SetRect(&rect,pSmt->Pos.x,ypos,pSmt->rect.right,ypos + pSmt->CharHeight);
    InvalidateRect(pSmt->hWnd, (LPRECT)&rect, TRUE);
    UpdateWindow(pSmt->hWnd);
}

static void NEAR ClearToLineStart(PSMT pSmt)
{

    RECT rect;

    register short offset = pSmt->CurLineOffset+ 1;
    register short width = offset * pSmt->CharWidth;

    wordmemset(pSmt->lines[pSmt->CurLine], SP, offset);

    SetRect(&rect, 0, pSmt->Pos.y, width, pSmt->Pos.y + pSmt->CharHeight);
    InvalidateRect(pSmt->hWnd, (LPRECT)&rect, TRUE);
    UpdateWindow(pSmt->hWnd);

}

static void NEAR ClearLine(PSMT pSmt)
{

    RECT rect;

    wordmemset(pSmt->lines[pSmt->CurLine], SP, pSmt->MaxCols);
    SetRect((LPRECT)&rect, 0, pSmt->Pos.y, pSmt->rect.right,
					pSmt->Pos.y + pSmt->CharHeight);
    InvalidateRect(pSmt->hWnd, (LPRECT)&rect, TRUE);
    UpdateWindow(pSmt->hWnd);

}

static void NEAR ClearToEndOfPage(PSMT pSmt)
{

    RECT rect;
    register int i;

    for (i = pSmt->CurLine; i < pSmt->MaxLines; i++)
	wordmemset(pSmt->lines[i], SP, pSmt->MaxCols);

    SetRect(&rect, 0, pSmt->Pos.y + pSmt->CharHeight,
			pSmt->rect.right, pSmt->rect.bottom);
    InvalidateRect(pSmt->hWnd, &rect, TRUE);
    UpdateWindow(pSmt->hWnd);

}

static void NEAR ClearToTopOfPage(PSMT pSmt)
{
    RECT rect;
    register int i;

    for (i = 0; i < pSmt->CurLine; i++)
	wordmemset(pSmt->lines[i], SP, pSmt->MaxCols);
   
    SetRect(&rect, 0, 0, pSmt->rect.right, pSmt->Pos.y);
    InvalidateRect(pSmt->hWnd, &rect, TRUE);
    UpdateWindow(pSmt->hWnd);

}

static void NEAR ClearScreen(PSMT pSmt)
{
    register int i;

    for (i = 0; i < pSmt->MaxLines; i++)
        wordmemset(pSmt->lines[i], SP, pSmt->MaxCols);
    InvalidateRect(pSmt->hWnd, NULL, TRUE);
    UpdateWindow(pSmt->hWnd);
}

static void NEAR AlignScreen(PSMT pSmt)
{

    register int i;

    for (i = 0; i < pSmt->MaxLines; i++)
        wordmemset(pSmt->lines[i], 'E', pSmt->MaxCols);
    InvalidateRect(pSmt->hWnd, NULL, TRUE);
    UpdateWindow(pSmt->hWnd);
    PositionCursor(pSmt, 0, 0);

}

static void NEAR FillScreen(PSMT pSmt)
{

    register int i,j;
    BYTE ch = 0;

    for (i = 0; i < pSmt->MaxLines; i++)
	for (j = 0; j < pSmt->MaxCols; j++)
	    *(pSmt->lines[i] + j) = (WORD)ch++;

    InvalidateRect(pSmt->hWnd, NULL, TRUE);
    UpdateWindow(pSmt->hWnd);
    PositionCursor(pSmt, 0, 0);

}

static void NEAR SetOriginMode(PSMT pSmt, BOOL param)
{
    if (param) {
	pSmt->TopOrgLine = pSmt->TopScroll;
	pSmt->BottomOrgLine = pSmt->BottomScroll;
    }
    else {
	pSmt->TopOrgLine = 0;
	pSmt->BottomOrgLine = (pSmt->MaxLines - 1);
    }
    pSmt->OriginMode = param;
    PositionCursor(pSmt, 0, 0);
}

static void NEAR PositionCursor(PSMT pSmt, short r, short c)
{

    register short rows = pSmt->BottomOrgLine;
    register short cols = pSmt->MaxCols;

    if (c >= cols)
	c = cols - 1 ;
    pSmt->Pos.x = c * pSmt->CharWidth;
    pSmt->CurLineOffset = c;

    r += pSmt->TopOrgLine;
    if (r > rows)
	r = rows;
    pSmt->Pos.y = r * pSmt->CharHeight;
    pSmt->CurLine = r;

    AdjustWindowToCursor(pSmt);
}

static int NEAR SmartTermDisplay(PSMT pSmt, BYTE *str, short len)
{
	
    register BYTE *ptr;
    register short ctr;
    short cols = pSmt->MaxCols;
    short cwidth = pSmt->CharWidth;
    short width = pSmt->rect.right;
    short txpos;
    short toff;
    WORD *tBuf;
    WORD attrib = pSmt->Attrib;
    WORD savebuf[MAXCOLUMNS];

    while (len > 0) {
	ptr = str;
	ctr = 0;
	toff = pSmt->CurLineOffset;
	if (pSmt->HaveToWrap && pSmt->Wrap && (toff == (cols - 1))) {
	    DoCR(pSmt);
	    DoLF(pSmt);
	    toff = pSmt->CurLineOffset;
	    pSmt->HaveToWrap = FALSE;
	}
	txpos = pSmt->Pos.x;
	tBuf = pSmt->lines[pSmt->CurLine];

	while ((len > 0) && (toff < cols)) {
	    if (pSmt->ICToggle)
	        savebuf[ctr] = *(tBuf + toff);
	    *(tBuf + toff++) = *ptr++ + attrib;
	    if ((pSmt->MarginBell) && (toff == (cols - 8)))
		MessageBeep(0);
	    ctr += 1;
	    txpos += cwidth;
	    len -= 1;
	}
	if (ctr) {
	    if (pSmt->ICToggle) {
		RECT rect;
		short ypos = pSmt->Pos.y;
		short xpos = pSmt->Pos.x;
		short tomove, tocopy;
		tomove =  cols - toff - ctr;
		tocopy = min (ctr, cols - toff);
		if (tomove > 0)
		    memmove(tBuf + toff + ctr, tBuf + toff, tomove);
		if (tocopy > 0)
		    strncpy((BYTE *)(tBuf + toff), 
					(BYTE *)savebuf, sizeof(WORD) * tocopy);
		SetRect(&rect, xpos, ypos, width, ypos + pSmt->CharHeight);
		ScrollWindow(pSmt->hWnd, txpos - xpos, 0, &rect, &rect);
		UpdateWindow(pSmt->hWnd);
	    }
	    else {
		HDC hDC = GetDC(pSmt->hWnd);
		ShowLineOfText(pSmt,hDC,str,ctr,pSmt->Pos.x,pSmt->Pos.y,
						(BYTE)HIBYTE(attrib));
		ReleaseDC(pSmt->hWnd, hDC);
	    }
	    if (toff < cols) {
	        pSmt->Pos.x = txpos;
	        pSmt->CurLineOffset = toff;
		pSmt->HaveToWrap = FALSE;
	    }
	    else {
	        pSmt->CurLineOffset = (cols - 1);
	        pSmt->Pos.x = width - cwidth;
		pSmt->HaveToWrap = TRUE;
	    }
	}
        str = ptr;
    }
    return (len);
}

static void NEAR ShowLineOfText(PSMT pSmt, HDC hDC, BYTE *str, short len,
			short xpos, short ypos, BYTE attrib)
{

    HFONT hfont, holdfont;
    register BOOL underline = attrib & VA_UNDERLINE;
    register BOOL bold = (attrib & VA_BOLD) && pSmt->Bold;
    BOOL special = (attrib & VA_SPECIAL) && pSmt->Symbol;

    if (attrib & VA_MARK) {
	SetBkColor(hDC, ~pSmt->BGColor);
	SetTextColor(hDC, ~pSmt->TextColor);
    }
    else if (attrib & VA_REVERSE) {
	SetBkColor(hDC, pSmt->TextColor);
	SetTextColor(hDC, pSmt->BGColor);
    }
    else {
        SetBkColor(hDC, pSmt->BGColor);
        SetTextColor(hDC, pSmt->TextColor);
    }
    if (bold || underline || special) {
        pSmt->lfnt.lfUnderline = (BYTE)underline;
        pSmt->lfnt.lfWeight = bold ? FW_BOLD : FW_NORMAL;
	pSmt->lfnt.lfCharSet = (BYTE)(special ? SYMBOL_CHARSET : ANSI_CHARSET);
        hfont = CreateFontIndirect(&pSmt->lfnt);
	holdfont = SelectObject(hDC, hfont);
	TextOut(hDC, xpos, ypos, (LPSTR)str, len);
	SelectObject(hDC, holdfont);
	DeleteObject(hfont);
        pSmt->lfnt.lfUnderline = 0;
        pSmt->lfnt.lfWeight = FW_NORMAL;
	pSmt->lfnt.lfCharSet = ANSI_CHARSET;
    }
    else {
        SelectObject(hDC, pSmt->hFont);
        TextOut(hDC, xpos, ypos, (LPSTR)str, len);
    }
}

static void NEAR CursorUp(PSMT pSmt, int count)
{

    register short d1 = pSmt->CurLine - pSmt->TopScroll;
    register short val;

    if (d1) {
	if (d1 > 0)
	    val = min(count, d1);
	else
	    val = min(count, pSmt->CurLine);
        pSmt->Pos.y -= val * pSmt->CharHeight;
        pSmt->CurLine -= val;
	AdjustWindowToCursor(pSmt);
    }
}
static void NEAR CursorDown(PSMT pSmt, int count)
{

    register short d1 = pSmt->BottomScroll - pSmt->CurLine;
    register short val;

    if (d1) {
	if (d1 > 0)
	    val = min(count, d1);
	else
	    val = min(count, pSmt->MaxLines - pSmt->CurLine - 1);
        pSmt->Pos.y += val * pSmt->CharHeight;
        pSmt->CurLine += val;
        AdjustWindowToCursor(pSmt);
    }
}

static void NEAR CursorRight(PSMT pSmt, int count)
{
    register short *offset = &pSmt->CurLineOffset;
    register int *xpos = &pSmt->Pos.x;
    short cols = pSmt->MaxCols - 1;
    short cwidth = pSmt->CharWidth;

    while ((*offset < cols) && (count--)) {
	*offset += 1;
	*xpos += cwidth;
    }
}

static void NEAR CursorLeft(PSMT pSmt, int count)
{
    register short *offset = &pSmt->CurLineOffset;
    register int *xpos = &pSmt->Pos.x;
    short cwidth = pSmt->CharWidth;

    while ((*offset > 0) && (count--)) {
	*offset -= 1;
	*xpos -= cwidth;
    }
}
        
static void NEAR DoCR(PSMT pSmt)
{
    pSmt->Pos.x = pSmt->CurLineOffset = 0;
}

static void NEAR DoHT(PSMT pSmt)
{

    register short *offset = &pSmt->CurLineOffset;
    register int *xpos;
    short cwidth;
    short cols = pSmt->MaxCols - 1;
    
    if (*offset >= cols)
	return;

    xpos = &pSmt->Pos.x;
    cwidth = pSmt->CharWidth;

    do {
	*offset += 1;
	*xpos += cwidth;
    } while ((pSmt->TabStops[*offset] != 'T') && (*offset < cols));
}

static void NEAR DoBS(PSMT pSmt)
{
    if (pSmt->CurLineOffset) {
	pSmt->CurLineOffset -= 1;
	pSmt->Pos.x -= pSmt->CharWidth;
    }
}

static void NEAR DoLF(PSMT pSmt)
{

    register int scrollrem;

    if (pSmt->CurLine == pSmt->BottomScroll) {
	scrollindex(pSmt, TRUE);
	wordmemset(pSmt->lines[pSmt->CurLine], SP, pSmt->MaxCols);
	if (pSmt->SmoothScroll) {
	    for (scrollrem = pSmt->CharHeight;
		 scrollrem >= pSmt->ScrollUnits;
		 scrollrem -= pSmt->ScrollUnits) {
	        ScrollWindow(pSmt->hWnd,0,-pSmt->ScrollUnits,NULL,&pSmt->srect);
	        UpdateWindow(pSmt->hWnd);
	    }
	    if (scrollrem) {
	        ScrollWindow(pSmt->hWnd,0,-scrollrem,NULL,&pSmt->srect);
	        UpdateWindow(pSmt->hWnd);
	    }
/*
	    for (i = 0; i < pSmt->CharHeight/2; i++) {
	        ScrollWindow(pSmt->hWnd,0, -2, NULL, &pSmt->srect);
	        UpdateWindow(pSmt->hWnd);
	    }
	    if (pSmt->CharHeight & 1) {
		ScrollWindow(pSmt->hWnd,0, -1, NULL, &pSmt->srect);
		UpdateWindow(pSmt->hWnd);
	    }
*/
	}
	else {
            ScrollWindow(pSmt->hWnd,0,-pSmt->CharHeight, NULL, &pSmt->srect);
            UpdateWindow(pSmt->hWnd);
	}
    }
    else if (pSmt->CurLine < (pSmt->MaxLines - 1)) {
	pSmt->Pos.y += pSmt->CharHeight;
	pSmt->CurLine += 1;
        AdjustWindowToCursor(pSmt);
    }
}

static void NEAR ReverseIndex(PSMT pSmt)
{

    register int scrollrem;

    if (pSmt->CurLine == pSmt->TopScroll) {
	scrollindex(pSmt, FALSE);
	wordmemset(pSmt->lines[pSmt->CurLine], SP, pSmt->MaxCols);
	if (pSmt->SmoothScroll) {
	    for (scrollrem = pSmt->CharHeight;
		 scrollrem >= pSmt->ScrollUnits;
		 scrollrem -= pSmt->ScrollUnits) {
	        ScrollWindow(pSmt->hWnd,0,+pSmt->ScrollUnits,NULL,&pSmt->srect);
	        UpdateWindow(pSmt->hWnd);
	    }
	    if (scrollrem) {
	        ScrollWindow(pSmt->hWnd,0,+scrollrem,NULL,&pSmt->srect);
	        UpdateWindow(pSmt->hWnd);
	    }
/*
	    for (i = 0; i < pSmt->CharHeight/2; i++) {
	        ScrollWindow(pSmt->hWnd,0, 2, (LPRECT)NULL, &pSmt->srect);
	        UpdateWindow(pSmt->hWnd);
	    }
	    if (pSmt->CharHeight & 1) {
		ScrollWindow(pSmt->hWnd, 0, 1, (LPRECT)NULL, &pSmt->srect);
		UpdateWindow(pSmt->hWnd);
	    }
*/
	}
	else {
            ScrollWindow(pSmt->hWnd,0, pSmt->CharHeight, NULL, &pSmt->srect);
            UpdateWindow(pSmt->hWnd);
	}
    }
    else if (pSmt->CurLine > 0) {
	pSmt->Pos.y -= pSmt->CharHeight;
	pSmt->CurLine -= 1;
        AdjustWindowToCursor(pSmt);
    }
}

static void NEAR TermWndPaint(PSMT pSmt, LPPAINTSTRUCT lpps)
{

    register int i,j, k;
    BYTE buf[MAXCOLUMNS];
    HDC hDC = lpps->hdc;
    RECT crect;
    BYTE attrib;
    short xpos;
    short cols = pSmt->MaxCols;
    short cheight = pSmt->CharHeight;
    short cwidth = pSmt->CharWidth;
    short count;
    short leftcol = 0;
    short leftbase = 0;

    if (!lpps->fErase) {
        SelectObject(hDC, pSmt->hbr);
	FillRect(hDC, (LPRECT)&lpps->rcPaint, pSmt->hbr);
    }
    crect.left = lpps->rcPaint.left;
    crect.right = lpps->rcPaint.right;
    crect.top = 0;
    crect.bottom = cheight;
/*
    if (crect.left > cwidth) {
	leftcol = crect.left / cwidth;
	leftbase = leftcol * cwidth;
    }
*/
    for (j = 0; j < pSmt->MaxLines; j++) {
	if (RectVisible(hDC, &crect)) {
	    k = 0;
	    xpos = leftbase;
	    attrib = (BYTE)HIBYTE(*pSmt->lines[j]);
	    for (i = cols - 1; (i >= leftcol) && (*(pSmt->lines[j] + i) == SP); i--)
		;
	    count = i + 1;
	    for (i = leftcol; i < count; i++) {
		if (attrib != (BYTE)HIBYTE(*(pSmt->lines[j] + i))) {
		    ShowLineOfText(pSmt, hDC, buf, k, xpos, crect.top, attrib);
		    xpos = cwidth * i;
		    k = 0;
		    attrib = (BYTE)HIBYTE(*(pSmt->lines[j] + i));
		}
		buf[k++] = (BYTE)LOBYTE(*(pSmt->lines[j] + i));
	    }
	    ShowLineOfText(pSmt, hDC, buf, k, xpos, crect.top, attrib);
	}
	crect.top += cheight;
	crect.bottom += cheight;
    }
}

static void NEAR scrollindex(PSMT pSmt, BOOL direction)
{
    register WORD *temp;
    int bottom;
    register int count = pSmt->BottomScroll - pSmt->TopScroll;

    if (direction) {
	if (count == pSmt->MaxLines - 1) {
	    count = pSmt->MaxTextLines - 1;
	    temp = pSmt->lines[0];
	    bottom = count;
	    if (pSmt->scrollback < pSmt->MaxScrollBack)
		pSmt->scrollback += 1;
	    if (pSmt->scrollforward > 0)
		pSmt->scrollforward -= 1;
	}
	else {
	    temp = pSmt->lines[pSmt->TopScroll];
	    bottom = pSmt->BottomScroll;
	}
	memmove(&pSmt->lines[pSmt->TopScroll],
		&pSmt->lines[pSmt->TopScroll + 1],
		count * sizeof (WORD *));
	pSmt->lines[bottom] = temp;
    }
    else {
	temp = pSmt->lines[pSmt->BottomScroll];
	memmove(&pSmt->lines[pSmt->TopScroll + 1],
		&pSmt->lines[pSmt->TopScroll],
		count * sizeof (WORD *));
	pSmt->lines[pSmt->TopScroll] = temp;
    }
}

static void NEAR ComputeVisibleWindow(PSMT pSmt, short right, short bottom)
{

    POINT Pt;

    Pt.x = right;
    Pt.y = bottom;

    ClientToScreen(pSmt->hMain, &Pt);
    ScreenToClient(pSmt->hStatic,&Pt);

    pSmt->vrect.right = min((Pt.x /pSmt->CharWidth) * pSmt->CharWidth,
				 pSmt->rect.right);

    if (pSmt->vrect.right <= 0)
	pSmt->vrect.right = pSmt->CharWidth;

    pSmt->vrect.bottom = min((Pt.y / pSmt->CharHeight) * pSmt->CharHeight, 
							pSmt->rect.bottom);
    if (pSmt->vrect.bottom <= 0)
	pSmt->vrect.bottom = pSmt->CharHeight;

}

static void NEAR AdjustWindowToCursor(PSMT pSmt)
{

    register short Y2, Y;
    POINT Pt;
    short ypos;
    HWND hWnd = pSmt->hWnd;
    
    Y2 = pSmt->vrect.bottom - pSmt->CharHeight;

    Pt.x = pSmt->Pos.x;
    Pt.y = ypos = pSmt->Pos.y;

    ClientToScreen(hWnd, &Pt);
    ScreenToClient(pSmt->hStatic, &Pt);

    Y = Pt.y;

    if (Y > Y2) {
	pSmt->rect.top = Y2 - ypos;
	MoveWindow(hWnd,pSmt->rect.left, pSmt->rect.top,
				pSmt->rect.right,pSmt->rect.bottom, TRUE);
    }
    else if (Y < 0) {
	pSmt->rect.top = -ypos;
	MoveWindow(hWnd,pSmt->rect.left, pSmt->rect.top,
				pSmt->rect.right, pSmt->rect.bottom, TRUE);
    }
}

static void NEAR wordmemset(WORD *dest, WORD val, int count)
{
/*
    register WORD *wptr = dest;
    register int i;

    for (i = 0; i < count; i++)
        *wptr++ = val;
*/

_asm {
	pushf			; save direction flag
	push	di		; save pointer
	cld

	mov	ax,ds		; set up es
	mov	es,ax
	mov	di,dest		; set destination pointer

	mov	ax,val		; value to set
	mov	cx,count	; number of words to store
	rep	stosw		; do it
	
	pop	di		; restore registers which must be saved
	popf
      }
}

short FAR PASCAL GetFontInfo(LPLOGFONT lf, LPTEXTMETRIC tm, 
			     short type, LPSTR lpData)
{

    SMT FAR *pSmt;
    LPSTR dest;
    LPSTR src;
    register int i;
    int width, height, weight;
    BYTE charset;
    static BOOL copied = FALSE;

    if ((lf->lfPitchAndFamily & 3) != FIXED_PITCH)
	return TRUE;

    pSmt = (SMT FAR *)lpData;
    dest = (LPSTR)&pSmt->lfnt;
    src = (LPSTR)lf;

    width = lf->lfWidth;
    height = lf->lfHeight;
    weight = lf->lfWeight;
    charset = lf->lfCharSet;

    if ((width == pSmt->NFontWidth) && (height == pSmt->NFontHeight)) {
	if (weight == FW_BOLD)
	    pSmt->NBold = TRUE;
	if (charset == SYMBOL_CHARSET)
	    pSmt->NSymbol = TRUE;
    }
    if ((width == pSmt->SFontWidth) && (height == pSmt->SFontHeight)) {
	if (weight == FW_BOLD)
	    pSmt->SBold = TRUE;
	if (charset == SYMBOL_CHARSET)
	    pSmt->SSymbol = TRUE;
    }

    if (!copied) {
        for (i = 0; i < sizeof(LOGFONT); i++)
            *(dest + i) = *(src + i);
	copied = TRUE;
    }
    return TRUE;

}

HFONT FAR SetFontData(PSMT pSmt)
{

    TEXTMETRIC TM;
    HDC hDC;
    HFONT hFont, hOldFont;
    FARPROC fp;
    HWND hWnd = pSmt->hMain;

    hDC = GetDC(hWnd);
    fp = MakeProcInstance((FARPROC)GetFontInfo,
			   GetWindowWord(hWnd,GWW_HINSTANCE));
    EnumFonts(hDC, pSmt->lfnt.lfFaceName, fp, (LPSTR)pSmt);
    FreeProcInstance(fp);
    if (pSmt->MaxCols == MAXCOLUMNS) {
        pSmt->lfnt.lfWidth = pSmt->SFontWidth;
        pSmt->lfnt.lfHeight = pSmt->SFontHeight;
	pSmt->Bold = pSmt->SBold;
    } else {
        pSmt->lfnt.lfWidth = pSmt->NFontWidth;
        pSmt->lfnt.lfHeight = pSmt->NFontHeight;
	pSmt->Bold = pSmt->NBold;
    }
    pSmt->lfnt.lfEscapement = 0;
    pSmt->lfnt.lfOrientation = 0;
    pSmt->lfnt.lfWeight = FW_NORMAL;
    pSmt->lfnt.lfItalic = 0;
    pSmt->lfnt.lfUnderline = 0;
    pSmt->lfnt.lfStrikeOut = 0;
    pSmt->lfnt.lfCharSet = ANSI_CHARSET;
    hFont = CreateFontIndirect(&pSmt->lfnt);
    hOldFont = SelectObject(hDC, hFont);
    GetTextMetrics(hDC, &TM);
    pSmt->CharHeight = TM.tmHeight + TM.tmExternalLeading;
    pSmt->CharWidth = TM.tmAveCharWidth;
    SelectObject(hDC, hOldFont);
    ReleaseDC(pSmt->hMain, hDC);

    return (hFont);

}
