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

  1. /* File: D:\WACKER\tdll\termcpy.c (Created: 24-Jan-1994)
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 4 $
  7. * $Date: 5/09/01 4:38p $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. #include "stdtyp.h"
  12. #include "mc.h"
  13. #include "tdll.h"
  14. #include "htchar.h"
  15. #include "session.h"
  16. #include "backscrl.h"
  17. #include "assert.h"
  18. #include <emu\emu.h>
  19. #include "term.hh"
  20. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  21. * FUNCTION:
  22. * CopyMarkedTextFromTerminal
  23. *
  24. * DESCRIPTION:
  25. * Helper function that gets the marked region and passes the call
  26. * onto CopyTextFromTerminal().
  27. *
  28. * ARGUMENTS:
  29. * hSession - public session handle
  30. * ppv - pointer to a buffer pointer
  31. * pdwCnt - pointer to size variable
  32. * fIncludeLF - TRUE means include linefeeds.
  33. *
  34. * RETURNS:
  35. * BOOL
  36. *
  37. */
  38. BOOL CopyMarkedTextFromTerminal(const HSESSION hSession, void **ppv,
  39. DWORD *pdwCnt, const BOOL fIncludeLF)
  40. {
  41. BOOL fReturn;
  42. ECHAR *pechBuf;
  43. TCHAR *pszOutput;
  44. const HWND hwndTerm = sessQueryHwndTerminal(hSession);
  45. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
  46. fReturn = CopyTextFromTerminal(hSession, &hhTerm->ptBeg, &hhTerm->ptEnd,
  47. ppv, pdwCnt, fIncludeLF);
  48. pechBuf = *ppv;
  49. // Strip Out Any repeated Characters in the string
  50. StrCharStripDBCSString(pechBuf, (long)StrCharGetEcharByteCount(pechBuf), pechBuf);
  51. // hMem currently points to an array of ECHAR's, convert this to
  52. // TCHARS before giving the results to the caller.
  53. pszOutput = malloc((ULONG)StrCharGetEcharByteCount(pechBuf) + 1);
  54. CnvrtECHARtoMBCS(pszOutput, (ULONG)StrCharGetEcharByteCount(pechBuf) + 1,
  55. pechBuf,StrCharGetEcharByteCount(pechBuf)+1);//mrw:5/17/95
  56. *(pszOutput + StrCharGetEcharByteCount(pechBuf)) = ETEXT('\0');
  57. free(pechBuf);
  58. pechBuf = NULL;
  59. *ppv = pszOutput;
  60. *pdwCnt = (ULONG)StrCharGetByteCount(pszOutput);
  61. return fReturn;
  62. }
  63. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  64. * FUNCTION:
  65. * CopyTextFromTerminal
  66. *
  67. * DESCRIPTION:
  68. * A work-horse function that will use the given points as a marked region
  69. * and do the necessary work to make a copy of the marked text into
  70. * a new memory region. The marked range can include the backscroll
  71. * region and cross into the terminal region. The begining and ending
  72. * points are in terminal coordinates (backscroll lines are numbered
  73. * -1 to -infinity, terminal lines are numbered 1 to 24, line 0 is the
  74. * divider line and does not exist for copies but can be included in
  75. * the range). It is *not* a requirement that the begininig point be
  76. * less than the ending point.
  77. *
  78. * ARGUMENTS:
  79. * HSESSION hSession - handle to the session.
  80. * LPPOINT lpptBeg - begining point of marked region.
  81. * LPPOINT lpptEnd - end point of mark region.
  82. * void **pv - pointer to buffer pointer
  83. * DWORD *pdwCnt - pointer to double word for size
  84. * BOOL fIncludeLF -
  85. *
  86. * RETURNS:
  87. * BOOL
  88. *
  89. */
  90. BOOL CopyTextFromTerminal(const HSESSION hSession,
  91. const PPOINT pptBeg,
  92. const PPOINT pptEnd,
  93. void **ppv,
  94. DWORD *pdwCnt,
  95. const BOOL fIncludeLF)
  96. {
  97. int iWant,
  98. iGot,
  99. yLn,
  100. xCol,
  101. iLen,
  102. iTmp,
  103. iRows,
  104. iCols,
  105. iTopline,
  106. iOffset,
  107. iBkLns,
  108. iSize;
  109. DWORD dwSize, dwOldSize;
  110. ECHAR *lpachTxt;
  111. ECHAR *lpachBuf;
  112. ECHAR achTmp[256],
  113. *pachTmp;
  114. ECHAR **alpstrTxt;
  115. long lBeg, lEnd;
  116. HCURSOR hCursor;
  117. ECHAR *hMem = 0; // malloc memory
  118. ECHAR *hMemTmp = 0; // malloc memory
  119. POINT ptBeg, ptEnd, ptTmp;
  120. const HWND hwndTerm = sessQueryHwndTerminal(hSession);
  121. const HHTERM hhTerm = (HHTERM)GetWindowLongPtr(hwndTerm, GWLP_USERDATA);
  122. const HBACKSCRL hBackscrl = sessQueryBackscrlHdl(hhTerm->hSession);
  123. *ppv = 0;
  124. *pdwCnt = 0;
  125. hCursor = SetCursor(LoadCursor((HINSTANCE)0, IDC_WAIT));
  126. dwSize = 1; // By starting at one, we always have room for the '\0'.
  127. iRows = hhTerm->iRows;
  128. iCols = hhTerm->iCols;
  129. iTopline = hhTerm->iTopline;
  130. alpstrTxt = hhTerm->fplpstrTxt;
  131. ptBeg = *pptBeg;
  132. ptEnd = *pptEnd;
  133. /* --- do some range checking for the line number --- */
  134. iBkLns = backscrlGetNumLines(hBackscrl);
  135. iBkLns = -iBkLns;
  136. if (ptBeg.y > 0 && ptBeg.y > iRows)
  137. ptBeg.y = iRows;
  138. if (ptBeg.y < 0 && ptBeg.y < iBkLns)
  139. ptBeg.y = iBkLns;
  140. if (ptEnd.y > 0 && ptEnd.y > iRows)
  141. ptEnd.y = iRows;
  142. if (ptEnd.y < 0 && ptEnd.y < iBkLns)
  143. ptEnd.y = iBkLns;
  144. /* --- and do some range checking for the column number --- */
  145. if (ptBeg.x < 0) /* negative column doesn't make much sense */
  146. ptBeg.x = 0;
  147. if (ptBeg.x >= iCols)
  148. ptBeg.x = iCols - 1;
  149. if (ptEnd.x < 0) /* see above */
  150. ptEnd.x = 0;
  151. if (ptEnd.x >= iCols)
  152. ptEnd.x = iCols - 1;
  153. /* --- convert to offsets --- */
  154. lBeg = (ptBeg.y * iCols) + ptBeg.x;
  155. lEnd = (ptEnd.y * iCols) + ptEnd.x;
  156. if (lBeg == lEnd)
  157. {
  158. SetCursor(hCursor);
  159. return FALSE;
  160. }
  161. sessSetSuspend(hSession, SUSPEND_TERMINAL_COPY);
  162. if (lBeg > lEnd)
  163. {
  164. ptTmp = ptEnd;
  165. ptEnd = ptBeg;
  166. ptBeg = ptTmp;
  167. }
  168. if ((hMem = malloc(dwSize * sizeof(ECHAR))) == 0)
  169. {
  170. assert(FALSE);
  171. SetCursor(hCursor);
  172. sessClearSuspend(hSession, SUSPEND_TERMINAL_COPY);
  173. return FALSE;
  174. }
  175. // Get first line of range
  176. iGot = 0;
  177. lpachTxt = 0;
  178. achTmp[0] = ETEXT('\0');
  179. if (ptBeg.y < 0)
  180. {
  181. xCol = ptBeg.x;
  182. yLn = ptBeg.y;
  183. iWant = ptEnd.y - ptBeg.y + 1;
  184. if (iWant > 0)
  185. {
  186. while (iWant > 0)
  187. {
  188. if (backscrlGetBkLines(hBackscrl, yLn, iWant, &iGot,
  189. &lpachTxt, &iOffset) == FALSE)
  190. {
  191. goto PROCESS_ERROR;
  192. }
  193. lpachTxt += iOffset;
  194. // Lets say the user has highlighted an area of the backscroll
  195. // region that has no data (ie. a blank line). Adding xCol to
  196. // lpachTxt is incorrect. This for-loop checks for this
  197. // condition and resets lpachTxt to the beginning of the line.
  198. // Incidentally, this also sets xCol to 0 which is necessary
  199. // for subsequent lines to feed in correctly.
  200. for (lpachBuf = lpachTxt ; xCol > 0 ; --xCol, ++lpachTxt)
  201. {
  202. if (*lpachTxt == ETEXT('\n'))
  203. {
  204. lpachTxt = lpachBuf;
  205. xCol = 0;
  206. break;
  207. }
  208. }
  209. iWant -= iGot;
  210. while (iGot-- > 0 && yLn < ptEnd.y && yLn < -1)
  211. {
  212. for (pachTmp = achTmp, iTmp = 0 ;
  213. *lpachTxt != ETEXT('\n') &&
  214. //
  215. // Fix for not getting full backscroll buffer
  216. // in DBCS versions by taking into account the
  217. // size of the ECHAR. REV: 03/07/2001
  218. //
  219. iTmp < MAX_EMUCOLS * sizeof(ECHAR);
  220. ++pachTmp, ++iTmp)
  221. {
  222. *pachTmp = *lpachTxt++;
  223. }
  224. // Fail Safe: if the text we received from
  225. // backscrlGetBkLines() is mangled somehow and we
  226. // don't see a newline, then abort before we seg.
  227. //
  228. // Fix for not getting full backscroll buffer
  229. // in DBCS versions by taking into account the
  230. // size of the ECHAR. REV: 03/07/2001
  231. //
  232. if (iTmp >= MAX_EMUCOLS * sizeof(ECHAR))
  233. goto PROCESS_ERROR;
  234. lpachTxt += 1;
  235. *pachTmp++ = ETEXT('\r');
  236. if (fIncludeLF)
  237. *pachTmp++ = ETEXT('\n');
  238. *pachTmp = ETEXT('\0');
  239. hMemTmp = hMem;
  240. dwOldSize = dwSize - 1;
  241. dwSize += (DWORD)StrCharGetEcharLen(achTmp);
  242. hMem = realloc(hMemTmp, dwSize *sizeof(ECHAR));
  243. if (hMem == 0)
  244. goto PROCESS_ERROR;
  245. /* remember how a realloc works */
  246. hMemTmp = (ECHAR *)0;
  247. lpachBuf = hMem + dwOldSize;
  248. iSize = StrCharGetEcharByteCount(achTmp);
  249. if ( iSize )
  250. MemCopy(lpachBuf, achTmp, iSize );
  251. hMem[dwSize - 1] = ETEXT('\0');
  252. yLn += 1;
  253. }
  254. if (yLn >= ptEnd.y || yLn >= -1)
  255. break;
  256. }
  257. // Another bug bytes the dust. Wasn't checking to see if iGot
  258. // was the reason we exited the loop above. It caused things
  259. // to seg occassionally.
  260. if (iGot >= 0)
  261. {
  262. // Last line stuff (could be crossing into terminal area but
  263. // we still need to clean-up backscroll stuff.
  264. if (ptBeg.y == ptEnd.y)
  265. xCol = ptEnd.x - ptBeg.x;
  266. else if (ptEnd.y < 0) /* && ptEnd.x > 0) removed - mrw */
  267. xCol = ptEnd.x;
  268. else
  269. xCol = iCols;
  270. for (pachTmp = achTmp ; xCol-- > 0 && *lpachTxt != ETEXT('\n'); ++pachTmp)
  271. *pachTmp = *lpachTxt++;
  272. if (ptEnd.y >= 0)
  273. {
  274. *pachTmp++ = ETEXT('\r');
  275. if (fIncludeLF)
  276. *pachTmp++ = ETEXT('\n');
  277. }
  278. *pachTmp = ETEXT('\0');
  279. }
  280. hMemTmp = hMem;
  281. dwOldSize = dwSize - 1;
  282. dwSize += (DWORD)StrCharGetEcharLen(achTmp);
  283. hMem = realloc(hMemTmp, dwSize * sizeof(ECHAR));
  284. if (hMem == 0)
  285. goto PROCESS_ERROR;
  286. /* remember how a realloc works */
  287. hMemTmp = (ECHAR *)0;
  288. lpachBuf = hMem + dwOldSize;
  289. iSize = StrCharGetEcharByteCount(achTmp);
  290. if ( iSize )
  291. MemCopy(lpachBuf, achTmp, iSize);
  292. hMem[dwSize - 1] = ETEXT('\0');
  293. } // end if (iWant > 0)
  294. // terminal area...
  295. if (ptEnd.y >= 0)
  296. {
  297. yLn = 1;
  298. while (yLn <= ptEnd.y)
  299. {
  300. iTmp = ((yLn + iTopline) % MAX_EMUROWS) - 1;
  301. if (iTmp < 0)
  302. iTmp = MAX_EMUROWS - 1;
  303. lpachTxt = alpstrTxt[iTmp];
  304. iLen = strlentrunc(lpachTxt, iCols);
  305. xCol = (yLn == ptEnd.y) ? min(ptEnd.x, iLen) : iLen;
  306. for (pachTmp = achTmp ; xCol > 0 ; --xCol)
  307. *pachTmp++ = *lpachTxt++;
  308. if (yLn != ptEnd.y)
  309. {
  310. *pachTmp++ = ETEXT('\r');
  311. if (fIncludeLF)
  312. *pachTmp++ = ETEXT('\n');
  313. }
  314. *pachTmp = ETEXT('\0');
  315. hMemTmp = hMem;
  316. dwOldSize = dwSize - 1;
  317. dwSize += (DWORD)StrCharGetEcharLen(achTmp);
  318. hMem = realloc(hMemTmp, dwSize * sizeof(ECHAR));
  319. if (hMem == 0)
  320. goto PROCESS_ERROR;
  321. /* remember how a realloc works */
  322. hMemTmp = (ECHAR *)0;
  323. lpachBuf = hMem + dwOldSize;
  324. iSize = StrCharGetEcharByteCount(achTmp);
  325. if ( iSize )
  326. MemCopy(lpachBuf, achTmp, iSize );
  327. hMem[dwSize - 1] = ETEXT('\0');
  328. yLn += 1;
  329. }
  330. }
  331. }
  332. else // terminal only case
  333. {
  334. if (ptBeg.y >= 0)
  335. {
  336. yLn = ptBeg.y;
  337. while (yLn <= ptEnd.y)
  338. {
  339. iTmp = ((yLn + iTopline) % MAX_EMUROWS) - 1;
  340. if (iTmp < 0)
  341. iTmp = MAX_EMUROWS - 1;
  342. lpachTxt = alpstrTxt[iTmp];
  343. if (ptBeg.y == ptEnd.y)
  344. {
  345. lpachTxt += ptBeg.x;
  346. xCol = min(strlentrunc(lpachTxt, iCols - ptBeg.x),
  347. ptEnd.x - ptBeg.x);
  348. }
  349. else if (yLn == ptBeg.y)
  350. {
  351. lpachTxt += ptBeg.x;
  352. xCol = strlentrunc(lpachTxt, iCols - ptBeg.x);
  353. }
  354. else if (yLn == ptEnd.y)
  355. {
  356. xCol = min(ptEnd.x, strlentrunc(lpachTxt, iCols));
  357. }
  358. else
  359. {
  360. xCol = strlentrunc(lpachTxt, iCols);
  361. }
  362. for (pachTmp = achTmp ; xCol > 0 ; --xCol)
  363. *pachTmp++ = *lpachTxt++;
  364. if (yLn != ptEnd.y)
  365. {
  366. *pachTmp++ = ETEXT('\r');
  367. if (fIncludeLF)
  368. *pachTmp++ = ETEXT('\n');
  369. }
  370. *pachTmp = ETEXT('\0');
  371. hMemTmp = hMem;
  372. dwOldSize = dwSize - 1;
  373. dwSize += (DWORD)StrCharGetEcharLen(achTmp);
  374. hMem = realloc(hMemTmp, dwSize * sizeof(ECHAR));
  375. if (hMem == 0)
  376. goto PROCESS_ERROR;
  377. /* remember how a realloc works */
  378. hMemTmp = (ECHAR *)0;
  379. lpachBuf = hMem + dwOldSize;
  380. iSize = StrCharGetEcharByteCount(achTmp);
  381. if ( iSize )
  382. MemCopy(lpachBuf, achTmp, iSize );
  383. hMem[dwSize - 1] = ETEXT('\0');
  384. yLn += 1;
  385. }
  386. }
  387. }
  388. SetCursor(hCursor);
  389. *ppv = hMem;
  390. *pdwCnt = (ULONG)StrCharGetEcharByteCount(hMem);
  391. sessClearSuspend(hSession, SUSPEND_TERMINAL_COPY);
  392. return TRUE;
  393. // process error condition here.
  394. PROCESS_ERROR:
  395. if (hMem)
  396. {
  397. free(hMem);
  398. hMem = NULL;
  399. }
  400. if (hMemTmp)
  401. {
  402. free(hMemTmp);
  403. hMemTmp = NULL;
  404. }
  405. SetCursor(hCursor);
  406. sessClearSuspend(hSession, SUSPEND_TERMINAL_COPY);
  407. return 0;
  408. }
  409. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  410. * FUNCTION:
  411. * strlentrunc
  412. *
  413. * DESCRIPTION:
  414. * Finds the length of a character buffer less the trailing whitespace.
  415. *
  416. * ARGUMENTS:
  417. * pach - array of t characters
  418. * iLen - length of buffer
  419. *
  420. * RETURNS:
  421. * new length
  422. *
  423. */
  424. int strlentrunc(const ECHAR *pach, const int iLen)
  425. {
  426. int i;
  427. for (i = iLen-1 ; i >= 0 ; --i)
  428. {
  429. switch (pach[i])
  430. {
  431. /* Whitespace characters */
  432. case ETEXT('\0'):
  433. case ETEXT('\t'):
  434. case ETEXT('\n'):
  435. case ETEXT('\v'):
  436. case ETEXT('\f'):
  437. case ETEXT('\r'):
  438. case ETEXT(' '):
  439. break;
  440. default:
  441. return i+1;
  442. }
  443. }
  444. return 0;
  445. }