828 lines
21 KiB
C
828 lines
21 KiB
C
|
/*** winclip.c - windows clipboard editor extension
|
||
|
*
|
||
|
* Copyright <C> 1988, Microsoft Corporation
|
||
|
*
|
||
|
* Purpose:
|
||
|
* Contains the tglcase function.
|
||
|
*
|
||
|
* Revision History:
|
||
|
*
|
||
|
* 28-Jun-1988 LN Created
|
||
|
* 12-Sep-1988 mz Made WhenLoaded match declaration
|
||
|
*
|
||
|
*************************************************************************/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdlib.h> /* min macro definition */
|
||
|
#include <string.h> /* prototypes for string fcns */
|
||
|
|
||
|
#undef pascal
|
||
|
#include "zext.h"
|
||
|
|
||
|
#define M_FALSE ((flagType)0)
|
||
|
#define M_TRUE ((flagType)(-1))
|
||
|
|
||
|
#define BUFLEN_MAX (BUFLEN-1)
|
||
|
|
||
|
/*
|
||
|
** Internal function prototypes
|
||
|
*/
|
||
|
#ifdef DEBUG
|
||
|
#define DPRINT(p) DoMessage(p)
|
||
|
#else
|
||
|
#define DPRINT(p)
|
||
|
#endif
|
||
|
|
||
|
HWND ghwndClip;
|
||
|
HINSTANCE ghmod;
|
||
|
int gfmtArgType;
|
||
|
|
||
|
void DeleteArg( PFILE pFile, int argType, COL xStart, LINE yStart,
|
||
|
COL xEnd, COL yEnd );
|
||
|
|
||
|
void InsertText( PFILE pFile, LPSTR pszText, DWORD dwInsMode,
|
||
|
COL xStart, LINE yStart );
|
||
|
flagType pascal EXTERNAL WinCutCopy (ARG *pArg, flagType fCut, flagType fClip);
|
||
|
LPSTR EndOfLine( LPSTR psz );
|
||
|
LPSTR EndOfBreak( LPSTR psz );
|
||
|
int ExtendLine( LPSTR psz, int cchSZ, char ch, int cchNew );
|
||
|
|
||
|
/*************************************************************************
|
||
|
**
|
||
|
** wincopy
|
||
|
** Toggle the case of alphabetics contaied within the selected argument:
|
||
|
**
|
||
|
** NOARG - Toggle case of entire current line
|
||
|
** NULLARG - Toggle case of current line, from cursor to end of line
|
||
|
** LINEARG - Toggle case of range of lines
|
||
|
** BOXARG - Toggle case of characters with the selected box
|
||
|
** NUMARG - Converted to LINEARG before extension is called.
|
||
|
** MARKARG - Converted to Appropriate ARG form above before extension is
|
||
|
** called.
|
||
|
**
|
||
|
** STREAMARG - Not Allowed. Treated as BOXARG
|
||
|
** TEXTARG - Not Allowed
|
||
|
**
|
||
|
*/
|
||
|
flagType
|
||
|
pascal
|
||
|
EXTERNAL
|
||
|
wincopy (
|
||
|
unsigned int argData, /* keystroke invoked with */
|
||
|
ARG *pArg, /* argument data */
|
||
|
flagType fMeta /* indicates preceded by meta */
|
||
|
)
|
||
|
{
|
||
|
|
||
|
return WinCutCopy( pArg, M_FALSE, M_FALSE );
|
||
|
}
|
||
|
|
||
|
flagType
|
||
|
pascal
|
||
|
EXTERNAL
|
||
|
wincut (
|
||
|
unsigned int argData, /* keystroke invoked with */
|
||
|
ARG *pArg, /* argument data */
|
||
|
flagType fMeta /* indicates preceded by meta */
|
||
|
)
|
||
|
{
|
||
|
|
||
|
return WinCutCopy( pArg, M_TRUE, fMeta );
|
||
|
}
|
||
|
|
||
|
flagType
|
||
|
pascal
|
||
|
EXTERNAL
|
||
|
WinCutCopy (
|
||
|
ARG *pArg,
|
||
|
flagType fCut,
|
||
|
flagType fNoClip
|
||
|
)
|
||
|
{
|
||
|
PFILE pFile; /* file handle of current file */
|
||
|
COL xStart, xEnd;
|
||
|
LINE yStart, yEnd;
|
||
|
char achLine[BUFLEN];
|
||
|
HANDLE hText;
|
||
|
LPSTR pszText;
|
||
|
int iLine, cchLine;
|
||
|
flagType fRet = M_TRUE;
|
||
|
int argSave, argType;
|
||
|
|
||
|
pFile = FileNameToHandle ("", "");
|
||
|
|
||
|
|
||
|
argSave = argType = pArg->argType;
|
||
|
|
||
|
switch ( argType ) {
|
||
|
case BOXARG: /* case switch box */
|
||
|
xStart = pArg->arg.boxarg.xLeft;
|
||
|
xEnd = pArg->arg.boxarg.xRight + 1;
|
||
|
yStart = pArg->arg.boxarg.yTop;
|
||
|
yEnd = pArg->arg.boxarg.yBottom + 1;
|
||
|
|
||
|
/* At this point...
|
||
|
* [xy]Start is Inclusive, [xy]End is EXCLUSIVE of the box arg
|
||
|
*/
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
wsprintf( achLine, " BoxDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
|
||
|
DoMessage( achLine );
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case NOARG:
|
||
|
/* convert NOARG to a STREAMARG on whole current line */
|
||
|
argType = STREAMARG;
|
||
|
argSave = LINEARG;
|
||
|
xStart = 0;
|
||
|
yStart = pArg->arg.noarg.y;
|
||
|
xEnd = 0;
|
||
|
yEnd = yStart + 1;
|
||
|
break;
|
||
|
|
||
|
case TEXTARG:
|
||
|
/*
|
||
|
* Text args are only for real text. NumArgs and MarkArgs are
|
||
|
* converted to stream or box args by the editor since we say
|
||
|
* we accept NUMARG and MARKARG during initialization.
|
||
|
*/
|
||
|
argType = STREAMARG;
|
||
|
argSave = STREAMARG;
|
||
|
xStart = pArg->arg.textarg.x;
|
||
|
xEnd = lstrlen(pArg->arg.textarg.pText) + xStart;
|
||
|
yStart = yEnd = pArg->arg.textarg.y;
|
||
|
break;
|
||
|
|
||
|
case LINEARG: /* case switch line range */
|
||
|
/* convert LINEARG to a STREAMARG so we don't get lots of white space*/
|
||
|
argType = STREAMARG;
|
||
|
xStart = 0;
|
||
|
xEnd = 0;
|
||
|
yStart = pArg->arg.linearg.yStart;
|
||
|
yEnd = pArg->arg.linearg.yEnd + 1;
|
||
|
#ifdef DEBUG
|
||
|
wsprintf( achLine, " LineDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
|
||
|
DoMessage( achLine );
|
||
|
#endif
|
||
|
|
||
|
/* At this point...
|
||
|
* [xy]Start is Inclusive, [xy]End is EXCLUSIVE of the line arg
|
||
|
*/
|
||
|
|
||
|
break;
|
||
|
|
||
|
case STREAMARG:
|
||
|
/*
|
||
|
* Set Start == first char pos in stream, End == first char pos
|
||
|
* AFTER stream.
|
||
|
*/
|
||
|
xStart = pArg->arg.streamarg.xStart;
|
||
|
xEnd = pArg->arg.streamarg.xEnd;
|
||
|
yStart = pArg->arg.streamarg.yStart;
|
||
|
yEnd = pArg->arg.streamarg.yEnd;
|
||
|
#ifdef DEBUG
|
||
|
wsprintf( achLine, " StreamDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
|
||
|
DoMessage( achLine );
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
#ifdef DEBUG
|
||
|
wsprintf( achLine, " Unknown Arg: 0x%04x", argType );
|
||
|
DoMessage( achLine );
|
||
|
return M_TRUE;
|
||
|
#endif
|
||
|
return M_FALSE;
|
||
|
}
|
||
|
|
||
|
if (!fNoClip) {
|
||
|
if (argType == STREAMARG) {
|
||
|
int cch = 0;
|
||
|
int iChar;
|
||
|
|
||
|
for ( iLine = yStart; iLine <= yEnd; iLine++ )
|
||
|
cch += GetLine (iLine, achLine, pFile) + 3;
|
||
|
|
||
|
hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cch);
|
||
|
|
||
|
if (hText == NULL) {
|
||
|
DoMessage( " winclip: Out of Memory" );
|
||
|
return M_FALSE;
|
||
|
}
|
||
|
|
||
|
pszText = GlobalLock(hText);
|
||
|
|
||
|
|
||
|
iChar = xStart;
|
||
|
|
||
|
for ( iLine = yStart; iLine < yEnd; iLine++ ) {
|
||
|
cchLine = GetLine (iLine, achLine, pFile);
|
||
|
|
||
|
/* Incase we start after the end of the line */
|
||
|
if (cchLine < iChar)
|
||
|
cch = 0;
|
||
|
else
|
||
|
cch = cchLine - iChar;
|
||
|
|
||
|
CopyMemory(pszText, &achLine[iChar], cch);
|
||
|
pszText += cch;
|
||
|
strcpy( pszText, "\r\n" );
|
||
|
pszText += 2;
|
||
|
iChar = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* Get partial last line */
|
||
|
if (xEnd != 0) {
|
||
|
cchLine = GetLine (iLine, achLine, pFile);
|
||
|
|
||
|
/* if line is short, then pad it out */
|
||
|
cchLine = ExtendLine( achLine, cchLine, ' ', xEnd );
|
||
|
|
||
|
if (cchLine < iChar)
|
||
|
cchLine = 0;
|
||
|
else
|
||
|
cchLine = xEnd - iChar;
|
||
|
|
||
|
CopyMemory(pszText, &achLine[iChar], cchLine);
|
||
|
pszText += cchLine;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
LINE iLine;
|
||
|
int cchBox = xEnd - xStart;
|
||
|
|
||
|
hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
|
||
|
(yEnd - yStart) * (cchBox + 3));
|
||
|
|
||
|
if (hText == NULL) {
|
||
|
DoMessage( " winclip: Out of Memory" );
|
||
|
return M_FALSE;
|
||
|
}
|
||
|
|
||
|
pszText = GlobalLock(hText);
|
||
|
|
||
|
for ( iLine = yStart; iLine < yEnd; iLine++ ) {
|
||
|
cchLine = GetLine (iLine, achLine, pFile);
|
||
|
|
||
|
if (argType == BOXARG)
|
||
|
cchLine = ExtendLine( achLine, cchLine, ' ', xEnd );
|
||
|
|
||
|
if (cchLine < xStart )
|
||
|
cchLine = 0;
|
||
|
else
|
||
|
cchLine -= xStart;
|
||
|
|
||
|
cchLine = min(cchLine, cchBox);
|
||
|
|
||
|
CopyMemory(pszText, &achLine[xStart], cchLine);
|
||
|
pszText += cchLine;
|
||
|
strcpy( pszText, "\r\n" );
|
||
|
pszText += 2;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pszText = '\0';
|
||
|
|
||
|
GlobalUnlock(hText);
|
||
|
|
||
|
if (OpenClipboard(ghwndClip)) {
|
||
|
EmptyClipboard();
|
||
|
|
||
|
/*
|
||
|
* Set the text into the clipboard
|
||
|
*/
|
||
|
if (SetClipboardData(CF_TEXT, hText) == hText) {
|
||
|
/*
|
||
|
* Remember the Arg type for pasting back
|
||
|
*/
|
||
|
if (gfmtArgType != 0) {
|
||
|
DWORD *pdw;
|
||
|
HANDLE hArgType = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
|
||
|
sizeof(DWORD));
|
||
|
|
||
|
if (hArgType != NULL && (pdw = GlobalLock(hArgType)) != NULL) {
|
||
|
*pdw = (DWORD)(argSave);
|
||
|
|
||
|
GlobalUnlock(hArgType);
|
||
|
|
||
|
SetClipboardData(gfmtArgType, hArgType);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
/* An error occured writing text to clipboard */
|
||
|
|
||
|
wsprintf(achLine, " winclip: Error (%ld) setting data",
|
||
|
GetLastError());
|
||
|
DoMessage( achLine );
|
||
|
fRet = M_FALSE;
|
||
|
}
|
||
|
|
||
|
CloseClipboard();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* No need to free the handle, USER32 will do it (yes it keeps
|
||
|
* track of the client side handle) when we set the next clipboard
|
||
|
* data. (Love that Win3.1 compatibility!)
|
||
|
*/
|
||
|
if (fRet && fCut)
|
||
|
DeleteArg( pFile, argType, xStart, yStart, xEnd, yEnd );
|
||
|
|
||
|
|
||
|
return fRet;
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
**
|
||
|
** winpaste
|
||
|
** Toggle the case of alphabetics contaied within the selected argument:
|
||
|
**
|
||
|
** NOARG - Toggle case of entire current line
|
||
|
** NULLARG - Toggle case of current line, from cursor to end of line
|
||
|
** LINEARG - Toggle case of range of lines
|
||
|
** BOXARG - Toggle case of characters with the selected box
|
||
|
** NUMARG - Converted to LINEARG before extension is called.
|
||
|
** MARKARG - Converted to Appropriate ARG form above before extension is
|
||
|
** called.
|
||
|
**
|
||
|
** STREAMARG - Not Allowed. Treated as BOXARG
|
||
|
** TEXTARG - Not Allowed
|
||
|
**
|
||
|
*/
|
||
|
flagType
|
||
|
pascal
|
||
|
EXTERNAL
|
||
|
winpaste (
|
||
|
unsigned int argData, /* keystroke invoked with */
|
||
|
ARG *pArg, /* argument data */
|
||
|
flagType fMeta /* indicates preceded by meta */
|
||
|
)
|
||
|
{
|
||
|
PFILE pFile; /* file handle of current file */
|
||
|
COL xStart, xEnd;
|
||
|
LINE yStart, yEnd;
|
||
|
int argType;
|
||
|
UINT fmtData = CF_TEXT;
|
||
|
DWORD dwInsMode = STREAMARG;
|
||
|
HANDLE hText;
|
||
|
LPSTR pszText;
|
||
|
|
||
|
/*
|
||
|
* Get the clipboard text and insertion type
|
||
|
*/
|
||
|
if (pArg->argType == TEXTARG) {
|
||
|
int i, j;
|
||
|
char achLine[3 + 1 + 3 + 1 + 1 + BUFLEN + 1 + 1 + 5 + 1];
|
||
|
char *p;
|
||
|
|
||
|
/*
|
||
|
* Quick hack to make text arg pastes work like the do in Z
|
||
|
*/
|
||
|
j = pArg->arg.textarg.cArg;
|
||
|
if (j > 2)
|
||
|
j = 2;
|
||
|
|
||
|
achLine[0] = '\0';
|
||
|
for ( i = 0; i < j; i++ )
|
||
|
lstrcat(achLine, "arg ");
|
||
|
|
||
|
p = achLine + lstrlen(achLine);
|
||
|
wsprintf( p, "\"%s\" paste", pArg->arg.textarg.pText );
|
||
|
return fExecute( achLine );
|
||
|
}
|
||
|
|
||
|
/* if no text then return FALSE */
|
||
|
if (!IsClipboardFormatAvailable(fmtData)) {
|
||
|
|
||
|
/* No text, try display text */
|
||
|
fmtData = CF_DSPTEXT;
|
||
|
|
||
|
if (!IsClipboardFormatAvailable(fmtData)) {
|
||
|
/* bummer! no text at all, return FALSE */
|
||
|
DoMessage( " winclip: invalid clipboard format" );
|
||
|
return M_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!OpenClipboard(ghwndClip))
|
||
|
return M_FALSE;
|
||
|
|
||
|
hText = GetClipboardData(fmtData);
|
||
|
if (hText == NULL || (pszText = GlobalLock(hText)) == NULL) {
|
||
|
CloseClipboard();
|
||
|
return M_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Get insert mode */
|
||
|
|
||
|
if (IsClipboardFormatAvailable(gfmtArgType)) {
|
||
|
DWORD *pdw;
|
||
|
HANDLE hInsMode;
|
||
|
|
||
|
hInsMode = GetClipboardData(gfmtArgType);
|
||
|
|
||
|
if (hInsMode != NULL && (pdw = GlobalLock(hInsMode)) != NULL) {
|
||
|
dwInsMode = *pdw;
|
||
|
|
||
|
GlobalUnlock(hInsMode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
pFile = FileNameToHandle ("", "");
|
||
|
|
||
|
argType = pArg->argType;
|
||
|
|
||
|
switch ( argType ) {
|
||
|
case BOXARG: /* case switch box */
|
||
|
/*
|
||
|
* Set [xy]Start inclusive of box arg,
|
||
|
* [xy]End exclusive of box arg.
|
||
|
*/
|
||
|
xStart = pArg->arg.boxarg.xLeft;
|
||
|
xEnd = pArg->arg.boxarg.xRight + 1;
|
||
|
yStart = pArg->arg.boxarg.yTop;
|
||
|
yEnd = pArg->arg.boxarg.yBottom + 1;
|
||
|
break;
|
||
|
|
||
|
case LINEARG: /* case switch line range */
|
||
|
/*
|
||
|
* Set [xy]Start inclusive of line arg,
|
||
|
* [xy]End exclusive of line arg.
|
||
|
*/
|
||
|
xStart = 0;
|
||
|
xEnd = BUFLEN + 1;
|
||
|
yStart = pArg->arg.linearg.yStart;
|
||
|
yEnd = pArg->arg.linearg.yEnd + 1;
|
||
|
break;
|
||
|
|
||
|
case STREAMARG:
|
||
|
/*
|
||
|
* Set [xy]Start inclusive of stream
|
||
|
* xEnd is EXCLUSIVE of stream
|
||
|
* yEnd is INCLUSIVE of stream
|
||
|
*/
|
||
|
xStart = pArg->arg.streamarg.xStart;
|
||
|
xEnd = pArg->arg.streamarg.xEnd;
|
||
|
yStart = pArg->arg.streamarg.yStart;
|
||
|
yEnd = pArg->arg.streamarg.yEnd;
|
||
|
break;
|
||
|
|
||
|
case NOARG:
|
||
|
xStart = pArg->arg.noarg.x;
|
||
|
xEnd = xStart + 1;
|
||
|
yStart = pArg->arg.noarg.y;
|
||
|
yEnd = yStart + 1;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
GlobalUnlock(hText);
|
||
|
CloseClipboard();
|
||
|
return M_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Delete any selection
|
||
|
*/
|
||
|
DeleteArg( pFile, argType, xStart, yStart, xEnd, yEnd );
|
||
|
|
||
|
/*
|
||
|
* Insert new text with correct mode
|
||
|
*/
|
||
|
InsertText( pFile, pszText, dwInsMode, xStart, yStart );
|
||
|
|
||
|
GlobalUnlock(hText);
|
||
|
CloseClipboard();
|
||
|
|
||
|
return M_TRUE;
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
**
|
||
|
** windel
|
||
|
**
|
||
|
**
|
||
|
*/
|
||
|
flagType
|
||
|
pascal
|
||
|
EXTERNAL
|
||
|
windel (
|
||
|
unsigned int argData, /* keystroke invoked with */
|
||
|
ARG *pArg, /* argument data */
|
||
|
flagType fMeta /* indicates preceded by meta */
|
||
|
)
|
||
|
{
|
||
|
int argType = pArg->argType;
|
||
|
|
||
|
if (argType == NOARG)
|
||
|
return fExecute("delete");
|
||
|
|
||
|
if (argType == NULLARG) {
|
||
|
int c, x, y;
|
||
|
c = pArg->arg.nullarg.cArg;
|
||
|
x = pArg->arg.nullarg.x;
|
||
|
y = pArg->arg.nullarg.y;
|
||
|
|
||
|
pArg->argType = STREAMARG;
|
||
|
pArg->arg.streamarg.xStart = x;
|
||
|
pArg->arg.streamarg.xEnd = 0;
|
||
|
pArg->arg.streamarg.yStart = y;
|
||
|
pArg->arg.streamarg.yEnd = y + 1;
|
||
|
pArg->arg.streamarg.cArg = c;
|
||
|
}
|
||
|
|
||
|
return WinCutCopy (pArg, M_TRUE, fMeta);
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
**
|
||
|
** WhenLoaded
|
||
|
** Executed when extension gets loaded. Identify self & assign default
|
||
|
** keystroke.
|
||
|
**
|
||
|
** Entry:
|
||
|
** none
|
||
|
*/
|
||
|
void
|
||
|
winclipWhenLoaded ()
|
||
|
{
|
||
|
#if 0
|
||
|
WNDCLASS wc;
|
||
|
|
||
|
ghmod = GetModuleHandle(NULL);
|
||
|
|
||
|
wc.style = 0;
|
||
|
wc.lpfnWndProc = (WNDPROC)DefWindowProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
wc.hInstance = ghmod;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = NULL;
|
||
|
wc.hbrBackground = NULL;
|
||
|
wc.lpszMenuName = NULL; /* Name of menu resource in .RC file. */
|
||
|
wc.lpszClassName = "WinClipWClass"; /* Name used in call to CreateWindow. */
|
||
|
|
||
|
if (RegisterClass(&wc) && (ghwndClip = CreateWindow( "WinClipWClass",
|
||
|
"ClipWindow", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL,
|
||
|
ghmod, NULL)) == NULL ) {
|
||
|
DoMessage( " winclip: Initialization failed!" );
|
||
|
}
|
||
|
#else
|
||
|
ghwndClip = NULL; //assign clipboard to this thread instead
|
||
|
#endif
|
||
|
|
||
|
gfmtArgType = RegisterClipboardFormat( "Z Arg Type" );
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
DeleteArg(
|
||
|
PFILE pFile,
|
||
|
int argType,
|
||
|
COL xStart,
|
||
|
LINE yStart,
|
||
|
COL xEnd,
|
||
|
COL yEnd
|
||
|
)
|
||
|
{
|
||
|
|
||
|
switch ( argType ) {
|
||
|
|
||
|
case STREAMARG:
|
||
|
DelStream(pFile, xStart, yStart, xEnd, yEnd);
|
||
|
break;
|
||
|
|
||
|
case LINEARG:
|
||
|
DelStream(pFile, 0, yStart, 0, yEnd);
|
||
|
break;
|
||
|
|
||
|
|
||
|
case BOXARG: {
|
||
|
LINE iLine;
|
||
|
|
||
|
for ( iLine = yStart; iLine < yEnd; iLine++ ) {
|
||
|
DelStream( pFile, xStart, iLine, xEnd, iLine );
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
InsertText(
|
||
|
PFILE pFile,
|
||
|
LPSTR pszText,
|
||
|
DWORD dwInsMode,
|
||
|
COL xStart,
|
||
|
LINE yStart
|
||
|
)
|
||
|
{
|
||
|
char ch;
|
||
|
int cchLine, cchText, cchCopy;
|
||
|
LPSTR pszNL;
|
||
|
char achLine[BUFLEN];
|
||
|
char achEnd[BUFLEN];
|
||
|
|
||
|
switch ( dwInsMode ) {
|
||
|
case STREAMARG:
|
||
|
/*
|
||
|
* Split current line,
|
||
|
* tack first line from buffer to end of new line
|
||
|
* put the new lines in file
|
||
|
* shove the last line to the beggining of the 2nd half of the line
|
||
|
*/
|
||
|
DPRINT( " Stream Paste" );
|
||
|
if ( *pszText == '\0' )
|
||
|
break;
|
||
|
|
||
|
|
||
|
pszNL = EndOfLine(pszText);
|
||
|
|
||
|
cchLine = GetLine( yStart, achLine, pFile );
|
||
|
|
||
|
if (cchLine < xStart)
|
||
|
cchLine = ExtendLine( achLine, cchLine, ' ', xStart );
|
||
|
|
||
|
cchText = (int)(pszNL - pszText);
|
||
|
if (xStart + cchText >= BUFLEN_MAX) {
|
||
|
cchText = BUFLEN_MAX - xStart;
|
||
|
pszNL = pszText + cchText;
|
||
|
}
|
||
|
|
||
|
strcpy( achEnd, &achLine[xStart] );
|
||
|
cchLine -= xStart;
|
||
|
|
||
|
CopyMemory( &achLine[xStart], pszText, cchText );
|
||
|
cchText += xStart;
|
||
|
achLine[cchText] = '\0';
|
||
|
|
||
|
|
||
|
while ( *pszNL ) {
|
||
|
PutLine( yStart++, achLine, pFile );
|
||
|
CopyLine( NULL, pFile, 0, 0, yStart );
|
||
|
|
||
|
pszText = EndOfBreak(pszNL);
|
||
|
pszNL = EndOfLine(pszText);
|
||
|
|
||
|
cchText = (int)(pszNL - pszText);
|
||
|
|
||
|
CopyMemory( achLine, pszText, cchText );
|
||
|
achLine[cchText] = '\0';
|
||
|
}
|
||
|
|
||
|
cchCopy = 0;
|
||
|
if (cchLine + cchText > BUFLEN_MAX) {
|
||
|
cchCopy = (cchLine + cchText) - BUFLEN_MAX;
|
||
|
cchLine = cchLine - cchCopy;
|
||
|
}
|
||
|
|
||
|
CopyMemory( &achLine[cchText], achEnd, cchLine );
|
||
|
achLine[cchLine+cchText] = '\0';
|
||
|
PutLine( yStart++, achLine, pFile );
|
||
|
|
||
|
if (cchCopy != 0) {
|
||
|
CopyLine( NULL, pFile, 0, 0, yStart );
|
||
|
CopyMemory( achLine, &achEnd[cchLine], cchCopy );
|
||
|
achLine[cchCopy] = '\0';
|
||
|
PutLine( yStart++, achLine, pFile);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BOXARG:
|
||
|
/*
|
||
|
* Insert the text as a block into the middle of each line.
|
||
|
* This could be tricky since we need to pad all short lines
|
||
|
* out with spaces to match the lenght of the longest line
|
||
|
* in the text.
|
||
|
*/
|
||
|
|
||
|
DPRINT( " Box Paste" );
|
||
|
while ( *pszText ) {
|
||
|
pszNL = EndOfLine(pszText);
|
||
|
|
||
|
cchLine = GetLine( yStart, achLine, pFile );
|
||
|
|
||
|
if (cchLine < xStart)
|
||
|
cchLine = ExtendLine( achLine, cchLine, ' ', xStart );
|
||
|
|
||
|
cchText = (int)(pszNL - pszText);
|
||
|
if (cchLine + cchText > BUFLEN_MAX)
|
||
|
cchText = BUFLEN_MAX - cchLine;
|
||
|
|
||
|
/* insert text in middle of line */
|
||
|
strcpy( achEnd, &achLine[xStart] );
|
||
|
CopyMemory( &achLine[xStart], pszText, cchText );
|
||
|
strcpy( &achLine[xStart + cchText], achEnd );
|
||
|
|
||
|
/* put line in file */
|
||
|
PutLine( yStart++, achLine, pFile );
|
||
|
|
||
|
pszText = EndOfBreak(pszNL);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LINEARG:
|
||
|
/*
|
||
|
* shove the lines in the buffer before the current line
|
||
|
*/
|
||
|
DPRINT( " Line Paste" );
|
||
|
while ( *pszText ) {
|
||
|
pszNL = EndOfLine(pszText);
|
||
|
ch = *pszNL;
|
||
|
*pszNL = '\0';
|
||
|
CopyLine( NULL, pFile, 0, 0, yStart );
|
||
|
PutLine( yStart++, pszText, pFile);
|
||
|
*pszNL = ch;
|
||
|
pszText = EndOfBreak(pszNL);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
LPSTR
|
||
|
EndOfLine(
|
||
|
LPSTR psz
|
||
|
)
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
c = 0;
|
||
|
while ( *psz && *psz != '\r' && *psz != '\n' && c++ < BUFLEN_MAX )
|
||
|
psz++;
|
||
|
|
||
|
return psz;
|
||
|
}
|
||
|
|
||
|
LPSTR
|
||
|
EndOfBreak(
|
||
|
LPSTR psz
|
||
|
)
|
||
|
{
|
||
|
char chSkip;
|
||
|
|
||
|
switch ( *psz ) {
|
||
|
case '\r':
|
||
|
chSkip = '\n';
|
||
|
break;
|
||
|
|
||
|
case '\n':
|
||
|
chSkip = '\r';
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return psz;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (*(++psz) == chSkip)
|
||
|
psz++;
|
||
|
|
||
|
return psz;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
ExtendLine(
|
||
|
LPSTR psz,
|
||
|
int cchLine,
|
||
|
char ch,
|
||
|
int cchTotal
|
||
|
)
|
||
|
{
|
||
|
|
||
|
if ( cchLine >= cchTotal )
|
||
|
return cchLine;
|
||
|
|
||
|
if (cchTotal > BUFLEN_MAX)
|
||
|
cchTotal = BUFLEN_MAX;
|
||
|
|
||
|
psz = &psz[cchLine];
|
||
|
|
||
|
while ( cchLine++ < cchTotal )
|
||
|
*psz++ = ch;
|
||
|
|
||
|
*psz = '\0';
|
||
|
|
||
|
return cchLine;
|
||
|
}
|