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