Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

920 lines
18 KiB

#include "cmd.h"
//
// Externals for message buffer translation
//
extern TCHAR CrLf[];
extern unsigned msglen;
extern CPINFO CurrentCPInfo;
void FreeStr( IN PBYTE pbFree );
VOID SetColRow( PSCREEN );
ULONG GetNumRows( PSCREEN, PTCHAR );
HANDLE NtDllHandle = NULL;
TCHAR chLF = NLN;
STATUS
OpenScreen(
OUT PSCREEN *pscreen
)
/*++
Routine Description:
Allocates and initializes a data structure for screen I/O buffering.
Arguments:
crow - max rows on screen
ccol - max column on screen
ccolTab - spaces to insert for each tab call. This does not
expand tabs in the character stream but is used with the
WriteTab call.
cbMaxBuff - Max. size of a line on screen
Return Value:
pscreen - pointer to screen buffer, used in later calls.
Return: SUCCESS - allocated and inited buffer.
If failure to allocate an abort is executed and return to outer
level of interpreter is executed.
--*/
{
PSCREEN pscr;
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
ULONG cbMaxBuff;
pscr = (PSCREEN)gmkstr(sizeof(SCREEN));
pscr->hndScreen = NULL;
if (FileIsDevice(STDOUT)) {
pscr->hndScreen = CRTTONT(STDOUT);
if (!GetConsoleScreenBufferInfo(pscr->hndScreen,&ConInfo)) {
// must be a device but not console (maybe NUL)
pscr->hndScreen = NULL;
}
}
if (GetConsoleScreenBufferInfo( pscr->hndScreen, &ConInfo)) {
cbMaxBuff = (ConInfo.dwSize.X + _tcslen(CrLf)) < MAXCBMSGBUFFER ? MAXCBMSGBUFFER : (ConInfo.dwSize.X + _tcslen(CrLf));
} else {
cbMaxBuff = MAXCBMSGBUFFER + _tcslen(CrLf);
}
//
// allocate enough to hold a buffer plus line termination.
//
pscr->pbBuffer = (PTCHAR)gmkstr(cbMaxBuff*sizeof(TCHAR));
pscr->cbMaxBuffer = cbMaxBuff;
pscr->ccolTab = 0;
pscr->crow = pscr->ccol = 0;
pscr->crowPause = 0;
SetColRow(pscr);
*pscreen = pscr;
return( SUCCESS );
}
STATUS
WriteString(
IN PSCREEN pscr,
IN PTCHAR pszString
)
/*++
Routine Description:
Write a zero terminated string to pscr buffer
Arguments:
pscr - buffer into which to write.
pszString - String to copy
Return Value:
Return: SUCCESS - enough spaced existed in buffer for line.
FAILURE
--*/
{
return( WriteFmtString(pscr, TEXT("%s"), (PVOID)pszString ) );
}
STATUS
WriteMsgString(
IN PSCREEN pscr,
IN ULONG MsgNum,
IN ULONG NumOfArgs,
...
)
/*++
Routine Description:
Retrieve a message number and format with supplied arguments.
Arguments:
pscr - buffer into which to write.
MsgNum - message number to retrieve
NumOfArgs - no. of arguments suppling data.
... - pointers to zero terminated strings as data.
Return Value:
Return: SUCCESS
FAILURE - could not find any message including msg not found
message.
--*/
{
TCHAR szMsg[MAXCBMSGBUFFER];
PTCHAR pszMsg;
ULONG cbMsg, cbMsgBuf;
CHAR numbuf[ 32 ];
#ifdef UNICODE
TCHAR wnumbuf[ 32 ];
#endif
PTCHAR Inserts[ 2 ];
STATUS rc;
va_list arglist;
va_start(arglist, NumOfArgs);
if (pscr->cbMaxBuffer > MAXCBMSGBUFFER) {
pszMsg = (PTCHAR)gmkstr(pscr->cbMaxBuffer*sizeof(TCHAR));
cbMsgBuf = pscr->cbMaxBuffer;
} else {
pszMsg = szMsg;
cbMsgBuf = MAXCBMSGBUFFER;
}
cbMsg = FormatMessage(MsgNum >= MSG_RESPONSE_DATA ?
FORMAT_MESSAGE_FROM_HMODULE :
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
MsgNum,
0,
pszMsg,
cbMsgBuf,
&arglist
);
if (cbMsg == 0) {
if (NtDllHandle == NULL) {
NtDllHandle = GetModuleHandle( TEXT("NTDLL") );
}
cbMsg = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
(LPVOID)NtDllHandle,
MsgNum,
0,
pszMsg,
cbMsgBuf,
&arglist
);
}
va_end(arglist);
if (cbMsg == 0) {
_ultoa( MsgNum, numbuf, 16 );
#ifdef UNICODE
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, numbuf, -1, wnumbuf, 32);
Inserts[ 0 ]= wnumbuf;
#else
Inserts[ 0 ]= numbuf;
#endif
Inserts[ 1 ]= (MsgNum >= MSG_RESPONSE_DATA ? TEXT("Application") : TEXT("System"));
cbMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
ERROR_MR_MID_NOT_FOUND,
0,
pszMsg,
cbMsgBuf,
(va_list *)Inserts
);
}
if (cbMsg) {
pszMsg[cbMsg] = NULLC;
rc = WriteString(pscr, pszMsg);
//
// Flush out buffer if there is an eol. If not then we
// are printing part of a larger message
//
if (GetNumRows(pscr, pscr->pbBuffer) ) {
WriteFlush(pscr);
}
if (pszMsg != szMsg) {
FreeStr((PBYTE)pszMsg);
}
return( SUCCESS );
}
return( FAILURE );
}
STATUS
WriteFmtString(
IN PSCREEN pscr,
IN PTCHAR pszFmt,
IN PVOID pszString
)
/*++
Routine Description:
Write a zero terminated string to pscr
Note:
Do not use Msgs with this call. Use only internal Fmt strings
Use WriteMsgString for all system messages. It does not check for
CrLf at end of string to keep row count but WriteMsgString does
Arguments:
pscr - buffer into which to write.
pszFmt - format to apply.
pszString - String to copy
Return Value:
Return: SUCCESS
FAILURE
--*/
{
ULONG cbString;
TCHAR szString[MAXCBLINEBUFFER];
//
// Assume that the format overhead is small so this is a fair estimate
// of the target size.
//
cbString = _sntprintf(szString, MAXCBLINEBUFFER, pszFmt, pszString);
//
// If string can not fit on line then flush out the buffer and reset
// to beginning of line.
//
//
// BUGBUG this must be changed to separate the size of the
// buffer and the width of the screen. Right now a max path
// string will not get printed since it is bigger then the screen.
// In these cases we should have a single line with wrapping.
// We should also move to asking the console for our current
// line position instead of trying to track it. Each time we
// actually write to the scrren query for row position.
// We should check for file redirections etc.
//if ((pscr->ccol + cbString) >= pscr->ccolMax && !bFailIfTooLong) {
// WriteEol( pscr );
//}
//
// Check that string can fit in buffer
//
if ((pscr->ccol + cbString) < pscr->cbMaxBuffer) {
mystrcat(pscr->pbBuffer, szString);
pscr->ccol += cbString;
return( SUCCESS );
} else {
//
// String will not fit
//
return( FAILURE );
}
}
STATUS
WriteEol(
IN PSCREEN pscr
)
/*++
Routine Description:
Flush current buffer to screen and write a <cr>
Arguments:
pscr - buffer to write to console.
Return Value:
Return: SUCCESS
FAILURE
--*/
{
BOOL CrLfWritten=FALSE;
ULONG cbWritten;
//
// Check if have to wait for user to hit a key before printing rest of
// line.
CheckPause( pscr );
if ((pscr->ccol + mystrlen(CrLf)) >= pscr->cbMaxBuffer) {
pscr->ccol += _stprintf(pscr->pbBuffer + pscr->ccol, TEXT("%s"), CrLf);
CrLfWritten=TRUE;
}
//
// If we do not write all that we wanted then there must have been some error
//
if (FileIsConsole(STDOUT)) {
if (!WriteConsole(CRTTONT(STDOUT), pscr->pbBuffer, pscr->ccol, &cbWritten, NULL))
goto err_out_eol;
if (cbWritten != pscr->ccol)
goto err_out_eol;
}
else if (MyWriteFile(STDOUT,
pscr->pbBuffer, pscr->ccol*sizeof(TCHAR),
(LPDWORD)&cbWritten) == 0 ||
cbWritten != pscr->ccol*sizeof(TCHAR)) {
err_out_eol:
if (FileIsDevice(STDOUT)) {
//
// If writing to a device then it must have been write fault
// against the device.
//
#if DBG
fprintf(stderr, "WriteFlush - WriteConsole error %d, tried to write %d, did %d\n", GetLastError(), pscr->ccol, cbWritten);
#endif
PutStdErr(ERROR_WRITE_FAULT, NOARGS) ;
} else if (!FileIsPipe(STDOUT)) {
//
// If not a device (file) but not a pipe then the disk is
// considered full.
//
#if DBG
fprintf(stderr, "WriteFlush - WriteFile error %d, tried to write %d, did %d\n", GetLastError(), pscr->ccol*sizeof(TCHAR), cbWritten);
#endif
PutStdErr(ERROR_DISK_FULL, NOARGS) ;
}
//
// if it was was a pipe do not continue to print out to pipe since it
// has probably gone away. This is pretty serious so blow us out
// to the outer loop.
//
// We do not print an error message since this could be normal
// termination of the other end of the pipe. If it was command that
// blew away we would have had an error message already
//
Abort();
}
if (!CrLfWritten) {
if (FileIsConsole(STDOUT))
WriteConsole(CRTTONT(STDOUT), CrLf, mystrlen(CrLf), &cbWritten, NULL);
else
MyWriteFile(STDOUT, CrLf, mystrlen(CrLf)*sizeof(TCHAR),
(LPDWORD)&cbWritten);
}
//
// remember that crow is the number of rows printed
// since the last screen full. Not the current row position
//
//
// Computed the number of lines printed.
//
pscr->crow += GetNumRows( pscr, pscr->pbBuffer );
if (!CrLfWritten) {
pscr->crow += 1;
}
//
// Check if have to wait for user to hit a key before printing rest of
// line.
CheckPause( pscr );
if (pscr->crow > pscr->crowMax) {
pscr->crow = 0;
}
pscr->pbBuffer[0] = 0;
pscr->ccol = 0;
DEBUG((ICGRP, CONLVL, "Console: end row = %d\n", pscr->crow)) ;
return(SUCCESS);
}
VOID
CheckPause(
IN PSCREEN pscr
)
/*++
Routine Description:
Pause. Execution of screen is full, waiting for the user to type a key.
Arguments:
pscr - buffer holding row information
Return Value:
none
--*/
{
DEBUG((ICGRP, CONLVL, "CheckPause: Pause Count %d, Row Count %d",
pscr->crowPause, pscr->crow)) ;
if (pscr->crowPause) {
if (pscr->crow >= pscr->crowPause) {
ePause((struct cmdnode *)0);
pscr->crow = 0;
SetColRow( pscr );
SetPause(pscr, pscr->crowMax - 1);
}
}
}
VOID
SetTab(
IN PSCREEN pscr,
IN ULONG ccol
)
/*++
Routine Description:
Set the current tab spacing.
Arguments:
pscr - screen info.
ccol - tab spacing
Return Value:
none
--*/
{
pscr->ccolTabMax = pscr->ccolMax;
if (ccol) {
//
// divide the screen up into tab fields, then do
// not allow tabbing into past last field. This
// insures that all name of ccol size can fit on
// screen
//
pscr->ccolTabMax = (pscr->ccolMax / ccol) * ccol;
}
pscr->ccolTab = ccol;
}
STATUS
WriteTab(
IN PSCREEN pscr
)
/*++
Routine Description:
Fills the buffer with spaces up to the next tab position
Arguments:
pscr - screen info.
ccol - tab spacing
Return Value:
none
--*/
{
ULONG ccolBlanks;
#ifdef JAPAN
ULONG ccolActual;
#endif /* not Japan */
//
// Check that we have a non-zero tab spacing.
//
if ( pscr->ccolTab ) {
//
// Compute the number of spaces we will have to write.
//
#ifdef JAPAN
ccolActual = SizeOfHalfWidthString(pscr->pbBuffer);
ccolBlanks = pscr->ccolTab - (ccolActual % pscr->ccolTab);
#else /* not Japan */
ccolBlanks = pscr->ccolTab - (pscr->ccol % pscr->ccolTab);
#endif /* Japan */
//
// check if the tab will fit on the screen
//
#ifdef JAPAN
if ((ccolBlanks + ccolActual) < pscr->ccolTabMax) {
#else /* not Japan */
if ((ccolBlanks + pscr->ccol) < pscr->ccolTabMax) {
#endif /* Japan */
mytcsnset(pscr->pbBuffer + pscr->ccol, SPACE, ccolBlanks);
pscr->ccol += ccolBlanks;
pscr->pbBuffer[pscr->ccol] = NULLC;
return( SUCCESS );
} else {
//
// It could not so outpt <cr> and move to
// next line
//
return(WriteEol(pscr));
}
}
return( SUCCESS );
}
VOID
FillToCol (
IN PSCREEN pscr,
IN ULONG ccol
)
/*++
Routine Description:
Fills the buffer with spaces up ccol
Arguments:
pscr - screen info.
ccol - column to fill to.
Return Value:
none
--*/
{
#ifdef JAPAN
ULONG ccolActual = SizeOfHalfWidthString(pscr->pbBuffer);
ULONG cb;
#endif /* Japan */
#ifdef JAPAN
cb = _tcslen(pscr->pbBuffer);
if (ccolActual >= ccol) {
ccol = cb - (ccolActual - ccol);
#else /* not Japan */
if (pscr->ccol >= ccol) {
#endif /* Japan */
//
// If we are there or past it then truncate current line
// and return.
//
pscr->pbBuffer[ccol] = NULLC;
pscr->ccol = ccol;
return;
}
//
// Only fill to column width of buffer
//
#ifdef JAPAN
mytcsnset(pscr->pbBuffer + cb, SPACE, ccol - ccolActual);
ccol = cb + ccol - ccolActual;
#else /* not Japan */
mytcsnset(pscr->pbBuffer + pscr->ccol, SPACE, ccol - pscr->ccol);
#endif /* Japan */
pscr->ccol = ccol;
pscr->pbBuffer[ccol] = NULLC;
}
STATUS
WriteFlush(
IN PSCREEN pscr
)
/*++
Routine Description:
Write what ever is currently on the buffer to the screen. No EOF is
printed.
Arguments:
pscr - screen info.
Return Value:
Will abort on write error.
SUCCESS
--*/
{
DWORD cb;
//
// If there is something in the buffer flush it out
//
if (pscr->ccol) {
if (FileIsConsole(STDOUT)) {
ULONG cbWritten;
if (!WriteConsole(CRTTONT(STDOUT), pscr->pbBuffer, pscr->ccol, &cbWritten, NULL))
goto err_out_flush;
if (cbWritten != pscr->ccol)
goto err_out_flush;
}
else if (MyWriteFile(STDOUT,
pscr->pbBuffer, pscr->ccol*sizeof(TCHAR), &cb) == 0 ||
cb < pscr->ccol*sizeof(TCHAR)) {
err_out_flush:
if (FileIsDevice(STDOUT)) {
PutStdErr(ERROR_WRITE_FAULT, NOARGS) ;
} else if (!FileIsPipe(STDOUT)) {
PutStdErr(ERROR_DISK_FULL, NOARGS) ;
}
//
// if it was was a pipe do not continue to print out to pipe since it
// has probably gone away.
//
// BUGBUG make this a more general error return
//
Abort();
}
}
pscr->crow += GetNumRows(pscr, pscr->pbBuffer);
pscr->pbBuffer[0] = 0;
pscr->ccol = 0;
return(SUCCESS);
}
STATUS
WriteFlushAndEol(
IN PSCREEN pscr
)
/*++
Routine Description:
Write Flush with eof.
Arguments:
pscr - screen info.
Return Value:
Will abort on write error.
SUCCESS
--*/
{
STATUS rc = SUCCESS;
//
// Check if there is something on the line to print.
//
if (pscr->ccol) {
//
// If there would be either a line wrap or a LF printed
// from line the just flush otherwise use Eol rourtine
// to for LF
//
if (GetNumRows(pscr, pscr->pbBuffer) ) {
rc = WriteFlush(pscr);
} else {
rc = WriteEol(pscr);
}
}
return( rc );
}
void
SetColRow(
IN PSCREEN pscr
)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
ULONG crowMax, ccolMax;
crowMax = 25;
ccolMax = 80;
if (pscr->hndScreen) {
//
// On open we checked if this was a valid screen handle so this
// cannot fail for any meaning full reason. If we do fail then
// just leave it at the default.
//
if (GetConsoleScreenBufferInfo( pscr->hndScreen, &ConInfo)) {
//
// The console size we use is the screen buffer size not the
// windows size itself. The window is a frame upon the screen
// buffer and we should always write to the screen buffer and
// format based upon that information
//
ccolMax = ConInfo.dwSize.X;
crowMax = ConInfo.srWindow.Bottom - ConInfo.srWindow.Top + 1;
}
}
pscr->crowMax = crowMax;
pscr->ccolMax = ccolMax;
}
ULONG
GetNumRows(
IN PSCREEN pscr,
IN PTCHAR pbBuffer
)
{
PTCHAR szLFLast, szLFCur;
ULONG crow, cb;
szLFLast = pbBuffer;
crow = 0;
while ( szLFCur = mystrchr(szLFLast, chLF) ) {
cb = szLFCur - szLFLast;
while ( cb > pscr->ccolMax ) {
cb -= pscr->ccolMax;
crow++;
}
crow++;
szLFLast = szLFCur + 1;
}
//
// if there were no LF's in the line then crow would be
// 0. Count the number of lines the console will output in
// wrapping
//
if (crow == 0) {
crow = (pscr->ccol / pscr->ccolMax);
}
DEBUG((ICGRP, CONLVL, "Console: Num of rows counted = %d", crow)) ;
//
// a 0 returns means that there would not be a LF printed or
// a wrap done.
//
return( crow );
}
#if defined(JAPAN) && defined(UNICODE)
/***************************************************************************\
* BOOL IsFullWidth(WCHAR wch)
*
* Determine if the given Unicode char is fullwidth or not.
*
* History:
* 04-08-92 ShunK Created.
\***************************************************************************/
BOOL IsFullWidth(WCHAR wch)
{
if (CurrentCPInfo.MaxCharSize == 1)
return FALSE;
if (wch <= 0x007f || (wch >= 0xff60 && wch <= 0xff9f))
return(FALSE); // Half width.
else
return(TRUE); // Full width.
}
/***************************************************************************\
* BOOL SizeOfHalfWidthString(PWCHAR pwch)
*
* Determine size of the given Unicode string, adjusting for half-width chars.
*
* History:
* 08-08-93 FloydR Created.
\***************************************************************************/
int SizeOfHalfWidthString(PWCHAR pwch)
{
int c=0;
while (*pwch) {
if (IsFullWidth(*pwch))
c += 2;
else
c++;
pwch++;
}
return c;
}
#endif /* defined(JAPAN) && defined(UNICODE) */