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.

1639 lines
47 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * EDITEC.C
  8. * Win16 edit control code
  9. *
  10. * History:
  11. *
  12. * Created 28-May-1991 by Jeff Parsons (jeffpar)
  13. * Copied from WIN31 and edited (as little as possible) for WOW16.
  14. --*/
  15. /****************************************************************************/
  16. /* editec.c - Edit controls rewrite. Version II of edit controls. */
  17. /* */
  18. /* */
  19. /* Created: 24-Jul-88 davidds */
  20. /****************************************************************************/
  21. /* Warning: The single line editcontrols contain internal styles and API which
  22. * are need to support comboboxes. They are defined in combcom.h/combcom.inc
  23. * and may be redefined or renumbered as needed.
  24. */
  25. #define NO_LOCALOBJ_TAGS
  26. #include "user.h"
  27. #include "edit.h"
  28. /****************************************************************************/
  29. /* Handlers common to both single and multi line edit controls. */
  30. /****************************************************************************/
  31. LONG FAR PASCAL ECTabTheTextOut(hdc, x, y, lpstring, nCount, ped, iTabOrigin,
  32. fDrawTheText)
  33. HDC hdc;
  34. int x;
  35. int y;
  36. register int nCount; /* Count of chars in string */
  37. LPSTR lpstring;
  38. register PED ped;
  39. int iTabOrigin; /* Tab stops are with respect to this */
  40. BOOL fDrawTheText;
  41. /* effects: Outputs the tabbed text if fDrawTheText is TRUE and returns the
  42. * textextent of the tabbed text. This is a local function for edit control
  43. * use so that it can be optimized for speed.
  44. */
  45. {
  46. int nTabPositions; /* Count of tabstops in tabstop array */
  47. LPINT lpintTabStopPositions; /* Tab stop positions in pixels */
  48. int initialx = x; /* Save the initial x value so that we can get
  49. total width of the string */
  50. int cch;
  51. int textextent;
  52. int pixeltabstop = 0;
  53. int i;
  54. int cxCharWidth;
  55. int cyCharHeight = 0;
  56. RECT rc;
  57. BOOL fOpaque = GetBkMode(hdc) == OPAQUE;
  58. PINT charWidthBuff;
  59. if (!lpstring || !nCount)
  60. return(MAKELONG(0,0));
  61. nTabPositions = (ped->pTabStops ? *(ped->pTabStops) : 0);
  62. lpintTabStopPositions = (LPINT)(ped->pTabStops ? (ped->pTabStops+1): NULL);
  63. cxCharWidth = ped->aveCharWidth;
  64. cyCharHeight = ped->lineHeight;
  65. /* If no tabstop positions are specified, then use a default of 8 system
  66. * font ave char widths or use the single fixed tab stop.
  67. */
  68. if (!lpintTabStopPositions)
  69. pixeltabstop = 8*cxCharWidth;
  70. else
  71. {
  72. if (nTabPositions == 1)
  73. {
  74. pixeltabstop = lpintTabStopPositions[0];
  75. if (!pixeltabstop)
  76. pixeltabstop=1;
  77. }
  78. }
  79. rc.left = initialx;
  80. rc.top = y;
  81. rc.bottom = rc.top+cyCharHeight;
  82. while(nCount)
  83. {
  84. if (ped->charWidthBuffer)
  85. {
  86. charWidthBuff = (PINT)LMHtoP(ped->charWidthBuffer);
  87. textextent=0;
  88. /* Initially assume no tabs exist in the text so cch=nCount.
  89. */
  90. cch = nCount;
  91. for (i=0; i<nCount; i++)
  92. {
  93. /* Warning danger. We gotta be careful here and convert lpstr
  94. * (which is a SIGNED char) into an unsigned char before using
  95. * it to index into the array otherwise the C Compiler screws
  96. * us and gives a negative number...
  97. */
  98. #ifdef FE_SB
  99. if (ECIsDBCSLeadByte(ped,lpstring[i])
  100. && i+1 < nCount) {
  101. textextent += LOWORD(GetTextExtent(hdc,&lpstring[i],2));
  102. i++;
  103. } else if (lpstring[i] == TAB ){
  104. cch = i;
  105. break;
  106. } else
  107. textextent += (charWidthBuff[(WORD)(((unsigned char FAR *)lpstring)[i])]);
  108. #else
  109. if (lpstring[i] == TAB)
  110. {
  111. cch = i;
  112. break;
  113. }
  114. textextent += (charWidthBuff[(WORD)(((unsigned char FAR *)lpstring)[i])]);
  115. #endif
  116. }
  117. nCount = nCount - cch;
  118. }
  119. else
  120. {
  121. /* Gotta call the driver to do our text extent.
  122. */
  123. cch = (int)ECFindTab(lpstring, nCount);
  124. nCount = nCount - cch;
  125. textextent = LOWORD(GetTextExtent(hdc, lpstring, cch));
  126. }
  127. if (fDrawTheText)
  128. {
  129. /* Output all text up to the tab (or end of string) and get its
  130. * extent.
  131. */
  132. rc.right = x+LOWORD(textextent);
  133. ExtTextOut(hdc,x, y, (fOpaque ? ETO_OPAQUE : 0),
  134. (LPRECT)&rc, lpstring, cch, 0L);
  135. rc.left = rc.right;
  136. }
  137. if (!nCount)
  138. /* If we're at the end of the string, just return without bothering
  139. * to calc next tab stop.
  140. */
  141. return(MAKELONG(LOWORD(textextent)+(x-initialx),cyCharHeight));
  142. /* Find the next tab position and update the x value.
  143. */
  144. if (pixeltabstop)
  145. x = (((x-iTabOrigin+LOWORD(textextent))/pixeltabstop)*pixeltabstop)+
  146. pixeltabstop + iTabOrigin;
  147. else
  148. {
  149. x += LOWORD(textextent);
  150. for (i=0; i < nTabPositions; i++)
  151. {
  152. if (x < (lpintTabStopPositions[i] + iTabOrigin))
  153. {
  154. x = (lpintTabStopPositions[i] + iTabOrigin);
  155. break;
  156. }
  157. }
  158. /* Check if all the tabstops set are exhausted; Then start using
  159. * default tab stop positions.
  160. */
  161. if (i == nTabPositions)
  162. {
  163. pixeltabstop = 8 * cxCharWidth;
  164. x = ((x - iTabOrigin)/pixeltabstop)*pixeltabstop +
  165. pixeltabstop + iTabOrigin;
  166. }
  167. }
  168. /* Skip over the tab and the characters we just drew.
  169. */
  170. lpstring += (cch+1);
  171. nCount--; /* Skip over tab */
  172. if (!nCount && fDrawTheText)
  173. {
  174. /* This string ends with a tab. We need to opaque the rect produced
  175. * by this tab...
  176. */
  177. rc.right = x;
  178. ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE,
  179. (LPRECT)&rc, "", 0, 0L);
  180. }
  181. }
  182. return(MAKELONG((x-initialx), cyCharHeight));
  183. }
  184. ICH FAR PASCAL ECCchInWidth(ped, hdc, lpText, cch, width)
  185. register PED ped;
  186. HDC hdc;
  187. LPSTR lpText;
  188. register ICH cch;
  189. unsigned int width;
  190. /* effects: Returns maximum count of characters (up to cch) from the given
  191. * string which will fit in the given width. ie. Will tell you how much of
  192. * lpstring will fit in the given width even when using proportional
  193. * characters. WARNING: If we use kerning, then this loses...
  194. */
  195. {
  196. int stringExtent;
  197. int cchhigh;
  198. int cchnew = 0;
  199. int cchlow = 0;
  200. if ((width<=0) || !cch)
  201. return(0);
  202. /* Optimize nonproportional fonts for single line ec since they don't have
  203. * tabs.
  204. */
  205. if (ped->fNonPropFont && ped->fSingle)
  206. /* umin is unsigned min function */
  207. return(umin(width/ped->aveCharWidth,cch));
  208. /* Check if password hidden chars are being used. */
  209. if (ped->charPasswordChar)
  210. return(umin(width/ped->cPasswordCharWidth,cch));
  211. cchhigh = cch+1;
  212. while (cchlow < cchhigh-1)
  213. {
  214. cchnew = umax((cchhigh - cchlow)/2,1)+cchlow;
  215. if (ped->fSingle)
  216. stringExtent = LOWORD(GetTextExtent(hdc, (LPSTR)lpText, cchnew));
  217. else
  218. stringExtent = LOWORD(ECTabTheTextOut(hdc, 0, 0,
  219. (LPSTR)lpText,
  220. cchnew,
  221. ped, 0, FALSE));
  222. if (stringExtent > width)
  223. cchhigh = cchnew;
  224. else
  225. cchlow = cchnew;
  226. }
  227. #ifdef FE_SB
  228. cchlow = ECAdjustIch( ped, lpText, cchlow );
  229. #endif
  230. return(cchlow);
  231. }
  232. ICH FAR PASCAL ECFindTab(lpstr, cch)
  233. LPSTR lpstr;
  234. register ICH cch;
  235. /* effects: Scans lpstr and returns the number of chars till the first TAB.
  236. * Scans at most cch chars of lpstr.
  237. */
  238. {
  239. LPSTR copylpstr = lpstr;
  240. if (!cch)
  241. return(0);
  242. while (*lpstr != TAB)
  243. {
  244. lpstr++;
  245. if (--cch == 0)
  246. break;
  247. }
  248. return((ICH)(lpstr - copylpstr));
  249. }
  250. BOOL NEAR _fastcall ECIsDelimiter(char bCharVal)
  251. {
  252. return((bCharVal == ' ') || (bCharVal == '\t'));
  253. }
  254. LONG FAR PASCAL ECWord(ped, ichStart, fLeft)
  255. PED ped; /* Yes, I mean no register ped */
  256. ICH ichStart;
  257. BOOL fLeft;
  258. /* effects: if fLeft Returns the ichMinSel and ichMaxSel of the word to the
  259. * left of ichStart. ichMinSel contains the starting letter of the word,
  260. * ichmaxsel contains all spaces up to the first character of the next word.
  261. *
  262. * if !fLeft Returns the ichMinSel and ichMaxSel of the word to the right of
  263. * ichStart. ichMinSel contains the starting letter of the word, ichmaxsel
  264. * contains the first letter of the next word. If ichStart is in the middle
  265. * of a word, that word is considered the left or right word. ichMinSel is in
  266. * the low order word and ichMaxSel is in the high order word. ichMinSel is
  267. * in the low order word and ichMaxSel is in the high order word. A CR LF
  268. * pair or CRCRLF triple is considered a single word for the purposes of
  269. * multiline edit controls.
  270. */
  271. {
  272. PSTR pText;
  273. register PSTR pWordMinSel;
  274. register PSTR pWordMaxSel;
  275. BOOL charLocated=FALSE;
  276. BOOL spaceLocated=FALSE;
  277. #ifdef FE_SB
  278. PSTR pWordStr;
  279. BOOL fAlpha = FALSE;
  280. #endif
  281. if ((!ichStart && fLeft) || (ichStart == ped->cch && !fLeft))
  282. /* We are at the beginning of the text (looking left) or we are at end
  283. * of text (looking right), no word here
  284. */
  285. return(0L);
  286. pText = (PSTR) LocalLock(ped->hText);
  287. pWordMinSel = pWordMaxSel = pText+ichStart;
  288. /* if fLeft: Move pWordMinSel to the left looking for the start of a word.
  289. * If we start at a space, we will include spaces in the selection as we
  290. * move left untill we find a nonspace character. At that point, we continue
  291. * looking left until we find a space. Thus, the selection will consist of
  292. * a word with its trailing spaces or, it will consist of any leading at the
  293. * beginning of a line of text.
  294. */
  295. /* if !fLeft: (ie. right word) Move pWordMinSel looking for the start of a
  296. * word. If the pWordMinSel points to a character, then we move left
  297. * looking for a space which will signify the start of the word. If
  298. * pWordMinSel points to a space, we look right till we come upon a
  299. * character. pMaxWord will look right starting at pMinWord looking for the
  300. * end of the word and its trailing spaces.
  301. */
  302. #ifdef FE_SB
  303. if (fLeft || (!ECIsDelimiter(*pWordMinSel) && *pWordMinSel != 0x0D && !ECIsDBCSLeadByte(ped,*pWordMinSel)))
  304. #else
  305. if (fLeft || (!ECIsDelimiter(*pWordMinSel) && *pWordMinSel != 0x0D))
  306. #endif
  307. /* If we are moving left or if we are moving right and we are not on a
  308. * space or a CR (the start of a word), then we was look left for the
  309. * start of a word which is either a CR or a character. We do this by
  310. * looking left till we find a character (or if CR we stop), then we
  311. * continue looking left till we find a space or LF.
  312. */
  313. {
  314. #ifdef FE_SB
  315. while (pWordMinSel > pText &&
  316. ((!ECIsDelimiter(*(pWordStr=(PSTR)LOWORD(ECAnsiPrev(ped,pText,pWordMinSel)))) && *pWordStr != 0x0A) ||
  317. !charLocated)) /* FE_SB */
  318. { /* FE_SB */
  319. if (!fLeft && /* FE_SB */
  320. (ECIsDelimiter(*(pWordStr=ECAnsiPrev(ped,pText,pWordMinSel))) || /* FE_SB */
  321. *pWordStr == 0x0A)) /* FE_SB */
  322. #else
  323. while (pWordMinSel > pText &&
  324. ((!ECIsDelimiter(*(pWordMinSel-1)) && *(pWordMinSel-1) != 0x0A) ||
  325. !charLocated))
  326. {
  327. if (!fLeft &&
  328. (ECIsDelimiter(*(pWordMinSel-1)) ||
  329. *(pWordMinSel-1) == 0x0A))
  330. #endif
  331. /*
  332. * If we are looking for the start of the word right, then we
  333. * stop when we have found it. (needed in case charLocated is
  334. * still FALSE)
  335. */
  336. break;
  337. #ifdef FE_SB
  338. if( !ECIsDBCSLeadByte(ped,*pWordMinSel) && !ECIsDelimiter(*pWordMinSel) &&
  339. *pWordMinSel != 0x0d && *pWordMinSel != 0x0a &&
  340. pWordMinSel != pText+ichStart )
  341. fAlpha = TRUE;
  342. #endif
  343. #ifdef FE_SB
  344. pWordMinSel = ECAnsiPrev(ped,pText,pWordMinSel);
  345. #else
  346. pWordMinSel--;
  347. #endif
  348. #ifdef FE_SB
  349. if( ECIsDBCSLeadByte(ped, *pWordMinSel ) ){
  350. if( !fLeft || fAlpha )
  351. pWordMinSel = ECAnsiNext(ped,pWordMinSel);
  352. break;
  353. }
  354. #endif
  355. if (!ECIsDelimiter(*pWordMinSel) && *pWordMinSel != 0x0A)
  356. /*
  357. * We have found the last char in the word. Continue looking
  358. * backwards till we find the first char of the word
  359. */
  360. {
  361. charLocated = TRUE;
  362. /* We will consider a CR the start of a word */
  363. if (*pWordMinSel == 0x0D)
  364. break;
  365. }
  366. }
  367. }
  368. else
  369. {
  370. /* We are moving right and we are in between words so we need to move
  371. * right till we find the start of a word (either a CR or a character.
  372. */
  373. while ((ECIsDelimiter(*pWordMinSel) ||
  374. *pWordMinSel == 0x0A) &&
  375. pWordMinSel<pText+ped->cch)
  376. pWordMinSel++;
  377. }
  378. #ifdef FE_SB
  379. pWordMaxSel = (PSTR) umin((WORD)ECAnsiNext(ped,pWordMinSel),(WORD)pText+ped->cch);
  380. #else
  381. pWordMaxSel = (PSTR) umin((WORD)pWordMinSel+1,(WORD)pText+ped->cch);
  382. #endif
  383. if (*pWordMinSel == 0x0D)
  384. {
  385. #ifdef FE_SB
  386. if (pWordMinSel>pText && *(ECAnsiPrev(ped,pText,pWordMinSel)) == 0x0D)
  387. #else
  388. if (pWordMinSel>pText && *(pWordMinSel-1) == 0x0D)
  389. #endif
  390. /* So that we can treat CRCRLF as one word also. */
  391. pWordMinSel--;
  392. else if (*(pWordMinSel+1) == 0x0D)
  393. /* Move MaxSel on to the LF */
  394. pWordMaxSel++;
  395. }
  396. /* Check if we have a one character word */
  397. if (ECIsDelimiter(*pWordMaxSel))
  398. spaceLocated = TRUE;
  399. /* Move pWordMaxSel to the right looking for the end of a word and its
  400. * trailing spaces. WordMaxSel stops on the first character of the next
  401. * word. Thus, we break either at a CR or at the first nonspace char after
  402. * a run of spaces or LFs.
  403. */
  404. while ((pWordMaxSel < pText+ped->cch) &&
  405. (!spaceLocated || (ECIsDelimiter(*pWordMaxSel))))
  406. {
  407. if (*pWordMaxSel == 0x0D)
  408. break;
  409. #ifdef FE_SB
  410. if( ECIsDBCSLeadByte(ped,*pWordMaxSel) )
  411. break;
  412. else if( !ECIsDelimiter(*pWordMaxSel) && *pWordMaxSel != 0x0a &&
  413. *pWordMaxSel != 0x0d && ECIsDBCSLeadByte(ped,*pWordMinSel) )
  414. break;
  415. #endif
  416. #ifdef FE_SB
  417. pWordMaxSel = ECAnsiNext(ped,pWordMaxSel);
  418. #else
  419. pWordMaxSel++;
  420. #endif
  421. if (ECIsDelimiter(*pWordMaxSel))
  422. spaceLocated = TRUE;
  423. #ifdef FE_SB
  424. if (*(ECAnsiPrev(ped,pText,pWordMaxSel)) == 0x0A)
  425. break;
  426. #else
  427. if (*(pWordMaxSel-1) == 0x0A)
  428. break;
  429. #endif
  430. }
  431. LocalUnlock(ped->hText);
  432. return(MAKELONG(pWordMinSel-pText,pWordMaxSel-pText));
  433. }
  434. void FAR PASCAL ECEmptyUndo(ped)
  435. register PED ped;
  436. /* effects: empties the undo buffer.
  437. */
  438. {
  439. ped->undoType = UNDO_NONE;
  440. if (ped->hDeletedText)
  441. {
  442. GlobalFree(ped->hDeletedText);
  443. ped->hDeletedText = NULL;
  444. }
  445. }
  446. BOOL FAR PASCAL ECInsertText(ped, lpText, cchInsert)
  447. register PED ped;
  448. LPSTR lpText;
  449. ICH cchInsert;
  450. /* effects: Adds cch characters from lpText into the ped->hText starting at
  451. * ped->ichCaret. Returns TRUE if successful else FALSE. Updates
  452. * ped->cchAlloc and ped->cch properly if additional memory was allocated or
  453. * if characters were actually added. Updates ped->ichCaret to be at the end
  454. * of the inserted text. min and maxsel are equal to ichcaret.
  455. */
  456. {
  457. register PSTR pedText;
  458. PSTR pTextBuff;
  459. LONG style;
  460. WORD i;
  461. WORD allocamt;
  462. HANDLE hTextCopy;
  463. WORD lcompact;
  464. #ifdef FE_SB
  465. /* Make sure we don't split a DBCS in half - 05/15/90 */
  466. cchInsert = ECAdjustIch(ped, lpText, cchInsert);
  467. #endif
  468. if (!cchInsert)
  469. return(TRUE);
  470. /* Do we already have enough memory?? */
  471. if (cchInsert >= (ped->cchAlloc - ped->cch))
  472. {
  473. /* Save lpText across the allocs */
  474. SwapHandle(&lpText);
  475. /* Allocate what we need plus a little extra. Return FALSE if we are
  476. * unsuccessful.
  477. */
  478. allocamt = ped->cch+cchInsert;
  479. if (allocamt+CCHALLOCEXTRA > allocamt)
  480. /* Need to avoid wrapping around 64K if ped->cch+cchInsert is close
  481. * to 64K.
  482. */
  483. allocamt += CCHALLOCEXTRA;
  484. if (!ped->fSingle)
  485. {
  486. /* If multiline, try reallocing the text allowing it to be movable.
  487. * If it fails, move the line break array out of the way and try
  488. * again. We really fail if this doesn't work...
  489. */
  490. hTextCopy = LocalReAlloc(ped->hText, allocamt, LHND);
  491. if (hTextCopy)
  492. ped->hText = hTextCopy;
  493. else
  494. {
  495. /* If the above localrealloc fails, we need to take extreme
  496. * measures to try to alloc some memory. This is because the
  497. * local memory manager is broken when dealing with large
  498. * reallocs.
  499. */
  500. if (ped->chLines)
  501. {
  502. hTextCopy = (HANDLE)LocalReAlloc((HANDLE)ped->chLines,
  503. LocalSize((HANDLE)ped->chLines),
  504. LHND);
  505. if (!hTextCopy)
  506. return(FALSE);
  507. ped->chLines = (int *)hTextCopy;
  508. }
  509. LocalShrink(0,0x100);
  510. lcompact = umin(allocamt, CCHALLOCEXTRA*100);
  511. hTextCopy = LocalAlloc(LHND|LMEM_NOCOMPACT|LMEM_NODISCARD,
  512. lcompact);
  513. if (hTextCopy)
  514. LocalFree(hTextCopy);
  515. hTextCopy = LocalReAlloc(ped->hText, allocamt, LHND);
  516. if (hTextCopy)
  517. ped->hText = hTextCopy;
  518. else
  519. return(FALSE);
  520. }
  521. }
  522. else
  523. {
  524. if (!LocalReAlloc(ped->hText, allocamt, 0))
  525. return(FALSE);
  526. }
  527. ped->cchAlloc = LocalSize(ped->hText);
  528. /* Restore lpText */
  529. SwapHandle(&lpText);
  530. }
  531. /* Ok, we got the memory. Now copy the text into the structure
  532. */
  533. pedText = (PSTR) LocalLock(ped->hText);
  534. /* Get a pointer to the place where text is to be inserted */
  535. pTextBuff = pedText + ped->ichCaret;
  536. if (ped->ichCaret != ped->cch)
  537. {
  538. /* We are inserting text into the middle. We have to shift text to the
  539. * right before inserting new text.
  540. */
  541. LCopyStruct( (LPSTR)pTextBuff,
  542. (LPSTR)(pTextBuff + cchInsert),
  543. ped->cch-ped->ichCaret);
  544. }
  545. /* Make a copy of the text being inserted in the edit buffer. */
  546. /* Use this copy for doing UPPERCASE/LOWERCASE ANSI/OEM conversions */
  547. /* Fix for Bug #3406 -- 01/29/91 -- SANKAR -- */
  548. LCopyStruct(lpText, (LPSTR)pTextBuff, cchInsert);
  549. #ifndef PMODE
  550. LockData(0); /* Calls to Language drivers are made later; So, to be safe.*/
  551. #endif
  552. /* We need to get the style this way since edit controls use their own ds.
  553. */
  554. style = GetWindowLong(ped->hwnd, GWL_STYLE);
  555. if (style & ES_LOWERCASE)
  556. AnsiLowerBuff((LPSTR)pTextBuff, cchInsert);
  557. else
  558. if (style & ES_UPPERCASE)
  559. AnsiUpperBuff((LPSTR)pTextBuff, cchInsert);
  560. #ifdef FE_SB
  561. if( style & ES_OEMCONVERT ){
  562. for( i = 0; i < cchInsert; i++ ){
  563. /* Do not make any case conversion if a character is DBCS */
  564. if( ECIsDBCSLeadByte(ped, *((LPSTR)pTextBuff+i) ) )
  565. i++;
  566. else {
  567. if( IsCharLower( *((LPSTR)pTextBuff+i) ) ){
  568. AnsiUpperBuff( (LPSTR)pTextBuff+i, 1 );
  569. AnsiToOemBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
  570. OemToAnsiBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
  571. AnsiLowerBuff( (LPSTR)pTextBuff+i, 1 );
  572. } else {
  573. AnsiToOemBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
  574. OemToAnsiBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
  575. }
  576. }
  577. }
  578. }
  579. #else
  580. if (style & ES_OEMCONVERT)
  581. {
  582. for (i=0;i<cchInsert;i++)
  583. {
  584. if (IsCharLower(*((LPSTR)pTextBuff+i)))
  585. {
  586. AnsiUpperBuff((LPSTR)pTextBuff+i, 1);
  587. AnsiToOemBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
  588. OemToAnsiBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
  589. AnsiLowerBuff((LPSTR)pTextBuff+i,1);
  590. }
  591. else
  592. {
  593. AnsiToOemBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
  594. OemToAnsiBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
  595. }
  596. }
  597. }
  598. #endif
  599. #ifndef PMODE
  600. UnlockData(0);
  601. #endif
  602. LocalUnlock(ped->hText); /* Hereafter pTextBuff is invalid */
  603. /* Adjust UNDO fields so that we can undo this insert... */
  604. if (ped->undoType == UNDO_NONE)
  605. {
  606. ped->undoType = UNDO_INSERT;
  607. ped->ichInsStart = ped->ichCaret;
  608. ped->ichInsEnd = ped->ichCaret+cchInsert;
  609. }
  610. else
  611. if (ped->undoType & UNDO_INSERT)
  612. {
  613. if (ped->ichInsEnd == ped->ichCaret)
  614. ped->ichInsEnd += cchInsert;
  615. else
  616. {
  617. UNDOINSERT:
  618. if (ped->ichDeleted != ped->ichCaret)
  619. {
  620. /* Free Deleted text handle if any since user is inserting into
  621. a different point. */
  622. GlobalFree(ped->hDeletedText);
  623. ped->hDeletedText = NULL;
  624. ped->ichDeleted = -1;
  625. ped->undoType &= ~UNDO_DELETE;
  626. }
  627. ped->ichInsStart = ped->ichCaret;
  628. ped->ichInsEnd = ped->ichCaret+cchInsert;
  629. ped->undoType |= UNDO_INSERT;
  630. }
  631. }
  632. else
  633. if (ped->undoType == UNDO_DELETE)
  634. {
  635. goto UNDOINSERT;
  636. }
  637. ped->cch += cchInsert;
  638. ped->ichMinSel = ped->ichMaxSel = (ped->ichCaret += cchInsert);
  639. /* Set dirty bit */
  640. ped->fDirty = TRUE;
  641. return(TRUE);
  642. }
  643. ICH FAR PASCAL ECDeleteText(ped)
  644. register PED ped;
  645. /* effects: Deletes the text between ped->ichMinSel and ped->ichMaxSel. The
  646. * character at ichMaxSel is not deleted. But the character at ichMinSel is
  647. * deleted. ped->cch is updated properly and memory is deallocated if enough
  648. * text is removed. ped->ichMinSel, ped->ichMaxSel, and ped->ichCaret are set
  649. * to point to the original ped->ichMinSel. Returns the number of characters
  650. * deleted.
  651. */
  652. {
  653. register PSTR pedText;
  654. ICH cchDelete;
  655. LPSTR lpDeleteSaveBuffer;
  656. HANDLE hDeletedText;
  657. WORD bufferOffset;
  658. cchDelete = ped->ichMaxSel - ped->ichMinSel;
  659. if (!cchDelete)
  660. return(0);
  661. /* Ok, now lets delete the text. */
  662. pedText = (PSTR) LocalLock(ped->hText);
  663. /* Adjust UNDO fields so that we can undo this delete... */
  664. if (ped->undoType == UNDO_NONE)
  665. {
  666. UNDODELETEFROMSCRATCH:
  667. if (ped->hDeletedText = GlobalAlloc(GHND, (LONG)(cchDelete+1)))
  668. {
  669. ped->undoType = UNDO_DELETE;
  670. ped->ichDeleted = ped->ichMinSel;
  671. ped->cchDeleted = cchDelete;
  672. lpDeleteSaveBuffer = GlobalLock(ped->hDeletedText);
  673. LCopyStruct((LPSTR)(pedText+ped->ichMinSel),
  674. lpDeleteSaveBuffer,
  675. cchDelete);
  676. lpDeleteSaveBuffer[cchDelete]=0;
  677. GlobalUnlock(ped->hDeletedText);
  678. }
  679. }
  680. else
  681. if (ped->undoType & UNDO_INSERT)
  682. {
  683. UNDODELETE:
  684. ped->undoType = UNDO_NONE;
  685. ped->ichInsStart = ped->ichInsEnd = -1;
  686. GlobalFree(ped->hDeletedText);
  687. ped->hDeletedText = NULL;
  688. ped->ichDeleted = -1;
  689. ped->cchDeleted = 0;
  690. goto UNDODELETEFROMSCRATCH;
  691. }
  692. else
  693. if (ped->undoType == UNDO_DELETE)
  694. {
  695. if (ped->ichDeleted == ped->ichMaxSel)
  696. {
  697. /* Copy deleted text to front of undo buffer */
  698. hDeletedText = GlobalReAlloc(ped->hDeletedText,
  699. (LONG)(cchDelete+ped->cchDeleted+1),
  700. GHND);
  701. if (!hDeletedText)
  702. goto UNDODELETE;
  703. bufferOffset = 0;
  704. ped->ichDeleted = ped->ichMinSel;
  705. }
  706. else
  707. if (ped->ichDeleted == ped->ichMinSel)
  708. {
  709. /* Copy deleted text to end of undo buffer */
  710. hDeletedText = GlobalReAlloc(ped->hDeletedText,
  711. (LONG)(cchDelete+ped->cchDeleted+1),
  712. GHND);
  713. if (!hDeletedText)
  714. goto UNDODELETE;
  715. bufferOffset = ped->cchDeleted;
  716. }
  717. else
  718. /* Clear the current UNDO delete and add the new one since
  719. the deletes aren't contigous. */
  720. goto UNDODELETE;
  721. ped->hDeletedText = hDeletedText;
  722. lpDeleteSaveBuffer = (LPSTR)GlobalLock(hDeletedText);
  723. if (!bufferOffset)
  724. {
  725. /* Move text in delete buffer up so that we can insert the next
  726. text at the head of the buffer. */
  727. LCopyStruct(lpDeleteSaveBuffer,
  728. (LPSTR)(lpDeleteSaveBuffer+cchDelete),
  729. ped->cchDeleted);
  730. }
  731. LCopyStruct((LPSTR)(pedText+ped->ichMinSel),
  732. (LPSTR)(lpDeleteSaveBuffer+bufferOffset),
  733. cchDelete);
  734. lpDeleteSaveBuffer[ped->cchDeleted+cchDelete]=0;
  735. GlobalUnlock(ped->hDeletedText);
  736. ped->cchDeleted += cchDelete;
  737. }
  738. if (ped->ichMaxSel != ped->cch)
  739. {
  740. /* We are deleting text from the middle of the buffer so we have to
  741. shift text to the left. */
  742. LCopyStruct((LPSTR)(pedText + ped->ichMaxSel),
  743. (LPSTR)(pedText + ped->ichMinSel),
  744. ped->cch-ped->ichMaxSel);
  745. }
  746. LocalUnlock(ped->hText);
  747. if (ped->cchAlloc-ped->cch > CCHALLOCEXTRA)
  748. {
  749. /* Free some memory since we deleted a lot */
  750. LocalReAlloc(ped->hText, (WORD)(ped->cch+(CCHALLOCEXTRA/2)), 0);
  751. ped->cchAlloc = LocalSize(ped->hText);
  752. }
  753. ped->cch = ped->cch - cchDelete;
  754. ped->ichCaret = ped->ichMaxSel = ped->ichMinSel;
  755. /* Set dirty bit */
  756. ped->fDirty = TRUE;
  757. return(cchDelete);
  758. }
  759. void FAR PASCAL ECNotifyParent(ped, notificationCode)
  760. register PED ped;
  761. short notificationCode;
  762. /* effects: Sends the notification code to the parent of the edit control */
  763. {
  764. /*
  765. * Lowword contains handle to window highword has the notification code.
  766. */
  767. SendMessage(ped->hwndParent, WM_COMMAND,
  768. GetWindowWord(ped->hwnd,GWW_ID),
  769. MAKELONG(ped->hwnd, notificationCode));
  770. }
  771. void FAR PASCAL ECSetEditClip(ped, hdc)
  772. register PED ped;
  773. HDC hdc;
  774. /* effects: Sets the clip rectangle for the dc to ped->rcFmt intersect
  775. * rcClient.
  776. */
  777. {
  778. RECT rectClient;
  779. GetClientRect(ped->hwnd,(LPRECT)&rectClient);
  780. /*
  781. * If border bit is set, deflate client rectangle appropriately.
  782. */
  783. if (ped->fBorder)
  784. /* Shrink client area to make room for the border */
  785. InflateRect((LPRECT)&rectClient,
  786. -min(ped->aveCharWidth,ped->cxSysCharWidth)/2,
  787. -min(ped->lineHeight,ped->cySysCharHeight)/4);
  788. /* Set clip rectangle to rectClient intersect ped->rcFmt */
  789. if (!ped->fSingle)
  790. IntersectRect((LPRECT)&rectClient,
  791. (LPRECT)&rectClient, (LPRECT)&ped->rcFmt);
  792. IntersectClipRect(hdc,rectClient.left, rectClient.top,
  793. rectClient.right, rectClient.bottom);
  794. }
  795. HDC FAR PASCAL ECGetEditDC(ped, fFastDC)
  796. register PED ped;
  797. BOOL fFastDC;
  798. /* effects: Hides the caret, gets the DC for the edit control, and clips to
  799. * the rcFmt rectangle specified for the edit control and sets the proper
  800. * font. If fFastDC, just select the proper font but don't bother about clip
  801. * regions or hiding the caret.
  802. */
  803. {
  804. register HDC hdc;
  805. if (!fFastDC)
  806. HideCaret(ped->hwnd);
  807. hdc = GetDC(ped->hwnd);
  808. ECSetEditClip(ped, hdc);
  809. /*
  810. * Select the proper font for this edit control's dc.
  811. */
  812. if (ped->hFont)
  813. SelectObject(hdc, ped->hFont);
  814. return(hdc);
  815. }
  816. void FAR PASCAL ECReleaseEditDC(ped,hdc,fFastDC)
  817. register PED ped;
  818. HDC hdc;
  819. BOOL fFastDC;
  820. /* effects: Releases the DC (hdc) for the edit control and shows the caret.
  821. * If fFastDC, just select the proper font but don't bother about showing the
  822. * caret.
  823. */
  824. {
  825. if (ped->hFont)
  826. /*
  827. * Release the font selected in this dc.
  828. */
  829. SelectObject(hdc, GetStockObject(SYSTEM_FONT));
  830. ReleaseDC(ped->hwnd,hdc);
  831. if (!fFastDC)
  832. ShowCaret(ped->hwnd);
  833. }
  834. BOOL FAR PASCAL ECSetText(ped, lpstr)
  835. register PED ped;
  836. LPSTR lpstr;
  837. /* effects: Copies the null terminated text in lpstr to the ped. Notifies the
  838. * parent if there isn't enough memory. Sets the minsel, maxsel, and caret to
  839. * the beginning of the inserted text. Returns TRUE if successful else FALSE
  840. * if no memory (and notifies the parent).
  841. */
  842. {
  843. ICH cchLength;
  844. ICH cchSave = ped->cch;
  845. ICH ichCaretSave = ped->ichCaret;
  846. ped->cch = ped->ichCaret = 0;
  847. ped->cchAlloc = LocalSize(ped->hText);
  848. if (!lpstr)
  849. {
  850. LocalReAlloc(ped->hText, CCHALLOCEXTRA, 0);
  851. ped->cch = 0;
  852. }
  853. else
  854. {
  855. cchLength = lstrlen(lpstr);
  856. if (ped->fSingle)
  857. /* Limit single line edit controls to 32K */
  858. cchLength = umin(cchLength, 0x7ffe);
  859. /* Add the text */
  860. if (cchLength && !ECInsertText(ped,lpstr,cchLength))
  861. {
  862. /*
  863. * Restore original state and notify parent we ran out of memory.
  864. */
  865. ped->cch = cchSave;
  866. ped->ichCaret = ichCaretSave;
  867. ECNotifyParent(ped, EN_ERRSPACE);
  868. return(FALSE);
  869. }
  870. }
  871. ped->cchAlloc = LocalSize(ped->hText);
  872. ped->screenStart = ped->iCaretLine = 0;
  873. /* Update caret and selection extents */
  874. ped->ichMaxSel = ped->ichMinSel = ped->ichCaret = 0;
  875. ped->cLines = 1;
  876. return(TRUE);
  877. }
  878. ICH FAR PASCAL ECCopyHandler(ped)
  879. register PED ped;
  880. /* effects: Copies the text between ichMinSel and ichMaxSel to the clipboard.
  881. * Returns the number of characters copied.
  882. */
  883. {
  884. HANDLE hData;
  885. char *pchSel;
  886. char FAR *lpchClip;
  887. ICH cbData;
  888. cbData = ped->ichMaxSel - ped->ichMinSel;
  889. if (!cbData)
  890. return(0);
  891. if (!OpenClipboard(ped->hwnd))
  892. return(0);
  893. EmptyClipboard();
  894. /* +1 for the terminating NULL */
  895. if (!(hData = GlobalAlloc(LHND, (LONG)(cbData+1))))
  896. {
  897. CloseClipboard();
  898. return(0);
  899. }
  900. lpchClip = GlobalLock(hData);
  901. pchSel = LocalLock(ped->hText) + ped->ichMinSel;
  902. LCopyStruct((LPSTR)(pchSel), (LPSTR)lpchClip, cbData);
  903. *(lpchClip+cbData) = 0;
  904. LocalUnlock(ped->hText);
  905. GlobalUnlock(hData);
  906. SetClipboardData(CF_TEXT, hData);
  907. CloseClipboard();
  908. return(cbData);
  909. }
  910. /****************************************************************************/
  911. /* EditWndProc() */
  912. /****************************************************************************/
  913. LONG FAR PASCAL EditWndProc3(hwnd, message, wParam, lParam)
  914. HWND hwnd;
  915. WORD message;
  916. register WORD wParam;
  917. LONG lParam;
  918. /* effects: Class procedure for all edit controls.
  919. Dispatches all messages to the appropriate handlers which are named
  920. as follows:
  921. SL (single line) prefixes all single line edit control procedures while
  922. ML (multi line) prefixes all multi- line edit controls.
  923. EC (edit control) prefixes all common handlers.
  924. The EditWndProc only handles messages common to both single and multi
  925. line edit controls. Messages which are handled differently between
  926. single and multi are sent to SLEditWndProc or MLEditWndProc.
  927. Top level procedures are EditWndPoc, SLEditWndProc, and MLEditWndProc.
  928. SL*Handler or ML*Handler or EC*Handler procs are called to handle
  929. the various messages. Support procedures are prefixed with SL ML or
  930. EC depending on which code they support. They are never called
  931. directly and most assumpttions/effects are documented in the effects
  932. clause.
  933. */
  934. {
  935. register PED ped;
  936. /* Get the ped for the given window now since we will use it a lot in
  937. * various handlers. This was stored using SetWindowWord(hwnd,0,ped) when we
  938. * initially created the edit control.
  939. */
  940. ped = (PED) GetWindowWord(hwnd,0);
  941. if ((WORD)ped == (WORD)-1)
  942. /* The ped was destroyed and this is a rogue message to be ignored. */
  943. return(0L);
  944. /* Dispatch the various messages we can receive */
  945. switch (message)
  946. {
  947. /* Messages which are handled the same way for both single and multi line
  948. * edit controls.
  949. */
  950. case WM_COPY:
  951. /* wParam - not used
  952. lParam - not used */
  953. return((LONG)ECCopyHandler(ped));
  954. break;
  955. case WM_ENABLE:
  956. /* wParam - nonzero is window is enables else disable window if 0.
  957. lParam - not used
  958. */
  959. if (ped->fSingle)
  960. /* Cause the rectangle to be redrawn in grey.
  961. */
  962. InvalidateRect(ped->hwnd, NULL, FALSE);
  963. return((LONG)(ped->fDisabled = !wParam));
  964. break;
  965. case EM_GETLINECOUNT:
  966. /* wParam - not used
  967. lParam - not used */
  968. return((LONG)ped->cLines);
  969. break;
  970. case EM_GETMODIFY:
  971. /* wParam - not used
  972. lParam - not used */
  973. /* effects: Gets the state of the modify flag for this edit control.
  974. */
  975. return((LONG)ped->fDirty);
  976. break;
  977. case EM_GETRECT:
  978. /* wParam - not used
  979. lParam - pointer to a RECT data structure that gets the dimensions. */
  980. /*
  981. * effects: Copies the rcFmt rect to *lpRect. Note that the return value
  982. * of the copyrect has no meaning and we don't care...
  983. */
  984. return((LONG)CopyRect((LPRECT)lParam, (LPRECT)&ped->rcFmt));
  985. break;
  986. case WM_GETFONT:
  987. /* wParam - not used
  988. lParam - not used */
  989. return(ped->hFont);
  990. break;
  991. case WM_GETTEXT:
  992. /* wParam - max number of bytes to copy
  993. lParam - buffer to copy text to. Text is 0 terminated. */
  994. return((LONG)ECGetTextHandler(ped, wParam, (LPSTR)lParam));
  995. break;
  996. case WM_GETTEXTLENGTH:
  997. return((LONG)ped->cch);
  998. break;
  999. case WM_NCDESTROY:
  1000. /* wParam - used by DefWndProc called within ECNcDestroyHandler
  1001. lParam - used by DefWndProc called within ECNcDestroyHandler */
  1002. ECNcDestroyHandler(hwnd, ped, wParam, lParam);
  1003. break;
  1004. case WM_SETFONT:
  1005. /* wParam - handle to the font
  1006. lParam - redraw if true else don't */
  1007. ECSetFont(ped, (HANDLE)wParam, (BOOL)LOWORD(lParam));
  1008. break;
  1009. case WM_SETREDRAW:
  1010. /* wParam - specifies state of the redraw flag. nonzero = redraw
  1011. lParam - not used */
  1012. /* effects: Sets the state of the redraw flag for this edit control.
  1013. */
  1014. return((LONG)(ped->fNoRedraw = !(BOOL)wParam));
  1015. /* If NoRedraw is true, we don't redraw... (Yes, this is backwards we
  1016. * are keeping track of the opposite of the command ...
  1017. */
  1018. break;
  1019. case EM_CANUNDO:
  1020. /* wParam - not used
  1021. lParam - not used */
  1022. return((LONG)(ped->undoType != UNDO_NONE));
  1023. break;
  1024. case EM_EMPTYUNDOBUFFER:
  1025. /* wParam - not used
  1026. lParam - not used */
  1027. ECEmptyUndo(ped);
  1028. break;
  1029. case EM_GETSEL:
  1030. /* wParam - not used
  1031. lParam - not used */
  1032. /* effects: Gets the selection range for the given edit control. The
  1033. * starting position is in the low order word. It contains the position
  1034. * of the first nonselected character after the end of the selection in
  1035. * the high order word.
  1036. */
  1037. return(MAKELONG(ped->ichMinSel,ped->ichMaxSel));
  1038. break;
  1039. case EM_LIMITTEXT:
  1040. /* wParam - max number of bytes that can be entered
  1041. lParam - not used */
  1042. /* effects: Specifies the maximum number of bytes of text the user may
  1043. * enter. If maxLength is 0, we may enter MAXINT number of characters.
  1044. */
  1045. if (ped->fSingle)
  1046. {
  1047. if (wParam)
  1048. wParam = umin(0x7FFEu,wParam);
  1049. else
  1050. wParam = 0x7FFEu;
  1051. }
  1052. if (wParam)
  1053. ped->cchTextMax = (ICH)wParam;
  1054. else
  1055. ped->cchTextMax = 0xFFFFu;
  1056. break;
  1057. case EM_SETMODIFY:
  1058. /* wParam - specifies the new value for the modify flag
  1059. lParam - not used */
  1060. /*
  1061. * effects: Sets the state of the modify flag for this edit control.
  1062. */
  1063. ped->fDirty = wParam;
  1064. break;
  1065. case EM_SETPASSWORDCHAR:
  1066. /* wParam - sepecifies the new char to display instead of the real text.
  1067. if null, display the real text. */
  1068. ECSetPasswordChar(ped, wParam);
  1069. break;
  1070. case EM_GETFIRSTVISIBLE:
  1071. /* wParam - not used
  1072. lParam - not used */
  1073. /* effects: Returns the first visible char for single line edit controls
  1074. * and returns the first visible line for multiline edit controls.
  1075. */
  1076. return((LONG)(WORD)ped->screenStart);
  1077. break;
  1078. case EM_SETREADONLY:
  1079. /* wParam - state to set read only flag to */
  1080. ped->fReadOnly = wParam;
  1081. lParam = GetWindowLong(ped->hwnd, GWL_STYLE);
  1082. if (wParam)
  1083. lParam |= ES_READONLY;
  1084. else
  1085. lParam &= (~ES_READONLY);
  1086. SetWindowLong(ped->hwnd, GWL_STYLE, lParam);
  1087. return(1L);
  1088. break;
  1089. /* Messages handled differently for single and multi line edit controls */
  1090. case WM_CREATE:
  1091. /* Since the ped for this edit control is not defined, we have to check
  1092. * the style directly.
  1093. */
  1094. if (GetWindowLong(hwnd, GWL_STYLE) & ES_MULTILINE)
  1095. return(MLEditWndProc(hwnd, ped, message, wParam, lParam));
  1096. else
  1097. return(SLEditWndProc(hwnd, ped, message, wParam, lParam));
  1098. break;
  1099. case WM_NCCREATE:
  1100. return(ECNcCreate(hwnd, (LPCREATESTRUCT)lParam));
  1101. break;
  1102. default:
  1103. if (ped->fSingle)
  1104. return(SLEditWndProc(hwnd, ped, message, wParam, lParam));
  1105. else
  1106. return(MLEditWndProc(hwnd, ped, message, wParam, lParam));
  1107. break;
  1108. } /* switch (message) */
  1109. return(1L);
  1110. } /* EditWndProc */
  1111. void NEAR PASCAL ECFindXORblks(lpOldBlk, lpNewBlk, lpBlk1, lpBlk2)
  1112. /*
  1113. * This finds the XOR of lpOldBlk and lpNewBlk and returns resulting blocks
  1114. * through the lpBlk1 and lpBlk2; This could result in a single block or
  1115. * at the maximum two blocks;
  1116. * If a resulting block is empty, then it's StPos field has -1.
  1117. * NOTE:
  1118. * When called from MultiLine edit control, StPos and EndPos fields of
  1119. * these blocks have the Starting line and Ending line of the block;
  1120. * When called from SingleLine edit control, StPos and EndPos fields
  1121. * of these blocks have the character index of starting position and
  1122. * ending position of the block.
  1123. */
  1124. LPBLOCK lpOldBlk;
  1125. LPBLOCK lpNewBlk;
  1126. LPBLOCK lpBlk1;
  1127. LPBLOCK lpBlk2;
  1128. {
  1129. if(lpOldBlk -> StPos >= lpNewBlk ->StPos)
  1130. {
  1131. lpBlk1 -> StPos = lpNewBlk -> StPos;
  1132. lpBlk1 -> EndPos = umin(lpOldBlk -> StPos, lpNewBlk -> EndPos);
  1133. }
  1134. else
  1135. {
  1136. lpBlk1 -> StPos = lpOldBlk -> StPos;
  1137. lpBlk1 -> EndPos = umin(lpNewBlk -> StPos, lpOldBlk -> EndPos);
  1138. }
  1139. if(lpOldBlk -> EndPos <= lpNewBlk -> EndPos)
  1140. {
  1141. lpBlk2 -> StPos = umax(lpOldBlk -> EndPos, lpNewBlk -> StPos);
  1142. lpBlk2 -> EndPos = lpNewBlk -> EndPos;
  1143. }
  1144. else
  1145. {
  1146. lpBlk2 -> StPos = umax(lpNewBlk -> EndPos, lpOldBlk -> StPos);
  1147. lpBlk2 -> EndPos = lpOldBlk -> EndPos;
  1148. }
  1149. }
  1150. /*
  1151. * This function finds the XOR between two selection blocks(OldBlk and NewBlk)
  1152. * and returns the resulting areas thro the same parameters; If the XOR of
  1153. * both the blocks is empty, then this returns FALSE; Otherwise TRUE.
  1154. *
  1155. * NOTE:
  1156. * When called from MultiLine edit control, StPos and EndPos fields of
  1157. * these blocks have the Starting line and Ending line of the block;
  1158. * When called from SingleLine edit control, StPos and EndPos fields
  1159. * of these blocks have the character index of starting position and
  1160. * ending position of the block.
  1161. */
  1162. BOOL FAR PASCAL ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel, OldBlk,
  1163. NewBlk)
  1164. PED ped;
  1165. ICH ichOldMinSel;
  1166. ICH ichOldMaxSel;
  1167. LPBLOCK OldBlk;
  1168. LPBLOCK NewBlk;
  1169. {
  1170. BLOCK Blk[2];
  1171. int iBlkCount = 0;
  1172. int i;
  1173. Blk[0].StPos = Blk[0].EndPos = Blk[1].StPos = Blk[1].EndPos = -1;
  1174. /* Check if the Old selection block existed */
  1175. if(ichOldMinSel != ichOldMaxSel)
  1176. {
  1177. /* Yes! Old block existed. */
  1178. Blk[0].StPos = OldBlk -> StPos;
  1179. Blk[0].EndPos = OldBlk -> EndPos;
  1180. iBlkCount++;
  1181. }
  1182. /* Check if the new Selection block exists */
  1183. if(ped -> ichMinSel != ped -> ichMaxSel)
  1184. {
  1185. /* Yes! New block exists */
  1186. Blk[1].StPos = NewBlk -> StPos;
  1187. Blk[1].EndPos = NewBlk -> EndPos;
  1188. iBlkCount++;
  1189. }
  1190. /* If both the blocks exist find the XOR of them */
  1191. if(iBlkCount == 2)
  1192. {
  1193. /* Check if both blocks start at the same character position */
  1194. if(ichOldMinSel == ped->ichMinSel)
  1195. {
  1196. /* Check if they end at the same character position */
  1197. if(ichOldMaxSel == ped -> ichMaxSel)
  1198. return(FALSE); /* Nothing changes */
  1199. #ifdef FE_SB
  1200. /* This look like bug, Because it uses min/max to compare
  1201. * two ICH values even if ICH is unsigned!
  1202. */
  1203. Blk[0].StPos = umin(NewBlk -> EndPos, OldBlk -> EndPos);
  1204. Blk[0].EndPos = umax(NewBlk -> EndPos, OldBlk -> EndPos);
  1205. #else
  1206. Blk[0].StPos = min(NewBlk -> EndPos, OldBlk -> EndPos);
  1207. Blk[0].EndPos = max(NewBlk -> EndPos, OldBlk -> EndPos);
  1208. #endif
  1209. Blk[1].StPos = -1;
  1210. }
  1211. else
  1212. {
  1213. if(ichOldMaxSel == ped -> ichMaxSel)
  1214. {
  1215. Blk[0].StPos = umin(NewBlk -> StPos, OldBlk -> StPos);
  1216. Blk[0].EndPos = umax(NewBlk -> StPos, OldBlk -> StPos);
  1217. Blk[1].StPos = -1;
  1218. }
  1219. else
  1220. ECFindXORblks(OldBlk, NewBlk, &Blk[0], &Blk[1]);
  1221. }
  1222. }
  1223. LCopyStruct((LPSTR)&Blk[0], (LPSTR)OldBlk, sizeof(BLOCK));
  1224. LCopyStruct((LPSTR)&Blk[1], (LPSTR)NewBlk, sizeof(BLOCK));
  1225. return(TRUE); /* Yup , There is something to paint */
  1226. }
  1227. #ifdef FE_SB
  1228. /*
  1229. * Set DBCS Vector for specified character set.
  1230. */
  1231. VOID FAR PASCAL ECGetDBCSVector( ped )
  1232. PED ped;
  1233. {
  1234. HANDLE hTable;
  1235. PBYTE pTable, pDBCS;
  1236. unsigned i;
  1237. switch( ped->charSet ) {
  1238. case SHIFTJIS_CHARSET: /* 128 -> Japan */
  1239. ped->DBCSVector[0] = 0x81;
  1240. ped->DBCSVector[1] = 0x9f;
  1241. ped->DBCSVector[2] = 0xe0;
  1242. ped->DBCSVector[3] = 0xfc;
  1243. break;
  1244. case CHINESEBIG5_CHARSET: /* 136 -> Taiwan */
  1245. ped->DBCSVector[0] = 0x81;
  1246. ped->DBCSVector[1] = 0xfe;
  1247. break;
  1248. case GB2312_CHARSET: /* 134 -> China KKFIX 10/19/96 Change GB2312 -> GBK Code range*/
  1249. ped->DBCSVector[0] = 0x81;
  1250. ped->DBCSVector[1] = 0xfe;
  1251. break;
  1252. case HANGEUL_CHARSET:
  1253. ped->DBCSVector[0] = 0x81;
  1254. ped->DBCSVector[1] = 0xfe;
  1255. break;
  1256. default:
  1257. ped->DBCSVector[0] = 0x0;
  1258. break;
  1259. }
  1260. /* If we can allocate 256 bytes of local memory, edit control
  1261. * operations are more comfortable
  1262. */
  1263. if ((ped->hDBCSVector = LocalAlloc( LHND, sizeof(BYTE)*256 )) == NULL)
  1264. return;
  1265. pTable = (PBYTE)LocalLock( ped->hDBCSVector );
  1266. pDBCS = ped->DBCSVector;
  1267. while(pDBCS[0]) {
  1268. for (i = pDBCS[0]; i <= pDBCS[1]; i++) pTable[i] = 1;
  1269. pDBCS += 2;
  1270. }
  1271. LocalUnlock( ped->hDBCSVector );
  1272. }
  1273. /*
  1274. * Advance string pointer for Edit Control use only.
  1275. */
  1276. LPSTR FAR PASCAL ECAnsiNext( ped, lpCurrent )
  1277. PED ped;
  1278. LPSTR lpCurrent;
  1279. {
  1280. return lpCurrent+((ECIsDBCSLeadByte(ped,*lpCurrent)==TRUE)?2:1);
  1281. }
  1282. /*
  1283. * Decrement string pointer for Edit Control use only.
  1284. */
  1285. LPSTR FAR PASCAL ECAnsiPrev( ped, lpBase, lpStr )
  1286. PED ped;
  1287. LPSTR lpBase, lpStr;
  1288. {
  1289. LPSTR lpCurrent = lpStr;
  1290. // human C discompiler version 1.0---
  1291. //; parmD pFirst ; [bx+10] es:di
  1292. //; parmD pStr ; [bx+6] ds:si
  1293. //
  1294. // cmp si,di ; pointer to first char?
  1295. // jz ap5 ; yes, just quit
  1296. if (lpBase == lpCurrent)
  1297. return lpBase;
  1298. // dec si ; backup once
  1299. // cmp si,di ; pointer to first char?
  1300. // jz ap5 ; yse, just quit
  1301. if (--lpCurrent == lpBase)
  1302. return lpBase;
  1303. //ap1:
  1304. // dec si ; backup once
  1305. // mov al, [si] ; fetch a character
  1306. // cCall IsDBCSLeadByte,<ax> ; DBCS lead byte candidate?
  1307. // test ax,ax ;
  1308. // jz ap2 ; jump if not.
  1309. // cmp si,di ; backword exhausted?
  1310. // jz ap3 ; jump if so
  1311. // jmp ap1 ; repeat if not
  1312. do {
  1313. lpCurrent--;
  1314. if (!ECIsDBCSLeadByte(ped, *lpCurrent)) {
  1315. lpCurrent++;
  1316. break;
  1317. }
  1318. } while(lpCurrent != lpBase);
  1319. //ap2:
  1320. // inc si ; adjust pointer correctly
  1321. //ap3:
  1322. return lpStr - (((lpStr - lpCurrent) & 1) ? 1 : 2);
  1323. // mov bx, [bp+6] ;
  1324. // mov di, bx ; result in DI
  1325. // dec di ;
  1326. // sub bx, si ; how many characters backworded
  1327. // test bx, 1 ; see even or odd...
  1328. // jnz ap4 ; odd - previous char is SBCS
  1329. // dec di ; make DI for DBCS
  1330. //ap4:
  1331. // mov si, di ; final result in SI
  1332. //ap5:
  1333. // mov ax,si
  1334. // mov dx,ds
  1335. //
  1336. // pop di
  1337. // pop si
  1338. // pop ds
  1339. //
  1340. // pop bp
  1341. // ret 8
  1342. //cEnd nogen
  1343. }
  1344. /*
  1345. * Test to see DBCS lead byte or not - Edit Control use only.
  1346. */
  1347. BOOL FAR PASCAL ECIsDBCSLeadByte( ped, cch )
  1348. PED ped;
  1349. BYTE cch;
  1350. {
  1351. BYTE ch1, ch2;
  1352. PBYTE pTable;
  1353. if (!ped->fDBCS)
  1354. return FALSE;
  1355. if (ped->hDBCSVector) {
  1356. pTable = (PBYTE)LMHtoP(ped->hDBCSVector);
  1357. return pTable[ cch ];
  1358. }
  1359. pTable = ped->DBCSVector;
  1360. while( *pTable ) {
  1361. ch1 = *pTable++;
  1362. ch2 = *pTable++;
  1363. if (cch >= ch1 && cch <= ch2)
  1364. return TRUE;
  1365. }
  1366. return FALSE;
  1367. }
  1368. /*
  1369. * Assemble two WM_CHAR messages to single DBCS character.
  1370. * If program detects first byte of DBCS character in WM_CHAR message,
  1371. * it calls this function to obtain second WM_CHAR message from queue.
  1372. * finally this routine assembles first byte and second byte into single
  1373. * DBCS character.
  1374. */
  1375. int FAR PASCAL DBCSCombine(hwnd, ch)
  1376. register HWND hwnd;
  1377. int ch;
  1378. {
  1379. MSG msg;
  1380. int i;
  1381. i = 10; /* loop counter to avoid the infinite loop */
  1382. while (!PeekMessage((LPMSG)&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)) {
  1383. if (--i == 0)
  1384. return( NULL );
  1385. Yield();
  1386. }
  1387. return ((unsigned)ch | ((unsigned)(msg.wParam)<<8));
  1388. }
  1389. /*
  1390. * This function adjusts a current pointer correctly. If a current
  1391. * pointer is lying between DBCS first byte and second byte, this
  1392. * function adjusts a current pointer to a first byte of DBCS position
  1393. * by decrement once.
  1394. */
  1395. ICH FAR PASCAL ECAdjustIch( ped, lpstr, ch )
  1396. PED ped;
  1397. LPSTR lpstr;
  1398. ICH ch;
  1399. {
  1400. ICH newch = ch;
  1401. if ( newch == 0 )
  1402. return ( newch );
  1403. if ( !ECIsDBCSLeadByte(ped, lpstr[--newch] ) )
  1404. return ( ch ); // previous char is SBCS
  1405. while(1) {
  1406. if (!ECIsDBCSLeadByte(ped, lpstr[newch] )) {
  1407. newch++;
  1408. break;
  1409. }
  1410. if (newch)
  1411. newch--;
  1412. else
  1413. break;
  1414. }
  1415. return ((ch - newch) & 1) ? ch-1 : ch;
  1416. }
  1417. #endif