Source code of Windows XP (NT5)
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.

830 lines
22 KiB

  1. /*** winclip.c - windows clipboard editor extension
  2. *
  3. * Copyright <C> 1988, Microsoft Corporation
  4. *
  5. * Purpose:
  6. * Contains the tglcase function.
  7. *
  8. * Revision History:
  9. *
  10. * 28-Jun-1988 LN Created
  11. * 12-Sep-1988 mz Made WhenLoaded match declaration
  12. *
  13. *************************************************************************/
  14. #define EXT_ID " winclip ver 1.00 "##__DATE__
  15. #include <windows.h>
  16. #include <stdlib.h> /* min macro definition */
  17. #include <string.h> /* prototypes for string fcns */
  18. #undef pascal
  19. #include "../../inc/ext.h"
  20. #define M_FALSE ((flagType)0)
  21. #define M_TRUE ((flagType)(-1))
  22. #define BUFLEN_MAX (BUFLEN-1)
  23. /*
  24. ** Internal function prototypes
  25. */
  26. void pascal id (char *);
  27. void EXTERNAL WhenLoaded (void);
  28. flagType pascal EXTERNAL wincopy (unsigned int, ARG far *, flagType);
  29. flagType pascal EXTERNAL wincut (unsigned int, ARG far *, flagType);
  30. flagType pascal EXTERNAL winpaste (unsigned int, ARG far *, flagType);
  31. #ifdef DEBUG
  32. # define DPRINT(p) DoMessage(p)
  33. #else
  34. # define DPRINT(p)
  35. #endif
  36. HWND ghwndClip;
  37. HINSTANCE ghmod;
  38. int gfmtArgType;
  39. void DeleteArg( PFILE pFile, int argType, COL xStart, LINE yStart,
  40. COL xEnd, COL yEnd );
  41. void InsertText( PFILE pFile, LPSTR pszText, DWORD dwInsMode,
  42. COL xStart, LINE yStart );
  43. flagType pascal EXTERNAL WinCutCopy (ARG *pArg, flagType fCut, flagType fClip);
  44. LPSTR EndOfLine( LPSTR psz );
  45. LPSTR EndOfBreak( LPSTR psz );
  46. int ExtendLine( LPSTR psz, int cchSZ, char ch, int cchNew );
  47. /*************************************************************************
  48. **
  49. ** wincopy
  50. ** Toggle the case of alphabetics contaied within the selected argument:
  51. **
  52. ** NOARG - Toggle case of entire current line
  53. ** NULLARG - Toggle case of current line, from cursor to end of line
  54. ** LINEARG - Toggle case of range of lines
  55. ** BOXARG - Toggle case of characters with the selected box
  56. ** NUMARG - Converted to LINEARG before extension is called.
  57. ** MARKARG - Converted to Appropriate ARG form above before extension is
  58. ** called.
  59. **
  60. ** STREAMARG - Not Allowed. Treated as BOXARG
  61. ** TEXTARG - Not Allowed
  62. **
  63. */
  64. flagType pascal EXTERNAL wincopy (
  65. unsigned int argData, /* keystroke invoked with */
  66. ARG *pArg, /* argument data */
  67. flagType fMeta /* indicates preceded by meta */
  68. ) {
  69. return WinCutCopy( pArg, M_FALSE, M_FALSE );
  70. }
  71. flagType pascal EXTERNAL wincut (
  72. unsigned int argData, /* keystroke invoked with */
  73. ARG *pArg, /* argument data */
  74. flagType fMeta /* indicates preceded by meta */
  75. ) {
  76. return WinCutCopy( pArg, M_TRUE, fMeta );
  77. }
  78. flagType pascal EXTERNAL WinCutCopy (ARG *pArg, flagType fCut, flagType fNoClip)
  79. {
  80. PFILE pFile; /* file handle of current file */
  81. COL xStart, xEnd;
  82. LINE yStart, yEnd;
  83. char achLine[BUFLEN];
  84. HANDLE hText;
  85. LPSTR pszText;
  86. int iLine, cchLine;
  87. flagType fRet = M_TRUE;
  88. int argSave, argType;
  89. pFile = FileNameToHandle ("", "");
  90. argSave = argType = pArg->argType;
  91. switch( argType ) {
  92. case BOXARG: /* case switch box */
  93. xStart = pArg->arg.boxarg.xLeft;
  94. xEnd = pArg->arg.boxarg.xRight + 1;
  95. yStart = pArg->arg.boxarg.yTop;
  96. yEnd = pArg->arg.boxarg.yBottom + 1;
  97. /* At this point...
  98. * [xy]Start is Inclusive, [xy]End is EXCLUSIVE of the box arg
  99. */
  100. #ifdef DEBUG
  101. wsprintf( achLine, " BoxDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
  102. DoMessage( achLine );
  103. #endif
  104. break;
  105. case NOARG:
  106. /* convert NOARG to a STREAMARG on whole current line */
  107. argType = STREAMARG;
  108. argSave = LINEARG;
  109. xStart = 0;
  110. yStart = pArg->arg.noarg.y;
  111. xEnd = 0;
  112. yEnd = yStart + 1;
  113. break;
  114. case TEXTARG:
  115. /*
  116. * Text args are only for real text. NumArgs and MarkArgs are
  117. * converted to stream or box args by the editor since we say
  118. * we accept NUMARG and MARKARG during initialization.
  119. */
  120. argType = STREAMARG;
  121. argSave = STREAMARG;
  122. xStart = pArg->arg.textarg.x;
  123. xEnd = lstrlen(pArg->arg.textarg.pText) + xStart;
  124. yStart = yEnd = pArg->arg.textarg.y;
  125. break;
  126. case LINEARG: /* case switch line range */
  127. /* convert LINEARG to a STREAMARG so we don't get lots of white space*/
  128. argType = STREAMARG;
  129. xStart = 0;
  130. xEnd = 0;
  131. yStart = pArg->arg.linearg.yStart;
  132. yEnd = pArg->arg.linearg.yEnd + 1;
  133. #ifdef DEBUG
  134. wsprintf( achLine, " LineDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
  135. DoMessage( achLine );
  136. #endif
  137. /* At this point...
  138. * [xy]Start is Inclusive, [xy]End is EXCLUSIVE of the line arg
  139. */
  140. break;
  141. case STREAMARG:
  142. /*
  143. * Set Start == first char pos in stream, End == first char pos
  144. * AFTER stream.
  145. */
  146. xStart = pArg->arg.streamarg.xStart;
  147. xEnd = pArg->arg.streamarg.xEnd;
  148. yStart = pArg->arg.streamarg.yStart;
  149. yEnd = pArg->arg.streamarg.yEnd;
  150. #ifdef DEBUG
  151. wsprintf( achLine, " StreamDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
  152. DoMessage( achLine );
  153. #endif
  154. break;
  155. default:
  156. #ifdef DEBUG
  157. wsprintf( achLine, " Unknown Arg: 0x%04x", argType );
  158. DoMessage( achLine );
  159. return M_TRUE;
  160. #endif
  161. return M_FALSE;
  162. }
  163. if (!fNoClip) {
  164. if (argType == STREAMARG) {
  165. int cch = 0;
  166. int iChar;
  167. for( iLine = yStart; iLine <= yEnd; iLine++ )
  168. cch += GetLine (iLine, achLine, pFile) + 3;
  169. hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cch);
  170. if (hText == NULL) {
  171. DoMessage( " winclip: Out of Memory" );
  172. return M_FALSE;
  173. }
  174. pszText = GlobalLock(hText);
  175. iChar = xStart;
  176. for( iLine = yStart; iLine < yEnd; iLine++ ) {
  177. cchLine = GetLine (iLine, achLine, pFile);
  178. /* Incase we start after the end of the line */
  179. if (cchLine < iChar)
  180. cch = 0;
  181. else
  182. cch = cchLine - iChar;
  183. CopyMemory(pszText, &achLine[iChar], cch);
  184. pszText += cch;
  185. strcpy( pszText, "\r\n" );
  186. pszText += 2;
  187. iChar = 0;
  188. }
  189. /* Get partial last line */
  190. if (xEnd != 0) {
  191. cchLine = GetLine (iLine, achLine, pFile);
  192. /* if line is short, then pad it out */
  193. cchLine = ExtendLine( achLine, cchLine, ' ', xEnd );
  194. if (cchLine < iChar)
  195. cchLine = 0;
  196. else
  197. cchLine = xEnd - iChar;
  198. CopyMemory(pszText, &achLine[iChar], cchLine);
  199. pszText += cchLine;
  200. }
  201. } else {
  202. LINE iLine;
  203. int cchBox = xEnd - xStart;
  204. hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  205. (yEnd - yStart) * (cchBox + 3));
  206. if (hText == NULL) {
  207. DoMessage( " winclip: Out of Memory" );
  208. return M_FALSE;
  209. }
  210. pszText = GlobalLock(hText);
  211. for( iLine = yStart; iLine < yEnd; iLine++ ) {
  212. cchLine = GetLine (iLine, achLine, pFile);
  213. if (argType == BOXARG)
  214. cchLine = ExtendLine( achLine, cchLine, ' ', xEnd );
  215. if (cchLine < xStart )
  216. cchLine = 0;
  217. else
  218. cchLine -= xStart;
  219. cchLine = min(cchLine, cchBox);
  220. CopyMemory(pszText, &achLine[xStart], cchLine);
  221. pszText += cchLine;
  222. strcpy( pszText, "\r\n" );
  223. pszText += 2;
  224. }
  225. }
  226. *pszText = '\0';
  227. GlobalUnlock(hText);
  228. if (OpenClipboard(ghwndClip)) {
  229. EmptyClipboard();
  230. /*
  231. * Set the text into the clipboard
  232. */
  233. if (SetClipboardData(CF_TEXT, hText) == hText) {
  234. /*
  235. * Remember the Arg type for pasting back
  236. */
  237. if (gfmtArgType != 0) {
  238. DWORD *pdw;
  239. HANDLE hArgType = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  240. sizeof(DWORD));
  241. if (hArgType != NULL && (pdw = GlobalLock(hArgType)) != NULL) {
  242. *pdw = (DWORD)(argSave);
  243. GlobalUnlock(hArgType);
  244. SetClipboardData(gfmtArgType, hArgType);
  245. }
  246. }
  247. } else {
  248. /* An error occured writing text to clipboard */
  249. wsprintf(achLine, " winclip: Error (%ld) setting data",
  250. GetLastError());
  251. DoMessage( achLine );
  252. fRet = M_FALSE;
  253. }
  254. CloseClipboard();
  255. }
  256. }
  257. /*
  258. * No need to free the handle, USER32 will do it (yes it keeps
  259. * track of the client side handle) when we set the next clipboard
  260. * data. (Love that Win3.1 compatibility!)
  261. */
  262. if (fRet && fCut)
  263. DeleteArg( pFile, argType, xStart, yStart, xEnd, yEnd );
  264. return fRet;
  265. }
  266. /*************************************************************************
  267. **
  268. ** winpaste
  269. ** Toggle the case of alphabetics contaied within the selected argument:
  270. **
  271. ** NOARG - Toggle case of entire current line
  272. ** NULLARG - Toggle case of current line, from cursor to end of line
  273. ** LINEARG - Toggle case of range of lines
  274. ** BOXARG - Toggle case of characters with the selected box
  275. ** NUMARG - Converted to LINEARG before extension is called.
  276. ** MARKARG - Converted to Appropriate ARG form above before extension is
  277. ** called.
  278. **
  279. ** STREAMARG - Not Allowed. Treated as BOXARG
  280. ** TEXTARG - Not Allowed
  281. **
  282. */
  283. flagType pascal EXTERNAL winpaste (
  284. unsigned int argData, /* keystroke invoked with */
  285. ARG *pArg, /* argument data */
  286. flagType fMeta /* indicates preceded by meta */
  287. )
  288. {
  289. PFILE pFile; /* file handle of current file */
  290. COL xStart, xEnd;
  291. LINE yStart, yEnd;
  292. int argType;
  293. UINT fmtData = CF_TEXT;
  294. DWORD dwInsMode = STREAMARG;
  295. HANDLE hText;
  296. LPSTR pszText;
  297. /*
  298. * Get the clipboard text and insertion type
  299. */
  300. if (pArg->argType == TEXTARG) {
  301. int i, j;
  302. char achLine[3 + 1 + 3 + 1 + 1 + BUFLEN + 1 + 1 + 5 + 1];
  303. char *p;
  304. /*
  305. * Quick hack to make text arg pastes work like the do in MEP
  306. */
  307. j = pArg->arg.textarg.cArg;
  308. if (j > 2)
  309. j = 2;
  310. achLine[0] = '\0';
  311. for( i = 0; i < j; i++ )
  312. lstrcat(achLine, "arg ");
  313. p = achLine + lstrlen(achLine);
  314. wsprintf( p, "\"%s\" paste", pArg->arg.textarg.pText );
  315. return fExecute( achLine );
  316. }
  317. /* if no text then return FALSE */
  318. if (!IsClipboardFormatAvailable(fmtData)) {
  319. /* No text, try display text */
  320. fmtData = CF_DSPTEXT;
  321. if (!IsClipboardFormatAvailable(fmtData)) {
  322. /* bummer! no text at all, return FALSE */
  323. DoMessage( " winclip: invalid clipboard format" );
  324. return M_FALSE;
  325. }
  326. }
  327. if (!OpenClipboard(ghwndClip))
  328. return M_FALSE;
  329. hText = GetClipboardData(fmtData);
  330. if (hText == NULL || (pszText = GlobalLock(hText)) == NULL) {
  331. CloseClipboard();
  332. return M_FALSE;
  333. }
  334. /* Get insert mode */
  335. if (IsClipboardFormatAvailable(gfmtArgType)) {
  336. DWORD *pdw;
  337. HANDLE hInsMode;
  338. hInsMode = GetClipboardData(gfmtArgType);
  339. if (hInsMode != NULL && (pdw = GlobalLock(hInsMode)) != NULL) {
  340. dwInsMode = *pdw;
  341. GlobalUnlock(hInsMode);
  342. }
  343. }
  344. pFile = FileNameToHandle ("", "");
  345. argType = pArg->argType;
  346. switch( argType ) {
  347. case BOXARG: /* case switch box */
  348. /*
  349. * Set [xy]Start inclusive of box arg,
  350. * [xy]End exclusive of box arg.
  351. */
  352. xStart = pArg->arg.boxarg.xLeft;
  353. xEnd = pArg->arg.boxarg.xRight + 1;
  354. yStart = pArg->arg.boxarg.yTop;
  355. yEnd = pArg->arg.boxarg.yBottom + 1;
  356. break;
  357. case LINEARG: /* case switch line range */
  358. /*
  359. * Set [xy]Start inclusive of line arg,
  360. * [xy]End exclusive of line arg.
  361. */
  362. xStart = 0;
  363. xEnd = BUFLEN + 1;
  364. yStart = pArg->arg.linearg.yStart;
  365. yEnd = pArg->arg.linearg.yEnd + 1;
  366. break;
  367. case STREAMARG:
  368. /*
  369. * Set [xy]Start inclusive of stream
  370. * xEnd is EXCLUSIVE of stream
  371. * yEnd is INCLUSIVE of stream
  372. */
  373. xStart = pArg->arg.streamarg.xStart;
  374. xEnd = pArg->arg.streamarg.xEnd;
  375. yStart = pArg->arg.streamarg.yStart;
  376. yEnd = pArg->arg.streamarg.yEnd;
  377. break;
  378. case NOARG:
  379. xStart = pArg->arg.noarg.x;
  380. xEnd = xStart + 1;
  381. yStart = pArg->arg.noarg.y;
  382. yEnd = yStart + 1;
  383. break;
  384. default:
  385. GlobalUnlock(hText);
  386. CloseClipboard();
  387. return M_FALSE;
  388. }
  389. /*
  390. * Delete any selection
  391. */
  392. DeleteArg( pFile, argType, xStart, yStart, xEnd, yEnd );
  393. /*
  394. * Insert new text with correct mode
  395. */
  396. InsertText( pFile, pszText, dwInsMode, xStart, yStart );
  397. GlobalUnlock(hText);
  398. CloseClipboard();
  399. return M_TRUE;
  400. }
  401. /*************************************************************************
  402. **
  403. ** windel
  404. **
  405. **
  406. */
  407. flagType pascal EXTERNAL windel (
  408. unsigned int argData, /* keystroke invoked with */
  409. ARG *pArg, /* argument data */
  410. flagType fMeta /* indicates preceded by meta */
  411. )
  412. {
  413. int argType = pArg->argType;
  414. if (argType == NOARG)
  415. return fExecute("delete");
  416. if (argType == NULLARG) {
  417. int c, x, y;
  418. c = pArg->arg.nullarg.cArg;
  419. x = pArg->arg.nullarg.x;
  420. y = pArg->arg.nullarg.y;
  421. pArg->argType = STREAMARG;
  422. pArg->arg.streamarg.xStart = x;
  423. pArg->arg.streamarg.xEnd = 0;
  424. pArg->arg.streamarg.yStart = y;
  425. pArg->arg.streamarg.yEnd = y + 1;
  426. pArg->arg.streamarg.cArg = c;
  427. }
  428. return WinCutCopy (pArg, M_TRUE, fMeta);
  429. }
  430. /*************************************************************************
  431. **
  432. ** WhenLoaded
  433. ** Executed when extension gets loaded. Identify self & assign default
  434. ** keystroke.
  435. **
  436. ** Entry:
  437. ** none
  438. */
  439. void EXTERNAL WhenLoaded () {
  440. #if 0
  441. WNDCLASS wc;
  442. ghmod = GetModuleHandle(NULL);
  443. wc.style = 0;
  444. wc.lpfnWndProc = (WNDPROC)DefWindowProc;
  445. wc.cbClsExtra = 0;
  446. wc.cbWndExtra = 0;
  447. wc.hInstance = ghmod;
  448. wc.hIcon = NULL;
  449. wc.hCursor = NULL;
  450. wc.hbrBackground = NULL;
  451. wc.lpszMenuName = NULL; /* Name of menu resource in .RC file. */
  452. wc.lpszClassName = "WinClipWClass"; /* Name used in call to CreateWindow. */
  453. if (RegisterClass(&wc) && (ghwndClip = CreateWindow( "WinClipWClass",
  454. "ClipWindow", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL,
  455. ghmod, NULL)) != NULL ) {
  456. id(" Windows Clipboard Extentions for MEP,");
  457. } else {
  458. DoMessage( " winclip: Initialization failed!" );
  459. }
  460. #else
  461. ghwndClip = NULL; //assign clipboard to this thread instead
  462. #endif
  463. gfmtArgType = RegisterClipboardFormat( "MEP Arg Type" );
  464. #if 0
  465. //SetKey ("wincut", "ctrl+x");
  466. SetKey ("wincopy", "ctrl+c");
  467. SetKey ("winpaste", "ctrl+v");
  468. #endif
  469. }
  470. /*************************************************************************
  471. **
  472. ** id
  473. ** identify ourselves, along with any passed informative message.
  474. **
  475. ** Entry:
  476. ** pszMsg = Pointer to asciiz message, to which the extension name
  477. ** and version are appended prior to display.
  478. */
  479. void pascal id (char *pszFcn) {
  480. char buf[80];
  481. strcpy (buf,pszFcn);
  482. strcat (buf,EXT_ID);
  483. DoMessage (buf);
  484. }
  485. /*************************************************************************
  486. **
  487. ** Switch communication table to the editor.
  488. ** This extension defines no switches.
  489. */
  490. struct swiDesc swiTable[] = {
  491. {0, 0, 0}
  492. };
  493. /*************************************************************************
  494. **
  495. ** Command communication table to the editor.
  496. ** Defines the name, location and acceptable argument types.
  497. */
  498. struct cmdDesc cmdTable[] = {
  499. {"wincopy", (funcCmd) wincopy, 0, KEEPMETA | NOARG | BOXARG | LINEARG | STREAMARG | MARKARG | NULLEOL | NUMARG },
  500. {"wincut", (funcCmd) wincut, 0, NOARG | BOXARG | LINEARG | STREAMARG | MARKARG | NULLEOL | NUMARG | MODIFIES},
  501. {"windel", (funcCmd) windel, 0, NOARG | BOXARG | LINEARG | STREAMARG | NULLARG | MODIFIES},
  502. {"winpaste", (funcCmd) winpaste,0, KEEPMETA | NOARG | BOXARG | LINEARG | STREAMARG | TEXTARG | MODIFIES},
  503. {0, 0, 0}
  504. };
  505. void DeleteArg( PFILE pFile, int argType, COL xStart, LINE yStart,
  506. COL xEnd, COL yEnd ) {
  507. switch( argType ) {
  508. case STREAMARG:
  509. DelStream(pFile, xStart, yStart, xEnd, yEnd);
  510. break;
  511. case LINEARG:
  512. DelStream(pFile, 0, yStart, 0, yEnd);
  513. break;
  514. case BOXARG: {
  515. LINE iLine;
  516. for( iLine = yStart; iLine < yEnd; iLine++ ) {
  517. DelStream( pFile, xStart, iLine, xEnd, iLine );
  518. }
  519. break;
  520. }
  521. default:
  522. break;
  523. }
  524. }
  525. void InsertText( PFILE pFile, LPSTR pszText, DWORD dwInsMode, COL xStart,
  526. LINE yStart ) {
  527. char ch;
  528. int cchLine, cchText, cchCopy;
  529. LPSTR pszNL;
  530. char achLine[BUFLEN];
  531. char achEnd[BUFLEN];
  532. switch( dwInsMode ) {
  533. case STREAMARG:
  534. /*
  535. * Split current line,
  536. * tack first line from buffer to end of new line
  537. * put the new lines in file
  538. * shove the last line to the beggining of the 2nd half of the line
  539. */
  540. DPRINT( " Stream Paste" );
  541. if ( *pszText == '\0' )
  542. break;
  543. pszNL = EndOfLine(pszText);
  544. cchLine = GetLine( yStart, achLine, pFile );
  545. if (cchLine < xStart)
  546. cchLine = ExtendLine( achLine, cchLine, ' ', xStart );
  547. cchText = (int)(pszNL - pszText);
  548. if (xStart + cchText >= BUFLEN_MAX) {
  549. cchText = BUFLEN_MAX - xStart;
  550. pszNL = pszText + cchText;
  551. }
  552. strcpy( achEnd, &achLine[xStart] );
  553. cchLine -= xStart;
  554. CopyMemory( &achLine[xStart], pszText, cchText );
  555. cchText += xStart;
  556. achLine[cchText] = '\0';
  557. while( *pszNL ) {
  558. PutLine( yStart++, achLine, pFile );
  559. CopyLine( NULL, pFile, 0, 0, yStart );
  560. pszText = EndOfBreak(pszNL);
  561. pszNL = EndOfLine(pszText);
  562. cchText = (int)(pszNL - pszText);
  563. CopyMemory( achLine, pszText, cchText );
  564. achLine[cchText] = '\0';
  565. }
  566. cchCopy = 0;
  567. if (cchLine + cchText > BUFLEN_MAX) {
  568. cchCopy = (cchLine + cchText) - BUFLEN_MAX;
  569. cchLine = cchLine - cchCopy;
  570. }
  571. CopyMemory( &achLine[cchText], achEnd, cchLine );
  572. achLine[cchLine+cchText] = '\0';
  573. PutLine( yStart++, achLine, pFile );
  574. if (cchCopy != 0) {
  575. CopyLine( NULL, pFile, 0, 0, yStart );
  576. CopyMemory( achLine, &achEnd[cchLine], cchCopy );
  577. achLine[cchCopy] = '\0';
  578. PutLine( yStart++, achLine, pFile);
  579. }
  580. break;
  581. case BOXARG:
  582. /*
  583. * Insert the text as a block into the middle of each line.
  584. * This could be tricky since we need to pad all short lines
  585. * out with spaces to match the lenght of the longest line
  586. * in the text.
  587. */
  588. DPRINT( " Box Paste" );
  589. while( *pszText ) {
  590. pszNL = EndOfLine(pszText);
  591. cchLine = GetLine( yStart, achLine, pFile );
  592. if (cchLine < xStart)
  593. cchLine = ExtendLine( achLine, cchLine, ' ', xStart );
  594. cchText = (int)(pszNL - pszText);
  595. if (cchLine + cchText > BUFLEN_MAX)
  596. cchText = BUFLEN_MAX - cchLine;
  597. /* insert text in middle of line */
  598. strcpy( achEnd, &achLine[xStart] );
  599. CopyMemory( &achLine[xStart], pszText, cchText );
  600. strcpy( &achLine[xStart + cchText], achEnd );
  601. /* put line in file */
  602. PutLine( yStart++, achLine, pFile );
  603. pszText = EndOfBreak(pszNL);
  604. }
  605. break;
  606. case LINEARG:
  607. /*
  608. * shove the lines in the buffer before the current line
  609. */
  610. DPRINT( " Line Paste" );
  611. while( *pszText ) {
  612. pszNL = EndOfLine(pszText);
  613. ch = *pszNL;
  614. *pszNL = '\0';
  615. CopyLine( NULL, pFile, 0, 0, yStart );
  616. PutLine( yStart++, pszText, pFile);
  617. *pszNL = ch;
  618. pszText = EndOfBreak(pszNL);
  619. }
  620. break;
  621. default:
  622. break;
  623. }
  624. }
  625. LPSTR EndOfLine( LPSTR psz ) {
  626. int c;
  627. c = 0;
  628. while( *psz && *psz != '\r' && *psz != '\n' && c++ < BUFLEN_MAX )
  629. psz++;
  630. return psz;
  631. }
  632. LPSTR EndOfBreak( LPSTR psz ) {
  633. char chSkip;
  634. switch( *psz ) {
  635. case '\r':
  636. chSkip = '\n';
  637. break;
  638. case '\n':
  639. chSkip = '\r';
  640. break;
  641. default:
  642. return psz;
  643. }
  644. if (*(++psz) == chSkip)
  645. psz++;
  646. return psz;
  647. }
  648. int ExtendLine( LPSTR psz, int cchLine, char ch, int cchTotal ) {
  649. if ( cchLine >= cchTotal )
  650. return cchLine;
  651. if (cchTotal > BUFLEN_MAX)
  652. cchTotal = BUFLEN_MAX;
  653. psz = &psz[cchLine];
  654. while( cchLine++ < cchTotal )
  655. *psz++ = ch;
  656. *psz = '\0';
  657. return cchLine;
  658. }