ODBlock.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. /* OpenDoors Online Software Programming Toolkit
  2. * (C) Copyright 1991 - 1999 by Brian Pirie.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *
  19. * File: ODBlock.c
  20. *
  21. * Description: Implements the text block manipulation functions.
  22. *
  23. * Revisions: Date Ver Who Change
  24. * ---------------------------------------------------------------
  25. * Oct 13, 1994 6.00 BP New file header format.
  26. * Dec 09, 1994 6.00 BP Standardized coding style.
  27. * Aug 19, 1995 6.00 BP 32-bit portability.
  28. * Nov 11, 1995 6.00 BP Removed register keyword.
  29. * Nov 14, 1995 6.00 BP Added include of odscrn.h.
  30. * Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
  31. * Dec 12, 1995 6.00 BP Added entry, exit and kernel macros.
  32. * Dec 30, 1995 6.00 BP Added ODCALL for calling convention.
  33. * Feb 19, 1996 6.00 BP Changed version number to 6.00.
  34. * Mar 03, 1996 6.10 BP Begin version 6.10.
  35. * Aug 10, 2003 6.23 SH *nix support
  36. */
  37. #define BUILDING_OPENDOORS
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <stdio.h>
  41. #include "OpenDoor.h"
  42. #include "ODCore.h"
  43. #include "ODGen.h"
  44. #include "ODScrn.h"
  45. #include "ODKrnl.h"
  46. /* Set to TRUE when od_puttext() should leave the cursor in its original */
  47. /* position */
  48. static BOOL bScrollAction = TRUE;
  49. /* ----------------------------------------------------------------------------
  50. * od_puttext()
  51. *
  52. * Displays the contents of the buffer passed in block. Leaves cursor in
  53. * original position, unless bScrollAction is FALSE. Leaves colour at
  54. * original value.
  55. *
  56. * Parameters: nLeft - Column number of left edge of block of text to
  57. * transfer, where 1 is the leftmost column of the
  58. * screen.
  59. *
  60. * nTop - Row number of the top edge of block of text to
  61. * to transfer, where 1 is the top row of the screen.
  62. *
  63. * nRight - Column number of the right edge of block.
  64. *
  65. * nBottom - Row number of bottom edge of block.
  66. *
  67. * pBlock - Pointer to buffer that has been filled in the format
  68. * used by od_gettext().
  69. *
  70. * Return: TRUE on success, FALSE on failure.
  71. */
  72. ODAPIDEF BOOL ODCALL od_puttext(INT nLeft, INT nTop, INT nRight, INT nBottom,
  73. void *pBlock)
  74. {
  75. INT nRowLength = nRight - nLeft +1;
  76. INT nRowBytes = nRowLength * 2;
  77. char *pchTest;
  78. char *pchMemory;
  79. char *pBuffer=NULL;
  80. char *pchScreenBlock;
  81. INT nBlockRow = 0;
  82. INT nOutRow;
  83. INT nOutColour = 999;
  84. INT nOutColumn, nCheckColumn;
  85. char *pchMemBlock;
  86. INT nMoveCost = od_control.user_avatar ? 4 : 7;
  87. BYTE btMaxRight, btMaxBottom;
  88. /* Log function entry if running in trace mode. */
  89. TRACE(TRACE_API, "od_puttext()");
  90. /* Ensure that OpenDoors is initialized before proceeding. */
  91. if(!bODInitialized) od_init();
  92. OD_API_ENTRY();
  93. /* Get current display setting profile. */
  94. ODScrnGetTextInfo(&ODTextInfo);
  95. /* Calculate the maximum values for bottom and right of block. */
  96. btMaxRight=ODTextInfo.winright-ODTextInfo.winleft+1;
  97. btMaxBottom=ODTextInfo.winbottom-ODTextInfo.wintop+1;
  98. /* Check that parameters seem reasonable. */
  99. if(nLeft<1 || nTop<1 || nRight>btMaxRight || nBottom>btMaxBottom
  100. || nTop > nBottom || nLeft > nRight || pBlock==NULL)
  101. {
  102. od_control.od_error = ERR_PARAMETER;
  103. OD_API_EXIT();
  104. return(FALSE);
  105. }
  106. /* Ensure that ANSI and/or AVATAR mode is available. */
  107. if(!od_control.user_ansi && !od_control.user_avatar)
  108. {
  109. od_control.od_error = ERR_NOGRAPHICS;
  110. OD_API_EXIT();
  111. return(FALSE);
  112. }
  113. /* If OpenDoors is operating in remote mode. */
  114. if(od_control.baud != 0)
  115. {
  116. /* Allocate temporary buffer to store original screen contents while */
  117. /* buffer paste is being performed. */
  118. if((pBuffer=malloc(nRowBytes*(nBottom-nTop+1)))==NULL)
  119. {
  120. od_control.od_error = ERR_MEMORY;
  121. OD_API_EXIT();
  122. return(FALSE);
  123. }
  124. /* Get current screen contents of area to be pasted into, storing */
  125. /* into the temporary buffer. */
  126. if(!ODScrnGetText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, (BYTE)nBottom,
  127. pBuffer))
  128. {
  129. od_control.od_error = ERR_PARAMETER;
  130. free(pBuffer);
  131. OD_API_EXIT();
  132. return(FALSE);
  133. }
  134. }
  135. /* Display the block to be pasted on the local screen. */
  136. if(!ODScrnPutText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, (BYTE)nBottom,
  137. pBlock))
  138. {
  139. od_control.od_error = ERR_PARAMETER;
  140. if(pBuffer)
  141. free(pBuffer);
  142. OD_API_EXIT();
  143. return(FALSE);
  144. }
  145. /* If operating in remote mode. */
  146. if(od_control.baud != 0)
  147. {
  148. /* Loop for each line in the buffer to be pasted */
  149. for(nOutRow=nTop;nOutRow<=nBottom;++nOutRow,++nBlockRow)
  150. {
  151. /* Setup pointer to beginning of line of original screen contents. */
  152. pchScreenBlock=(char *)pBuffer+(nRowBytes*nBlockRow);
  153. /* Setup pointer to beginning of line of block to be displayed. */
  154. pchMemBlock=(char *)pBlock+(nRowBytes*nBlockRow);
  155. /* Loop for each column on this line. */
  156. for(nOutColumn=0;nOutColumn<nRowLength;)
  157. {
  158. /* Loop from this character onwards, counting number of */
  159. /* characters that don't need to be changed. */
  160. nCheckColumn=nOutColumn;
  161. pchMemory=((char *)pchMemBlock)+(nCheckColumn<<1);
  162. pchTest=((char *)pchScreenBlock)+(nCheckColumn<<1);
  163. for(;nCheckColumn<nRowLength;++nCheckColumn)
  164. {
  165. if(od_control.od_full_put) break;
  166. /* If both buffers have space characters. */
  167. if((*pchMemory==' ' || *pchMemory==0) && (*pchTest==' ' || *pchTest=='\0'))
  168. {
  169. /* If background colours differ, then stop comparison loop. */
  170. if((pchTest[1]&0x70) != (pchMemory[1]&0x70))
  171. {
  172. break;
  173. }
  174. }
  175. /* If both have different character and colour attributes. */
  176. else if(*((WORD *)pchTest) != *((WORD *)pchMemory))
  177. {
  178. /* Then stop comparison loop now. */
  179. break;
  180. }
  181. /* Increment source and background pointers by two bytes. */
  182. pchTest+=2;
  183. pchMemory+=2;
  184. }
  185. /* If no futher text to change on this line. */
  186. if(nCheckColumn==nRowLength)
  187. {
  188. /* Move to the next line. */
  189. goto next_line;
  190. }
  191. /* If this is the first text to be displayed on this line. */
  192. if(nOutColumn == 0)
  193. {
  194. /* Move the cursor to the first text to be changed on line. */
  195. nOutColumn = nCheckColumn;
  196. /* If AVATAR mode is available. */
  197. if(od_control.user_avatar)
  198. {
  199. /* Send the avatar cursor positioning command. */
  200. szODWorkString[0]=22;
  201. szODWorkString[1]=8;
  202. szODWorkString[2]=nOutRow;
  203. szODWorkString[3]=nLeft+nOutColumn;
  204. od_disp(szODWorkString,4,FALSE);
  205. }
  206. else
  207. {
  208. /* Otherwise, send the ANSI cursor positioning command. */
  209. sprintf(szODWorkString,"x[%d;%dH",nOutRow,nLeft + nOutColumn);
  210. szODWorkString[0]=27;
  211. od_disp(szODWorkString, strlen(szODWorkString), FALSE);
  212. }
  213. }
  214. /* If the number of characters after current cursor position */
  215. /* which must be changed, is greater than the number of */
  216. /* characters required to reposition the cursor on this line, */
  217. /* then move the cursor to skip unchanged characters. */
  218. else if((nCheckColumn-nOutColumn)>nMoveCost)
  219. {
  220. nOutColumn=nCheckColumn;
  221. /* If AVATAR mode is available. */
  222. if(od_control.user_avatar)
  223. {
  224. /* Advance cursor appropriate number of characters */
  225. /* using the AVATAR cursor position command. */
  226. szODWorkString[0]=22;
  227. szODWorkString[1]=8;
  228. szODWorkString[2]=nOutRow;
  229. szODWorkString[3]=nLeft+nOutColumn;
  230. od_disp(szODWorkString,4,FALSE);
  231. }
  232. else
  233. {
  234. /* Otherwise, advance cursor appropriate number of */
  235. /* characters using the ANSI cursor position command. */
  236. sprintf(szODWorkString,"x[%d;%dH",nOutRow,nLeft + nOutColumn);
  237. szODWorkString[0]=27;
  238. od_disp(szODWorkString,strlen(szODWorkString),FALSE);
  239. }
  240. }
  241. /* Output text for the number of characters found to be */
  242. /* different. */
  243. pchTest=(char *)&pchMemBlock[nOutColumn*2];
  244. for(;nOutColumn<=nCheckColumn;++nOutColumn)
  245. {
  246. if(pchTest[1] != nOutColour)
  247. {
  248. od_set_attrib(nOutColour=pchTest[1]);
  249. }
  250. od_disp(pchTest,1,FALSE);
  251. pchTest++;
  252. pchTest++;
  253. }
  254. }
  255. next_line:
  256. ;
  257. }
  258. /* If not disabled, update cursor position. */
  259. if(bScrollAction)
  260. {
  261. od_set_cursor(ODTextInfo.cury,ODTextInfo.curx);
  262. }
  263. /* Deallocate temporary buffer. */
  264. free(pBuffer);
  265. }
  266. /* Restore the original display attribute. */
  267. od_set_attrib(ODTextInfo.attribute);
  268. /* Return with success. */
  269. OD_API_EXIT();
  270. return(TRUE);
  271. }
  272. /* ----------------------------------------------------------------------------
  273. * od_gettext()
  274. *
  275. * Retrieves text from the screen (based on what is current displayed on the
  276. * local display), storing it in the buffer provided by the caller.
  277. *
  278. * Parameters: nLeft - Column number of left edge of block of text to
  279. * transfer, where 1 is the leftmost column of the
  280. * screen.
  281. *
  282. * nTop - Row number of the top edge of block of text to
  283. * to transfer, where 1 is the top row of the screen.
  284. *
  285. * nRight - Column number of the right edge of block.
  286. *
  287. * nBottom - Row number of bottom edge of block.
  288. *
  289. * pBlock - Pointer to buffer large enough to hold two bytes
  290. * for each character in the block.
  291. *
  292. * Return: TRUE on success, FALSE on failure.
  293. */
  294. ODAPIDEF BOOL ODCALL od_gettext(INT nLeft, INT nTop, INT nRight, INT nBottom,
  295. void *pBlock)
  296. {
  297. BYTE btMaxRight, btMaxBottom;
  298. /* Log function entry if running in trace mode. */
  299. TRACE(TRACE_API, "od_gettext()");
  300. /* Initialize OpenDoors if not already done. */
  301. if(!bODInitialized) od_init();
  302. OD_API_ENTRY();
  303. ODScrnGetTextInfo(&ODTextInfo);
  304. btMaxRight=ODTextInfo.winright-ODTextInfo.winleft+1;
  305. btMaxBottom=ODTextInfo.winbottom-ODTextInfo.wintop+1;
  306. if(nLeft<1 || nTop<1 || nRight>btMaxRight || nBottom>btMaxBottom || !pBlock)
  307. {
  308. od_control.od_error = ERR_PARAMETER;
  309. OD_API_EXIT();
  310. return(FALSE);
  311. }
  312. if(!od_control.user_ansi && !od_control.user_avatar)
  313. {
  314. od_control.od_error = ERR_NOGRAPHICS;
  315. OD_API_EXIT();
  316. return(FALSE);
  317. }
  318. OD_API_EXIT();
  319. return(ODScrnGetText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight, (BYTE)nBottom,
  320. pBlock));
  321. }
  322. /* ----------------------------------------------------------------------------
  323. * od_scroll()
  324. *
  325. * Scrolls the specified area of the screen by the specified number of
  326. * lines, in either the up or down directions. The cursor is left at its
  327. * original locaiton, and the display attribute is left at its original
  328. * setting. New lines are created in the current display colour.
  329. *
  330. * Parameters: nLeft - Column number of left edge of area to scroll, where
  331. * 1 is the leftmost column of the screen.
  332. *
  333. * nTop - Row number of the top edge of the area to scroll,
  334. * where 1 is the top row of the screen.
  335. *
  336. * nRight - Column number of the right edge of area to scroll.
  337. *
  338. * nBottom - Row number of bottom edge of area to scroll.
  339. *
  340. * nDistance - Number of lines to scroll the text. A value of 0
  341. * has no effect on the specified area, a positive
  342. * value moves the text upwards (leaving blank lines
  343. * at the bottom of the specified area), while a
  344. * negative value moves the text upwards. If the
  345. * distance is equal to the number of lines in the
  346. * area, then the entire area is cleared.
  347. *
  348. * nFlags - Bitwise-or (|) of SCROLL_* flags. SCROLL_NORMAL
  349. * is the default. SCROLL_NO_CLEAR does not clear
  350. * the new area at the top/bottom of the scroll
  351. * region if doing so would be slower.
  352. *
  353. * Return: TRUE on success, FALSE on failure.
  354. */
  355. ODAPIDEF BOOL ODCALL od_scroll(INT nLeft, INT nTop, INT nRight, INT nBottom,
  356. INT nDistance, WORD nFlags)
  357. {
  358. BYTE btWidth, btHeight;
  359. BYTE btCount;
  360. BYTE btFirst, btLast;
  361. char szAVTSeq[7];
  362. void *pBlock;
  363. char szBlank[81];
  364. BYTE btKeepHeight;
  365. BYTE btMaxRight;
  366. BYTE btMaxBottom;
  367. tODScrnTextInfo TextState;
  368. /* Log function entry if running in trace mode. */
  369. TRACE(TRACE_API, "od_scroll()");
  370. /* Ensure that OpenDoors has been initialized before proceeding. */
  371. if(!bODInitialized) od_init();
  372. OD_API_ENTRY();
  373. /* Get current display setting information. */
  374. ODScrnGetTextInfo(&TextState);
  375. /* Determine the height and width of the area to be scrolled. */
  376. btWidth=nRight-nLeft+1;
  377. btHeight=nBottom-nTop+1;
  378. /* Determine the number of lines currently in the area that will still */
  379. /* be visible after scrolling. */
  380. btKeepHeight=btHeight-((nDistance>=0) ? nDistance : -nDistance);
  381. /* Determine the maximum bottom and left coordinates of an area to be */
  382. /* scrolled. */
  383. btMaxRight=TextState.winright-TextState.winleft+1;
  384. btMaxBottom=TextState.winbottom-TextState.wintop+1;
  385. /* Check that parameters are valid. */
  386. if(nLeft<1 || nTop<1 || nRight>btMaxRight || nBottom>btMaxBottom ||
  387. nLeft > nRight || nTop > nBottom)
  388. {
  389. od_control.od_error = ERR_PARAMETER;
  390. OD_API_EXIT();
  391. return(FALSE);
  392. }
  393. /* Check that ANSI or AVATAR graphics mode is available. */
  394. if(!od_control.user_ansi && !od_control.user_avatar)
  395. {
  396. od_control.od_error = ERR_NOGRAPHICS;
  397. OD_API_EXIT();
  398. return(FALSE);
  399. }
  400. /* If distance to be scrolled is 0, then we are finished already and */
  401. /* can return immediately. */
  402. if(nDistance == 0)
  403. {
  404. OD_API_EXIT();
  405. return(TRUE);
  406. }
  407. /* If distance is positive, then we are moving text upwards. */
  408. if(nDistance>0)
  409. {
  410. /* Ensure that distance is not greater than size of scrolled area. */
  411. if(nDistance>btHeight)
  412. {
  413. nDistance=btHeight;
  414. }
  415. /* Calculate first and last line to be moved. */
  416. btFirst=nBottom-(nDistance-1);
  417. btLast=nBottom;
  418. }
  419. /* If distance is negative, then we are moving text downwards. */
  420. else /* if(nDistance<0) */
  421. {
  422. /* Ensure that distance is not greater than size of scrolled area. */
  423. if(nDistance<-btHeight)
  424. {
  425. nDistance=-btHeight;
  426. }
  427. /* Calculate first and last line to be moved. */
  428. btFirst=nTop;
  429. btLast=nTop-nDistance-1;
  430. }
  431. /* If AVATAR mode is available */
  432. if(od_control.user_avatar)
  433. {
  434. /* Generate AVATAR sequence which causes the remote terminal to */
  435. /* scroll an area of its screen. */
  436. szAVTSeq[0]=22;
  437. /* If scrolling text upwards. */
  438. if(nDistance>0)
  439. {
  440. /* Specify control sequence for scrolling upwards. */
  441. szAVTSeq[1]=10;
  442. szAVTSeq[2]=nDistance;
  443. /* Move text appropriate direction on local screen. */
  444. ODScrnCopyText((BYTE)nLeft, (BYTE)(nTop + nDistance), (BYTE)nRight,
  445. (BYTE)nBottom, (BYTE)nLeft, (BYTE)nTop);
  446. }
  447. /* If scrolling text downwards. */
  448. else /* if(disatnce<0) */
  449. {
  450. /* Specify control sequence for scrolling downwards. */
  451. szAVTSeq[1]=11;
  452. szAVTSeq[2]=-nDistance;
  453. /* Move text appropriate direction on local screen. */
  454. ODScrnCopyText((BYTE)nLeft, (BYTE)nTop, (BYTE)nRight,
  455. (BYTE)(nBottom + nDistance), (BYTE)nLeft, (BYTE)(nTop - nDistance));
  456. }
  457. /* Specify area to be scrolled to the AVATAR terminal. */
  458. szAVTSeq[3]=nTop;
  459. szAVTSeq[4]=nLeft;
  460. szAVTSeq[5]=nBottom;
  461. szAVTSeq[6]=nRight;
  462. /* Send the control sequence to the AVATAR terminal. */
  463. od_disp(szAVTSeq,7,FALSE);
  464. /* Generate string containing a blank line of text. */
  465. for(btCount=0;btCount<btWidth;++btCount) szBlank[btCount]=' ';
  466. szBlank[btCount]='\0';
  467. /* Blank-out lines that will no longer be visiable. */
  468. for(;btFirst<=btLast;++btFirst)
  469. {
  470. ODScrnSetCursorPos((BYTE)nLeft, btFirst);
  471. ODScrnDisplayString(szBlank);
  472. }
  473. /* Reset cursor position on local display. */
  474. ODScrnSetCursorPos(TextState.curx,TextState.cury);
  475. }
  476. /* Otherwise, we are using ANSI mode. */
  477. else /* if(od_control.user_ansi) */
  478. {
  479. /* If any of the original text will still be available after */
  480. /* scrolling. */
  481. if(btKeepHeight>0)
  482. {
  483. /* Allocate some temporary memory to hold text to be "got". */
  484. if((pBlock=malloc(btKeepHeight*btWidth*2))==NULL)
  485. {
  486. /* If memory allocation failed, then scrolling fails. */
  487. od_control.od_error = ERR_MEMORY;
  488. OD_API_EXIT();
  489. return(FALSE);
  490. }
  491. /* If we are scrolling text upwards. */
  492. if(nDistance > 0)
  493. {
  494. /* Move text that will still be visible, using od_gettext() */
  495. /* and od_puttext(). */
  496. od_gettext(nLeft,nTop+nDistance,nRight,nBottom,pBlock);
  497. bScrollAction=FALSE;
  498. od_puttext(nLeft,nTop,nRight,nBottom-nDistance,pBlock);
  499. bScrollAction=TRUE;
  500. }
  501. /* If we are scrolling text downwards. */
  502. else /* if(nDistance < 0) */
  503. {
  504. /* Move text that will still be visible, using od_gettext() */
  505. /* and od_puttext(). */
  506. od_gettext(nLeft,nTop,nRight,nBottom+nDistance,pBlock);
  507. bScrollAction=FALSE;
  508. od_puttext(nLeft,nTop-nDistance,nRight,nBottom,pBlock);
  509. bScrollAction=TRUE;
  510. }
  511. /* Deallocate temporary memory block. */
  512. free(pBlock);
  513. }
  514. /* If new area clearing has not been disabled. */
  515. if(!(nFlags&SCROLL_NO_CLEAR))
  516. {
  517. /* Loop for lines that should be blank. */
  518. for(;btFirst<=btLast;++btFirst)
  519. {
  520. /* Move cursor to the beginning of this line. */
  521. od_set_cursor(btFirst,nLeft);
  522. /* If right boarder of area to be scrolled is the edge of the */
  523. /* screen, then we can use a quick control sequence to clear */
  524. /* the rest of the line. Call od_clr_line() to do this. */
  525. if(nRight == 80)
  526. {
  527. od_clr_line();
  528. }
  529. /* If right boarder of area to be scrolled is not at the edge */
  530. /* of the screen, then each line must be manually erased, by */
  531. /* sending the appropriate number of blanks (spaces). */
  532. else /* if(right != 80) */
  533. {
  534. od_repeat(' ',btWidth);
  535. }
  536. }
  537. }
  538. /* Reset the cursor to its original position. */
  539. od_set_cursor(TextState.cury,TextState.curx);
  540. }
  541. /* Return with success */
  542. OD_API_EXIT();
  543. return(TRUE);
  544. }
  545. /* ----------------------------------------------------------------------------
  546. * od_save_screen()
  547. *
  548. * Stores the contents of the entire screen into a buffer, along with
  549. * the current cursor location and display colour. Supports all display
  550. * modes.
  551. *
  552. * Parameters: pBuffer - Pointer to a buffer of at least 4004 bytes in size,
  553. * where the information on the current screen state
  554. * will be stored.
  555. *
  556. * Return: TRUE on success, FALSE on failure.
  557. */
  558. ODAPIDEF BOOL ODCALL od_save_screen(void *pBuffer)
  559. {
  560. char btHeight;
  561. tODScrnTextInfo TextState;
  562. /* Log function entry if running in trace mode. */
  563. TRACE(TRACE_API, "od_save_screen()");
  564. /* Ensure that OpenDoors is initialized before proceeding. */
  565. if(!bODInitialized) od_init();
  566. OD_API_ENTRY();
  567. /* Check parameters and current output window size. */
  568. ODScrnGetTextInfo(&TextState);
  569. if(TextState.winleft!=1 || TextState.winright!=80 || !pBuffer)
  570. {
  571. od_control.od_error = ERR_PARAMETER;
  572. OD_API_EXIT();
  573. return(FALSE);
  574. }
  575. /* Store current cursor location in buffer. */
  576. ((char *)pBuffer)[0]=TextState.curx;
  577. ((char *)pBuffer)[1]=TextState.cury;
  578. /* Store current display colour in buffer. */
  579. ((char *)pBuffer)[2]=TextState.attribute;
  580. /* Store height of buffer stored. */
  581. ((char *)pBuffer)[3]=btHeight=TextState.winbottom-TextState.wintop+1;
  582. /* Store screen contents using local screen gettext() function. */
  583. OD_API_EXIT();
  584. return(ODScrnGetText(1,1,80,btHeight,(char *)pBuffer+4));
  585. }
  586. /* ----------------------------------------------------------------------------
  587. * od_restore_screen()
  588. *
  589. * Restores the screen contents, along with the current text colour and cursor
  590. * location, as previously stored by od_save_screen().
  591. *
  592. * Parameters: pBuffer - Pointer to buffer which was filled by a previous call
  593. * to od_save_screen().
  594. *
  595. * Return: TRUE on success, FALSE on failure.
  596. */
  597. ODAPIDEF BOOL ODCALL od_restore_screen(void *pBuffer)
  598. {
  599. char *pch;
  600. char btPos;
  601. char chLast;
  602. char *pchTextBuffer;
  603. char btHeight;
  604. int nToReturn=TRUE;
  605. tODScrnTextInfo TextState;
  606. char btLine;
  607. char btDistance=0;
  608. char btCursorRow;
  609. /* Log function entry if running in trace mode. */
  610. TRACE(TRACE_API, "od_restore_screen()");
  611. /* Ensure that OpenDoors is initialized before proceeding. */
  612. if(!bODInitialized) od_init();
  613. OD_API_ENTRY();
  614. /* Check parameters and current output window size. */
  615. ODScrnGetTextInfo(&TextState);
  616. if(TextState.winleft!=1 || TextState.winright!=80 || !pBuffer)
  617. {
  618. od_control.od_error = ERR_PARAMETER;
  619. OD_API_EXIT();
  620. return(FALSE);
  621. }
  622. /* Determine current window height were text will be restored. */
  623. btHeight=TextState.winbottom-TextState.wintop+1;
  624. /* If current display window height is too small for entire buffer */
  625. /* to be re-displayed. */
  626. if(btHeight<((char *)pBuffer)[3])
  627. {
  628. /* Then we will always display as much of the END of the buffer */
  629. /* as possible. */
  630. btDistance = btHeight - ((char *)pBuffer)[3];
  631. }
  632. else if(btHeight > ((char *)pBuffer)[3])
  633. {
  634. /* Otherwise, ensure that we don't try to display more lines that */
  635. /* are in the buffer. */
  636. btHeight=((char *)pBuffer)[3];
  637. }
  638. /* Clear the remote and local screens. */
  639. od_clr_scr();
  640. /* If ANSI or AVATAR modes are available. */
  641. if(od_control.user_avatar || od_control.user_ansi)
  642. {
  643. /* Then we can efficiently display the buffer using od_puttext(). */
  644. bScrollAction=FALSE;
  645. nToReturn=od_puttext(1,1,80,btHeight,(char *)pBuffer+(4+((int)btDistance*160)));
  646. bScrollAction=TRUE;
  647. /* Restore original cursor location. */
  648. od_set_cursor(((char *)pBuffer)[1],((char *)pBuffer)[0]);
  649. /* Restore original display attribute. */
  650. od_set_attrib(((char *)pBuffer)[2]);
  651. }
  652. /* If we are operating in ASCII mode. */
  653. else /* if (!od_control.od_avatar && !od_control.caller_ansi) */
  654. {
  655. /* Then the buffer is displayed one line at a time, beginning */
  656. /* at the top of the screen, up to the saved cusrsor location. */
  657. /* Set pointer to beginning of buffer to be displayed. */
  658. pchTextBuffer=(char *)pBuffer+4;
  659. /* Get final cursor row number. */
  660. btCursorRow=((char *)pBuffer)[1];
  661. /* Loop for each line in the buffer. */
  662. for(btLine=1;btLine<=btHeight;++btLine)
  663. {
  664. /* Set pointer to last character of line. */
  665. pch=(char *)pchTextBuffer+158;
  666. /* Loop backwards until a non-blank character is found, or we */
  667. /* reach the beginning of the line. */
  668. for(chLast=80;chLast>1;)
  669. {
  670. /* If this is a blank character. */
  671. if(*pch==32 || *pch==0)
  672. {
  673. /* Move to previous character. */
  674. --chLast;
  675. pch-=2;
  676. }
  677. /* If this is not a blank character, then stop looping. */
  678. else
  679. {
  680. break;
  681. }
  682. }
  683. /* If this is the line on which the cursor resides. */
  684. if(btLine==btCursorRow)
  685. {
  686. /* If last non-blank character of line is at or past the final */
  687. /* cursor location, then we backup the last character to be */
  688. /* displayed to the cursor before the final cursor position. */
  689. /* This code could be improved to be able to display text on */
  690. /* the entire cursor line by displaying the entire line, */
  691. /* sending a C/R, and redisplaying first portion of line to */
  692. /* end up with the cursor in the desired position. */
  693. if(chLast>=((char *)pBuffer)[0])
  694. {
  695. chLast=((char *)pBuffer)[0]-1;
  696. }
  697. }
  698. /* Display all characters on this line */
  699. pch = (char *)pchTextBuffer;
  700. for(btPos=1;btPos<=chLast;++btPos)
  701. {
  702. od_putch(*pch);
  703. pch+=2;
  704. }
  705. /* If this is the row where the cursor should be left, then we */
  706. /* stop displaying now. */
  707. if(btLine==btCursorRow)
  708. {
  709. break;
  710. }
  711. /* If cursor hasn't been wrapped, then we should send a C/R - */
  712. /* L/F sequence. */
  713. if(chLast != 80)
  714. {
  715. od_disp_str("\n\r");
  716. pchTextBuffer+=160;
  717. }
  718. }
  719. }
  720. /* Return with the appropriate success/failure status. */
  721. OD_API_EXIT();
  722. return(nToReturn);
  723. }