Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

679 lines
15 KiB

/* 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;
}