|
|
/* File: D:\WACKER\tdll\backscrl.c (Created: 10-Dec-1993)
* * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 9 $ * $Date: 8/27/01 9:00a $ */
#include <windows.h>
#pragma hdrstop
#include <stdlib.h>
#include <limits.h>
#include "stdtyp.h"
#include "tdll.h"
#include "mc.h"
#include "assert.h"
#include "session.h"
#include "session.hh"
#include <emu\emu.h>
#include <emu\emu.hh>
#include "update.h"
#include "backscrl.h"
#include "backscrl.hh"
#include "sess_ids.h"
#include "htchar.h"
#include "term.h"
#include "sf.h"
#include <term\res.h>
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlCreate * * DESCRIPTION: * Creates a server (now wudge) backsroll handle include the backscroll * region itself. * * ARGUMENTS: * Size of the backscoll region in bytes. * * RETURNS: * Handle to a backscroll structure on success, else (HBACKSCRL)0. * */ HBACKSCRL backscrlCreate(const HSESSION hSession, const int iBytes) { int i; HHBACKSCRL hBk;
assert(hSession);
hBk = (HHBACKSCRL)malloc(sizeof(struct stBackscrl));
if (hBk == 0) { assert(FALSE); return 0; }
memset(hBk, 0, sizeof(struct stBackscrl));
hBk->hSession = hSession; hBk->iPages = (iBytes / BACKSCRL_PAGESIZE) + 1;
if (hBk->iPages > BACKSCRL_MAXPAGES) { assert(FALSE); free(hBk); hBk = NULL; return 0; }
hBk->hBkPages = (HBKPAGE *)malloc((size_t)hBk->iPages * sizeof(HBKPAGE));
if (hBk->hBkPages == 0) { assert(FALSE); free(hBk); hBk = NULL; return (HBACKSCRL)0; }
for (i = 0 ; i < hBk->iPages ; ++i) { hBk->hBkPages[i] = (HBKPAGE)malloc(sizeof(struct stBackscrlPage));
if (hBk->hBkPages[i] == (HBKPAGE)0) { assert(FALSE); goto ERROROUT; }
hBk->hBkPages[i]->pachPage = (ECHAR *)malloc(BACKSCRL_PAGESIZE * sizeof(ECHAR));
if (hBk->hBkPages[i]->pachPage == 0) { assert(FALSE); goto ERROROUT; }
ECHAR_Fill(hBk->hBkPages[i]->pachPage, EMU_BLANK_CHAR, BACKSCRL_PAGESIZE); hBk->hBkPages[i]->iLines = 0; }
hBk->iCurrPage = 0; hBk->iOffset = 0; hBk->iLines = 0;
// Set this to some default...
//
hBk->iUserLines = hBk->iUserLinesSave = BKSCRL_USERLINES_DEFAULT_MAX;
hBk->hBkPages[hBk->iCurrPage]->iLines = 0;
return (HBACKSCRL)hBk;
// Fanstastic error recovery.
ERROROUT:
while (--i > 0) { free(hBk->hBkPages[i]->pachPage); hBk->hBkPages[i]->pachPage = NULL; free(hBk->hBkPages[i]); hBk->hBkPages[i] = NULL; }
free(hBk->hBkPages); hBk->hBkPages = NULL; free(hBk); hBk = NULL; return (HBACKSCRL)0; // caller does error message
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlDestroy * * DESCRIPTION: * Routine to free memory associated with the given backscoll handle. * * ARGUMENTS: * HBACKSCRL hBackscrl - handle to free. * * RETURNS: * nothing. * */ VOID backscrlDestroy(const HBACKSCRL hBackscrl) { int i; const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl;
if (hBk == 0) { assert(0); return; }
if (hBk->hBkPages) { for (i = 0 ; i < hBk->iPages ; ++i) { if (hBk->hBkPages[i]->pachPage) { free(hBk->hBkPages[i]->pachPage); hBk->hBkPages[i]->pachPage = NULL; }
free(hBk->hBkPages[i]); hBk->hBkPages[i] = NULL; }
free(hBk->hBkPages); hBk->hBkPages = NULL; }
free(hBk); return; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlAdd * * DESCRIPTION: * Adds a new line to the backscoll handle. The affect is to scroll the * preceding lines up by one and to add the given string to the bottom * of the backscroll region. * * ARGUMENTS: * HBACKSCRL hBackscrl - as usual * LPTSTR pachBuf - string to add * int usLen - length of the string. * * RETURNS: * TRUE always. * */ BOOL backscrlAdd(const HBACKSCRL hBackscrl, const ECHAR *pachBuf, const int iLen ) { register int i; ECHAR *pachBackscrl; const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl;
if (hBk == 0) { assert(0); return FALSE; }
if (hBk->iUserLines == 0) return TRUE;
// The following test has been removed because the emualtors no
// longer use a '\0' to delimit the end of a line. 5/16/94 --jcm
// Never let '\0's into the backscroll buffer! Avoid this like the
// plague since they display as wierd characters depending on the
// font selected on the CLIENT side. The wierd part is you can't
// always depend on the emulators putting a '\0' in the the buffer
// so we need to check for trailing space as well.
for (i = 0 ; i < iLen ; ++i) { if (pachBuf[i] == (ECHAR)0) break; }
// remove trailing whitespace.
while (i) { if (pachBuf[i - 1] != ETEXT(' ')) break;
i -= 1; }
DbgOutStr("%d-", i, 0, 0, 0, 0);
// check to see if there is room on the current page.
if (hBk->iOffset >= BACKSCRL_PAGESIZE || ((int)BACKSCRL_PAGESIZE - hBk->iOffset) <= i) { // pad rest of page with blanks so we know that this part of
// the buffer is empty.
if ((pachBackscrl = hBk->hBkPages[hBk->iCurrPage]->pachPage) == 0) { assert(0); return FALSE; }
ECHAR_Fill(pachBackscrl+hBk->iOffset, EMU_BLANK_CHAR, (size_t)(BACKSCRL_PAGESIZE - hBk->iOffset));
hBk->iCurrPage += 1;
if (hBk->iCurrPage >= hBk->iPages) hBk->iCurrPage = 0;
hBk->iOffset = 0;
// If we have wrapped, subtract the number of lines previously in
// this page from the total line count. Since the line count is
// intialized to 0 (see backscrlCreate()) I can always subract this
// amount without checking for wrapping since it will only be
// non-zero if we have wrapped.
hBk->iLines -= hBk->hBkPages[hBk->iCurrPage]->iLines; hBk->hBkPages[hBk->iCurrPage]->iLines = 0; }
// Assign a pointer for speed and clarity
if ((pachBackscrl = hBk->hBkPages[hBk->iCurrPage]->pachPage) == 0) { assert(0); return FALSE; }
// JYF 26-Mar-1999 limit the size so we don't overrun
// the buffer.
if (i) { MemCopy (pachBackscrl + hBk->iOffset, pachBuf, (size_t)min(BACKSCRL_PAGESIZE - hBk->iOffset, i) * sizeof(ECHAR)); }
hBk->iOffset += min(BACKSCRL_PAGESIZE - hBk->iOffset - 1, i);
pachBackscrl[hBk->iOffset++] = ETEXT('\n');
// Here's an interesting problem. We really can't reference more than
// a signed-integer's worth of lines, but we may have megabytes of
// backscroll memory. The answer is simple in this case. Never allow
// the line count to exceed the signed int max. This has the affect
// of spilling off the top lines in the buffer. - mrw
hBk->iLines = min(hBk->iLines+1, INT_MAX); hBk->hBkPages[hBk->iCurrPage]->iLines += 1; hBk->iChanged = TRUE; updateBackscroll(sessQueryUpdateHdl(hBk->hSession), 1); return TRUE; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlGetBkLines * * DESCRIPTION: * Retrieves specifed lines from the backscoll. This function is * complicated by the fact the backscoll memory is paged. A request * might cross one or more page boundaries. Thus only a portion of * the request may be satisfied. The client knows this and makes new * requests based on what it got from the server. * * ARGUMENTS: * hBackscrl - the usual * yBeg - begining line in backscroll to get. * sWant - number of lines requested. * psGot - number of lines retrived. * lpststrTxt - handle to backscrl memory page retrived. * pwOffset - offset into retrieved page (in TCHAR units). * * RETURNS: * BOOL * */ BOOL backscrlGetBkLines(const HBACKSCRL hBackscrl, const int yBeg, const int sWant, int *psGot, ECHAR **lptstrTxt, int *pwOffset ) { register int i, j, k; ECHAR *pachText; const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl;
assert(sWant > 0);
// Check to see if we are requesting beyond the end of the
// backscroll buffer.
if (abs(yBeg) > hBk->iLines) return FALSE;
k = hBk->iCurrPage; j = 0; i = 0;
// Find the backscoll page that has the requested text
//
for (;;) { if ((j -= hBk->hBkPages[k]->iLines) <= yBeg) break;
k = (hBk->iPages + k - 1) % hBk->iPages;
if (++i >= hBk->iPages) return FALSE; }
// Found the page.
//
*lptstrTxt = hBk->hBkPages[k]->pachPage;
// Now find offset into page where first line of requested text begins
//
for (pachText = hBk->hBkPages[k]->pachPage ; j < yBeg ; ++j) { while (*pachText != ETEXT('\n')) { pachText += 1; }
pachText += 1; }
*pwOffset = (DWORD)(pachText - hBk->hBkPages[k]->pachPage);
// Found offset. Now grab what we can and return it.
//
for (i = 1 ; i <= sWant ; ++i) { while ((pachText - hBk->hBkPages[k]->pachPage) < BACKSCRL_PAGESIZE && *pachText != ETEXT('\n')) { pachText += 1; }
if ((pachText - hBk->hBkPages[k]->pachPage) >= BACKSCRL_PAGESIZE) break;
*psGot = i; pachText += 1; // blow past newline
}
return TRUE; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlGetNumLines * * DESCRIPTION: * Returns the number of lines in the backscrl which is zero if the * backscroll is off, and the maximum is always the user set value. * * ARGUMENTS: * HBACKSCRL hBackscrl - external backscrl handle * * RETURNS: * Returns the uLines member. */ int backscrlGetNumLines(const HBACKSCRL hBackscrl) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; assert(hBk); return (hBk->fShowBackscrl) ? min(hBk->iUserLines, hBk->iLines) : 0; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlUSetNumLines * * DESCRIPTION: * Returns the iUserLines member. * * ARGUMENTS: * HBACKSCRL hBackscrl - external backscrl handle * * RETURNS: * void */ int backscrlSetUNumLines(const HBACKSCRL hBackscrl, const int iUserLines) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl;
if (hBk == 0) { assert(0); return -1; }
if (iUserLines != hBk->iUserLines) { backscrlChanged(hBackscrl); hBk->iUserLines = iUserLines;
// If we're setting the number of lines to zero, we're essentially
// disabling the backscroll. Flushing clears the screen as well.
//
if (iUserLines == 0) { HHSESSION hhSession = (HHSESSION)hBk->hSession; // REV: 07/26/2001 posted message to clear the backscroll
// otherwise a deadlock could occur as we may not be thread 0.
// backscrlFlush(hBackscrl);
PostMessage(hhSession->hwndSess, WM_COMMAND, IDM_CLEAR_BACKSCROLL, (LPARAM)0); }
}
return 0; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlGetUNumLines * * DESCRIPTION: * Returns the iUserLines member. * * ARGUMENTS: * HBACKSCRL hBackscrl - external backscrl handle * * RETURNS: * Returns the iUserLines member. */ int backscrlGetUNumLines(const HBACKSCRL hBackscrl) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; return hBk->iUserLines; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlRead * * DESCRIPTION: * Read the number of backscrol lines to keep as entered by the user. * NOTE: This should be put in the backscrlInitializeHdl() when this function * gets written. * * ARGUMENTS: * HBACKSCRL hBackscrl - external backscrl handle * * RETURNS: */ void backscrlRead(const HBACKSCRL hBackscrl) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; unsigned long ulSize;
ulSize = sizeof(hBk->iUserLines); hBk->iUserLines = BKSCRL_USERLINES_DEFAULT_MAX; sfGetSessionItem(sessQuerySysFileHdl(hBk->hSession), SFID_BKSC_ULINES, &ulSize, &hBk->iUserLines); hBk->iUserLinesSave = hBk->iUserLines; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlSave * * DESCRIPTION: * * ARGUMENTS: * HBACKSCRL hBackscrl - external backscrl handle * * RETURNS: */ void backscrlSave(const HBACKSCRL hBackscrl) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; unsigned long ulSize;
if (hBk->iUserLines != hBk->iUserLinesSave) { ulSize = sizeof(int); sfPutSessionItem(sessQuerySysFileHdl(hBk->hSession), SFID_BKSC_ULINES, ulSize, &(hBk->iUserLines)); } }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlFlush * * DESCRIPTION: * Empties the backscroll buffer and notifies the terminal so it can * update it's display. * * Note: Because this function calls RefreshTermWindow() it should only * be called from the main thread. - mrw * * ARGUMENTS: * hBackscrl - public backscroll handle * * RETURNS: * void * */ void backscrlFlush(const HBACKSCRL hBackscrl) { int i; const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; ECHAR aechBuf[10];
assert(hBk);
/* --- Shouldn't need this unless this is called while on line --- */
emuLock(sessQueryEmuHdl(hBk->hSession));
/* --- Force the update records to have something in them --- */
CnvrtMBCStoECHAR(aechBuf, sizeof(aechBuf), TEXT(" "), StrCharGetByteCount(TEXT(" "))); backscrlAdd(hBackscrl, aechBuf, 1);
/* --- Empty all pages --- */
for (i = 0 ; i < hBk->iPages ; ++i) hBk->hBkPages[i]->iLines = 0;
hBk->iLines = 0; hBk->iOffset = 0; //mrw:6/19/95
emuUnlock(sessQueryEmuHdl(hBk->hSession));
/* --- Let the terminal update now --- */
NotifyClient(hBk->hSession, EVENT_TERM_UPDATE, 0); RefreshTermWindow(sessQueryHwndTerminal(hBk->hSession)); return; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlChanged * * DESCRIPTION: * Returns iChanged member which is set whenever anything is added * to the backscroll buffer. It can be cleared by calling * backscrlResetChangedFlag(). * * ARGUMENTS: * hBackscrl - public backscroll handle * * RETURNS: * BOOL * */ BOOL backscrlChanged(const HBACKSCRL hBackscrl) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; assert(hBk); return hBk->iChanged; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlResetChangedFlag * * DESCRIPTION: * Resets the iChanged member to 0. Subsequent calls to backscrlAdd() * will set the flag to 1. * * ARGUMENTS: * hBackscrl - public backscrl handle * * RETURNS: * void * */ void backscrlResetChangedFlag(const HBACKSCRL hBackscrl) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl; assert(hBk); hBk->iChanged = 0; return; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION: * backscrlSetShowFlag * * DESCRIPTION: * The show flag controls whether or not the session will show/display * an antive backscrl. * * ARGUMENTS: * hBackscrl - public backscrl handle. * fFlag - TRUE=show, FALSE=hide * * RETURNS: * void * */ void backscrlSetShowFlag(const HBACKSCRL hBackscrl, const int fFlag) { const HHBACKSCRL hBk = (HHBACKSCRL)hBackscrl;
assert(hBk); hBk->fShowBackscrl = fFlag; return; }
|