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