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.
 
 
 
 
 
 

556 lines
13 KiB

/* File: D:\WACKER\tdll\termcpy.c (Created: 24-Jan-1994)
*
* Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
* All rights reserved
*
* $Revision: 4 $
* $Date: 5/09/01 4:38p $
*/
#include <windows.h>
#pragma hdrstop
#include "stdtyp.h"
#include "mc.h"
#include "tdll.h"
#include "htchar.h"
#include "session.h"
#include "backscrl.h"
#include "assert.h"
#include <emu\emu.h>
#include "term.hh"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* CopyMarkedTextFromTerminal
*
* DESCRIPTION:
* Helper function that gets the marked region and passes the call
* onto CopyTextFromTerminal().
*
* ARGUMENTS:
* hSession - public session handle
* ppv - pointer to a buffer pointer
* pdwCnt - pointer to size variable
* fIncludeLF - TRUE means include linefeeds.
*
* RETURNS:
* BOOL
*
*/
BOOL CopyMarkedTextFromTerminal(const HSESSION hSession, void **ppv,
DWORD *pdwCnt, const BOOL fIncludeLF)
{
BOOL fReturn;
ECHAR *pechBuf;
TCHAR *pszOutput;
const HWND hwndTerm = sessQueryHwndTerminal(hSession);
const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
fReturn = CopyTextFromTerminal(hSession, &hhTerm->ptBeg, &hhTerm->ptEnd,
ppv, pdwCnt, fIncludeLF);
pechBuf = *ppv;
// Strip Out Any repeated Characters in the string
StrCharStripDBCSString(pechBuf, (long)StrCharGetEcharByteCount(pechBuf), pechBuf);
// hMem currently points to an array of ECHAR's, convert this to
// TCHARS before giving the results to the caller.
pszOutput = malloc((ULONG)StrCharGetEcharByteCount(pechBuf) + 1);
CnvrtECHARtoMBCS(pszOutput, (ULONG)StrCharGetEcharByteCount(pechBuf) + 1,
pechBuf,StrCharGetEcharByteCount(pechBuf)+1);//mrw:5/17/95
*(pszOutput + StrCharGetEcharByteCount(pechBuf)) = ETEXT('\0');
free(pechBuf);
pechBuf = NULL;
*ppv = pszOutput;
*pdwCnt = (ULONG)StrCharGetByteCount(pszOutput);
return fReturn;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* CopyTextFromTerminal
*
* DESCRIPTION:
* A work-horse function that will use the given points as a marked region
* and do the necessary work to make a copy of the marked text into
* a new memory region. The marked range can include the backscroll
* region and cross into the terminal region. The begining and ending
* points are in terminal coordinates (backscroll lines are numbered
* -1 to -infinity, terminal lines are numbered 1 to 24, line 0 is the
* divider line and does not exist for copies but can be included in
* the range). It is *not* a requirement that the begininig point be
* less than the ending point.
*
* ARGUMENTS:
* HSESSION hSession - handle to the session.
* LPPOINT lpptBeg - begining point of marked region.
* LPPOINT lpptEnd - end point of mark region.
* void **pv - pointer to buffer pointer
* DWORD *pdwCnt - pointer to double word for size
* BOOL fIncludeLF -
*
* RETURNS:
* BOOL
*
*/
BOOL CopyTextFromTerminal(const HSESSION hSession,
const PPOINT pptBeg,
const PPOINT pptEnd,
void **ppv,
DWORD *pdwCnt,
const BOOL fIncludeLF)
{
int iWant,
iGot,
yLn,
xCol,
iLen,
iTmp,
iRows,
iCols,
iTopline,
iOffset,
iBkLns,
iSize;
DWORD dwSize, dwOldSize;
ECHAR *lpachTxt;
ECHAR *lpachBuf;
ECHAR achTmp[256],
*pachTmp;
ECHAR **alpstrTxt;
long lBeg, lEnd;
HCURSOR hCursor;
ECHAR *hMem = 0; // malloc memory
ECHAR *hMemTmp = 0; // malloc memory
POINT ptBeg, ptEnd, ptTmp;
const HWND hwndTerm = sessQueryHwndTerminal(hSession);
const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
const HBACKSCRL hBackscrl = sessQueryBackscrlHdl(hhTerm->hSession);
*ppv = 0;
*pdwCnt = 0;
hCursor = SetCursor(LoadCursor((HINSTANCE)0, IDC_WAIT));
dwSize = 1; // By starting at one, we always have room for the '\0'.
iRows = hhTerm->iRows;
iCols = hhTerm->iCols;
iTopline = hhTerm->iTopline;
alpstrTxt = hhTerm->fplpstrTxt;
ptBeg = *pptBeg;
ptEnd = *pptEnd;
/* --- do some range checking for the line number --- */
iBkLns = backscrlGetNumLines(hBackscrl);
iBkLns = -iBkLns;
if (ptBeg.y > 0 && ptBeg.y > iRows)
ptBeg.y = iRows;
if (ptBeg.y < 0 && ptBeg.y < iBkLns)
ptBeg.y = iBkLns;
if (ptEnd.y > 0 && ptEnd.y > iRows)
ptEnd.y = iRows;
if (ptEnd.y < 0 && ptEnd.y < iBkLns)
ptEnd.y = iBkLns;
/* --- and do some range checking for the column number --- */
if (ptBeg.x < 0) /* negative column doesn't make much sense */
ptBeg.x = 0;
if (ptBeg.x >= iCols)
ptBeg.x = iCols - 1;
if (ptEnd.x < 0) /* see above */
ptEnd.x = 0;
if (ptEnd.x >= iCols)
ptEnd.x = iCols - 1;
/* --- convert to offsets --- */
lBeg = (ptBeg.y * iCols) + ptBeg.x;
lEnd = (ptEnd.y * iCols) + ptEnd.x;
if (lBeg == lEnd)
{
SetCursor(hCursor);
return FALSE;
}
sessSetSuspend(hSession, SUSPEND_TERMINAL_COPY);
if (lBeg > lEnd)
{
ptTmp = ptEnd;
ptEnd = ptBeg;
ptBeg = ptTmp;
}
if ((hMem = malloc(dwSize * sizeof(ECHAR))) == 0)
{
assert(FALSE);
SetCursor(hCursor);
sessClearSuspend(hSession, SUSPEND_TERMINAL_COPY);
return FALSE;
}
// Get first line of range
iGot = 0;
lpachTxt = 0;
achTmp[0] = ETEXT('\0');
if (ptBeg.y < 0)
{
xCol = ptBeg.x;
yLn = ptBeg.y;
iWant = ptEnd.y - ptBeg.y + 1;
if (iWant > 0)
{
while (iWant > 0)
{
if (backscrlGetBkLines(hBackscrl, yLn, iWant, &iGot,
&lpachTxt, &iOffset) == FALSE)
{
goto PROCESS_ERROR;
}
lpachTxt += iOffset;
// Lets say the user has highlighted an area of the backscroll
// region that has no data (ie. a blank line). Adding xCol to
// lpachTxt is incorrect. This for-loop checks for this
// condition and resets lpachTxt to the beginning of the line.
// Incidentally, this also sets xCol to 0 which is necessary
// for subsequent lines to feed in correctly.
for (lpachBuf = lpachTxt ; xCol > 0 ; --xCol, ++lpachTxt)
{
if (*lpachTxt == ETEXT('\n'))
{
lpachTxt = lpachBuf;
xCol = 0;
break;
}
}
iWant -= iGot;
while (iGot-- > 0 && yLn < ptEnd.y && yLn < -1)
{
for (pachTmp = achTmp, iTmp = 0 ;
*lpachTxt != ETEXT('\n') &&
//
// Fix for not getting full backscroll buffer
// in DBCS versions by taking into account the
// size of the ECHAR. REV: 03/07/2001
//
iTmp < MAX_EMUCOLS * sizeof(ECHAR);
++pachTmp, ++iTmp)
{
*pachTmp = *lpachTxt++;
}
// Fail Safe: if the text we received from
// backscrlGetBkLines() is mangled somehow and we
// don't see a newline, then abort before we seg.
//
// Fix for not getting full backscroll buffer
// in DBCS versions by taking into account the
// size of the ECHAR. REV: 03/07/2001
//
if (iTmp >= MAX_EMUCOLS * sizeof(ECHAR))
goto PROCESS_ERROR;
lpachTxt += 1;
*pachTmp++ = ETEXT('\r');
if (fIncludeLF)
*pachTmp++ = ETEXT('\n');
*pachTmp = ETEXT('\0');
hMemTmp = hMem;
dwOldSize = dwSize - 1;
dwSize += (DWORD)StrCharGetEcharLen(achTmp);
hMem = realloc(hMemTmp, dwSize *sizeof(ECHAR));
if (hMem == 0)
goto PROCESS_ERROR;
/* remember how a realloc works */
hMemTmp = (ECHAR *)0;
lpachBuf = hMem + dwOldSize;
iSize = StrCharGetEcharByteCount(achTmp);
if ( iSize )
MemCopy(lpachBuf, achTmp, iSize );
hMem[dwSize - 1] = ETEXT('\0');
yLn += 1;
}
if (yLn >= ptEnd.y || yLn >= -1)
break;
}
// Another bug bytes the dust. Wasn't checking to see if iGot
// was the reason we exited the loop above. It caused things
// to seg occassionally.
if (iGot >= 0)
{
// Last line stuff (could be crossing into terminal area but
// we still need to clean-up backscroll stuff.
if (ptBeg.y == ptEnd.y)
xCol = ptEnd.x - ptBeg.x;
else if (ptEnd.y < 0) /* && ptEnd.x > 0) removed - mrw */
xCol = ptEnd.x;
else
xCol = iCols;
for (pachTmp = achTmp ; xCol-- > 0 && *lpachTxt != ETEXT('\n'); ++pachTmp)
*pachTmp = *lpachTxt++;
if (ptEnd.y >= 0)
{
*pachTmp++ = ETEXT('\r');
if (fIncludeLF)
*pachTmp++ = ETEXT('\n');
}
*pachTmp = ETEXT('\0');
}
hMemTmp = hMem;
dwOldSize = dwSize - 1;
dwSize += (DWORD)StrCharGetEcharLen(achTmp);
hMem = realloc(hMemTmp, dwSize * sizeof(ECHAR));
if (hMem == 0)
goto PROCESS_ERROR;
/* remember how a realloc works */
hMemTmp = (ECHAR *)0;
lpachBuf = hMem + dwOldSize;
iSize = StrCharGetEcharByteCount(achTmp);
if ( iSize )
MemCopy(lpachBuf, achTmp, iSize);
hMem[dwSize - 1] = ETEXT('\0');
} // end if (iWant > 0)
// terminal area...
if (ptEnd.y >= 0)
{
yLn = 1;
while (yLn <= ptEnd.y)
{
iTmp = ((yLn + iTopline) % MAX_EMUROWS) - 1;
if (iTmp < 0)
iTmp = MAX_EMUROWS - 1;
lpachTxt = alpstrTxt[iTmp];
iLen = strlentrunc(lpachTxt, iCols);
xCol = (yLn == ptEnd.y) ? min(ptEnd.x, iLen) : iLen;
for (pachTmp = achTmp ; xCol > 0 ; --xCol)
*pachTmp++ = *lpachTxt++;
if (yLn != ptEnd.y)
{
*pachTmp++ = ETEXT('\r');
if (fIncludeLF)
*pachTmp++ = ETEXT('\n');
}
*pachTmp = ETEXT('\0');
hMemTmp = hMem;
dwOldSize = dwSize - 1;
dwSize += (DWORD)StrCharGetEcharLen(achTmp);
hMem = realloc(hMemTmp, dwSize * sizeof(ECHAR));
if (hMem == 0)
goto PROCESS_ERROR;
/* remember how a realloc works */
hMemTmp = (ECHAR *)0;
lpachBuf = hMem + dwOldSize;
iSize = StrCharGetEcharByteCount(achTmp);
if ( iSize )
MemCopy(lpachBuf, achTmp, iSize );
hMem[dwSize - 1] = ETEXT('\0');
yLn += 1;
}
}
}
else // terminal only case
{
if (ptBeg.y >= 0)
{
yLn = ptBeg.y;
while (yLn <= ptEnd.y)
{
iTmp = ((yLn + iTopline) % MAX_EMUROWS) - 1;
if (iTmp < 0)
iTmp = MAX_EMUROWS - 1;
lpachTxt = alpstrTxt[iTmp];
if (ptBeg.y == ptEnd.y)
{
lpachTxt += ptBeg.x;
xCol = min(strlentrunc(lpachTxt, iCols - ptBeg.x),
ptEnd.x - ptBeg.x);
}
else if (yLn == ptBeg.y)
{
lpachTxt += ptBeg.x;
xCol = strlentrunc(lpachTxt, iCols - ptBeg.x);
}
else if (yLn == ptEnd.y)
{
xCol = min(ptEnd.x, strlentrunc(lpachTxt, iCols));
}
else
{
xCol = strlentrunc(lpachTxt, iCols);
}
for (pachTmp = achTmp ; xCol > 0 ; --xCol)
*pachTmp++ = *lpachTxt++;
if (yLn != ptEnd.y)
{
*pachTmp++ = ETEXT('\r');
if (fIncludeLF)
*pachTmp++ = ETEXT('\n');
}
*pachTmp = ETEXT('\0');
hMemTmp = hMem;
dwOldSize = dwSize - 1;
dwSize += (DWORD)StrCharGetEcharLen(achTmp);
hMem = realloc(hMemTmp, dwSize * sizeof(ECHAR));
if (hMem == 0)
goto PROCESS_ERROR;
/* remember how a realloc works */
hMemTmp = (ECHAR *)0;
lpachBuf = hMem + dwOldSize;
iSize = StrCharGetEcharByteCount(achTmp);
if ( iSize )
MemCopy(lpachBuf, achTmp, iSize );
hMem[dwSize - 1] = ETEXT('\0');
yLn += 1;
}
}
}
SetCursor(hCursor);
*ppv = hMem;
*pdwCnt = (ULONG)StrCharGetEcharByteCount(hMem);
sessClearSuspend(hSession, SUSPEND_TERMINAL_COPY);
return TRUE;
// process error condition here.
PROCESS_ERROR:
if (hMem)
{
free(hMem);
hMem = NULL;
}
if (hMemTmp)
{
free(hMemTmp);
hMemTmp = NULL;
}
SetCursor(hCursor);
sessClearSuspend(hSession, SUSPEND_TERMINAL_COPY);
return 0;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* strlentrunc
*
* DESCRIPTION:
* Finds the length of a character buffer less the trailing whitespace.
*
* ARGUMENTS:
* pach - array of t characters
* iLen - length of buffer
*
* RETURNS:
* new length
*
*/
int strlentrunc(const ECHAR *pach, const int iLen)
{
int i;
for (i = iLen-1 ; i >= 0 ; --i)
{
switch (pach[i])
{
/* Whitespace characters */
case ETEXT('\0'):
case ETEXT('\t'):
case ETEXT('\n'):
case ETEXT('\v'):
case ETEXT('\f'):
case ETEXT('\r'):
case ETEXT(' '):
break;
default:
return i+1;
}
}
return 0;
}