forked from microsoft/GW-BASIC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SCNDRV.ASM
2466 lines (2297 loc) · 75.2 KB
/
SCNDRV.ASM
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
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; [ This translation created 10-Feb-83 by Version 4.3 ]
.RADIX 8 ; To be safe
CSEG SEGMENT PUBLIC 'CODESG'
ASSUME CS:CSEG
INCLUDE OEM.H
TITLE SCNDRV This is the OS independent Screen Driver for GW BASIC
SUBTTL DATA DEFINITIONS - Miscellaneous
COMMENT *
--------- --- ---- -- ---------
COPYRIGHT (C) 1982 BY MICROSOFT
--------- --- ---- -- ---------
PROGRAMMER: MARC WILSON
*
INCLUDE GIO86U
.SALL
.RADIX 8
;OEM IFNDEFs
MELCO=0
CANON=0
;GENERIC IFNDEF'S:
TERMSW=0
HLPEDT=0
NMPAGE=1 ;Number of pages
NEWCHP=1 ;New change page routine
IBMEOL=IBMLIK ;Clear to EOL for COMPATIBILITY
IBMCSR=IBMLIK ;IBM COMPATIBILITY for cursor
;Definition of scroll types
; Choice of scroll type is by switch SCROLT.
; Switches defined here are used to implement a specific SCROLT type.
; If other scroll types are needed then additional SCROLT types should be
; defined here.
INVLIN=SCROLT ;Invisible (function key) Line
FKFSRL=(SCROLT-1) AND 1 ;Clear fkeys/full scroll/rewrite fkeys
;OTHER GENERIC SWITCHES(OEM SPECIFIC)
TXTWDO=0 ;list of OEM's which have window setting capability
SUBTTL DATA DEFINITIONS - Internal routines(with usage description)
;Entry points
PUBLIC SCNSWI ; Set CRT physical line width
;on entry: AL=width, CL=height
PUBLIC SCNCLR ; Clear CRT, Refresh Function Key Display,
; Home Graphics and Text Cursors
;on entry: none
PUBLIC SCNLOC ; Locate cursor on physical screen(1,1 = HOME)
;on entry: AH=column(x), AL=line(y)
PUBLIC SCNOUT ; Character output at current position
;on entry: AX=character
PUBLIC SCNRDL ; Read a physical line at current position
;on entry: DI=address of where to put string, CX=max count
;on exit: CX=CX-number of characters read
; DI=DI+number of characters read
PUBLIC SCNPOS ; Return current cursor location
;on exit: DL=cursor line, DH=cursor column
PUBLIC SCNRDT ; Read terminator for physical line
;on entry: DL=line number
;on exit: AH= terminator column, AL=terminator value
; Flags indicate terminator value:
; CF=EOL, ZF=Linefeed
PUBLIC SCNGWI ; Read logical width of lines
;on exit: AH=logical width of lines
PUBLIC SCNMRK ; Mark position as current FSTPOS, LSTPOS
;on entry: ZF set indicates use WDOLFT as column
; ZF clear indicates use CSRX as column
PUBLIC SCNIPL ; Initialize - called during IPL
PUBLIC SCNBRK ; Initialize - called when BREAK received by POLKEY
SUBTTL DATA DEFINITIONS - External routines and data
;EXTERNAL ROUTINES
EXTRN SCROLL:NEAR ; OEM supplied SCROLL routine
EXTRN SCROUT:NEAR ; OEM supplied character output
EXTRN SCRINP:NEAR ; OEM supplied screen input(read character)
EXTRN CLREOL:NEAR ; OEM supplied screen clear to end of line
;THE FOLLOWING IS DATA UNIQUE TO THE SCNDRV MODULE
; ALL DATA IS ONE BYTE LONG UNLESS STATED OTHERWISE
DSEG SEGMENT PUBLIC 'DATASG'
ASSUME DS:DSEG
EXTRN LINCNT:WORD ; Number of lines
EXTRN CRTWID:WORD ; Characters per line
EXTRN WDOTOP:WORD ; Top line in window(1-[LINCNT])
EXTRN WDOBOT:WORD ; Bottom line in window([WDOTOP]-[LINCNT])
EXTRN WDOLFT:WORD ; Leftmost column in window(1-[CRTWID])
EXTRN WDORGT:WORD ; Rightmost column plus one([WDOLFT]-[LINCNT])
EXTRN LINLEN:WORD ; Line max width(1 to CRTWID)
EXTRN LINTTB:WORD ; Line terminator table((# lines * 2) bytes long)
; Two items per entry:
; Terminator, last column
EXTRN TRMCUR:WORD ; Address of current terminator entry(2 bytes)
EXTRN FSTLIN:WORD ; Line number saved by SCNSTM call
EXTRN FSTCOL:WORD ; Column saved as above and decreases to WDOLFT
EXTRN LSTLIN:WORD ; Line number saved by SCNSTM and grows as the
; logical line grows.
EXTRN LSTCOL:WORD ; Column saved as above which grows as the logical
; line grows(always reflects last col on LSTLIN).
EXTRN F_CRET:WORD ; Zero indicates last character output was CR
EXTRN CSRY:WORD ; Current line(1-[LINCNT])
EXTRN CSRX:WORD ; Current column(1-[CRTWID])
EXTRN KEYSW:WORD ; ^O377=Function Keys displayed on bottom line
;THE FOLLOWING DATA IS ACCESSED BY SCNDRV BUT SET ELSEWHERE
EXTRN F_EDIT:WORD ; Set to non-zero by INLIN when editing
EXTRN F_INST:WORD ; Set to non-zero by INLIN for insert mode
DSEG ENDS
SUBTTL DATA DEFINITIONS - Literals
;CHARACTER DEFINITIONS
;
CHREDT=1 ; EDiT
CHRBKW=2 ; BacK Word
CHRCAN=3 ; CANcel
CHRHCN=4 ; Hard CaNcel
CHRCLE=5 ; CLear to End of line
CHRFDW=6 ; ForwarD Word
CHRBEL=7 ; BELl
CHRBAK=8D ; BAcKspace
CHRTAB=9D ; TAB
CHRLNF=10D ; LiNeFeed
CHRHOM=11D ; HOMe
CHRERA=12D ; ERAse
CHRRET=13D ; RETurn
CHRAPP=14D ; APPend
CHRINS=18D ; INSert
CHRFKD=20D ; Function Key Display key
CHRLDL=21D ; Line DeLete
CHRADV=28D ; cursor RiGhT
CHRREG=29D ; cursor LeFT
CHRUP=30D ; cursor UP
CHRDWN=31D ; cursor DoWN
CHRDEL=127D ; DELete
;TERMINATOR TABLE LITERALS
PUBLIC TRMLNF
TRMLNF=10D ; LINEFEED terminator
PUBLIC TRMEOL
TRMEOL=177O ; EOL terminator
PUBLIC TRMWRP
TRMWRP=0 ; WRAP terminator
PUBLIC TRMNWP
TRMNWP=1 ; NULL WRAP terminator
PUBLIC TRMNUL
TRMNUL=200O ; Sign bit indicates initialize line
;DEFAULT SCREEN SIZE
PUBLIC SCNSIZ
SCNSIZ=20D+(40D*400O) ; Height = 20, Width = 40
SUBTTL SCNIPL, SCNSWI AND SCNWDO The parameter setting routines
;SUBROUTINE SCNIPL(): ; Initialize
;**
SCNIPL:
DSEG SEGMENT PUBLIC 'DATASG'
EXTRN ESCFLG:WORD
DSEG ENDS
MOV BYTE PTR ESCFLG,LOW 0
RET
;** END SUBROUTINE SCNIPL
;BREAK - reset flags etc. when ^C typed.
;
SCNBRK: MOV BYTE PTR FSTLIN,LOW 0
MOV BYTE PTR LSTLIN,LOW 377O ; Set FSTPOS, LSTPOS to impossible values
MOV BYTE PTR F_CRET,LOW 377O ; Clear "last char was CR" flag
RET
;SUBROUTINE SCNSWI(WIDTH,HEIGHT): ; Set screen width(logical/physical) and height
;** on entry: AL=width, CL=height
;**
SCNSWI: MOV BYTE PTR CRTWID,AL ; Save physical width
MOV BYTE PTR LINLEN,AL ; Set logical line length
MOV BYTE PTR LINCNT,CL ; Save physical height
MOV BYTE PTR WDOTOP,LOW 1 ; Init window top
PUSH CX
DEC CL ; Reserve status line
MOV BYTE PTR WDOBOT,CL ; Set window bottom
POP CX
MOV BYTE PTR WDOLFT,LOW 1 ; Set window left
MOV BYTE PTR WDORGT,AL ; Set window right
RET
;** *** END
;** END SUBROUTINE SCNSWI
;SUBROUTINE SCNWDO(POSN,COUNT): ; Set text window
;**
;** on entry: AH=column posn, AL=line posn
;** CH=width, CL=height
;** on exit: AX,CX=values actually set
;** CF indicates posn outside screen
;**
;** NOTE: This routine truncates width and height.
;**
;** IF POSN IS CONTAINED WITHIN PHYSICAL SCREEN BEGIN
SUBTTL CURSOR READ/WRITE
;SUBROUTINE SCNLOC(X,Y): ; Locate cursor on physical screen
;** on entry: AH=column, AL=line(1,1 is home)
;**
SCNLOC: MOV BYTE PTR CSRX,AH
MOV BYTE PTR CSRY,AL
RET
;** END SUBROUTINE SCNLOC
;SUBROUTINE SCNCLR(X,Y): ; Clear Screen, Home Text & Graphics Cursor,
; ; Refresh Function Key Display
;** on entry:
;
EXTRN KEYDSP:NEAR,GRPINI:NEAR
SCNCLR:
CALL TTBINI ;Clear the terminator table
CALL GRPINI ;Home the graphics cursor
CALL WHOME ;DX=cursor home
MOV AX,DX
CALL SCNLOC ;set cursor position
JMP KEYDSP ;Conditionally display softkeys and return
;** END SUBROUTINE SCNCLR
;SUBROUTINE SCNPOS ; Read current cursor location
SCNPOS: MOV DH,BYTE PTR CSRX
MOV DL,BYTE PTR CSRY
PUSHF
CMP DH,BYTE PTR LINLEN
JBE SCNPS1 ;BRIF not beyond edge of screen
MOV DH,BYTE PTR LINLEN ;Force posn within screen
SCNPS1: POPF
RET
;** END SUBROUTINE SCNPOS
;SUBROUTINE SCNGWI ; Read current logical width
;** on exit: AH=width
;**
SCNGWI: MOV AH,BYTE PTR LINLEN
RET
;** END SUBROUTINE SCNGWI
SUBTTL TERMINATOR TABLE READ/WRITE/INITIALIZE
;SUBROUTINE SCNRDT(Y): ; Read terminator value and column
;** on entry: DL=line number
;** on exit: AH=terminator posn, AL=terminator value
;** If CF=1; EOL
;** If CF=0 and ZF=1; LF terminated
;**
SCNRDT: PUSH BX
MOV BL,DL ; BX = Displacement into table
ADD BL,BL
MOV BH,LOW 0
MOV WORD PTR TRMCUR,BX ; Save address of terminator reading(for set term)
MOV AH,BYTE PTR LINTTB[BX-2] ; Get terminator posn
MOV AL,BYTE PTR LINTTB[BX-1] ; Get terminator value
AND AL,LOW OFFSET 377O-TRMNUL ; Get rid of initialize line status bit
CMP AL,LOW OFFSET TRMEOL
STC
JZ SCNRTX ; BRIF EOL terminator(CF=1)
CMP AL,LOW OFFSET TRMLNF ; CF=0, set ZF if linefeed terminated
JNB SCNRTX ; BRIF carry not set
CMC ; clear carry
SCNRTX: POP BX
RET
;** END SUBROUTINE SCNRDT
;SUBROUTINE SCNWTT(TERM) ; Set new value for terminator last read
;** on entry: AH=column where physical line ends
;** AL=terminator type(one of: TRMEOL, TRMLNF
;** TRMWRP, TRMNWP)
;**
SCNWTT: PUSH BX
MOV BX,WORD PTR TRMCUR ; Get address of terminator last read
MOV BYTE PTR LINTTB[BX-2],AH
AND BYTE PTR LINTTB[BX-1],LOW OFFSET TRMNUL
OR BYTE PTR LINTTB[BX-1],AL ; Write new terminator, leaving NULL bit
POP BX
RET
;** END SUBROUTINE SCNWTT
;TERMINATOR TABLE INIT
;
TTBINI: MOV CX,OFFSET NMLINE+1 ; CX=count of line term table entries
MOV BX,OFFSET LINTTB ; BX=addr of line term table
TTBIN0: MOV BYTE PTR 0[BX],LOW 0 ; Clear column number
MOV BYTE PTR 1[BX],LOW OFFSET TRMEOL ; Set terminator to <CR>
INC BX
INC BX
LOOP TTBIN0 ; Init entire line terminator table
RET
SUBTTL CHARACTER OUTPUT
;SUBROUTINE SCNOUT(CHAR): ; Output character
;** on entry: AX= character
;**
SCNOUT: PUSH DX
PUSH CX
PUSH BX
CALL CTLDSP ; If control char or ESC sequence, do operation
JB SCNOTX ; No char to output
CALL CHWRAP ; Do wrap for char in AX, return DX=posn for output
EXTRN SETCSR:NEAR
DSEG SEGMENT PUBLIC 'DATASG'
EXTRN CSRTYP:WORD
DSEG ENDS
MOV BYTE PTR CSRTYP,LOW 0D ; Set next cursor type to off
CALL SETCSR ; Insure that the cursor is off
CALL SCROUT ; Send char in AX to BIOS at DX posn
MOV BYTE PTR F_CRET,LOW 377O ; Clear last char was Carriage return flag
SCNOTX: POP BX
POP CX
POP DX
RET
;** END SUBROUTINE SCNOUT
;SUBROUTINE MKRMCI ; Open up sapce for char if insert mode
;
MKRMCI: PUSHF
TEST BYTE PTR F_INST,LOW 377O
JZ MKRCIX ; BRIF not insert mode(do nothing)
POPF
MOV CH,AL
INC CH ; CH=space needed
CALL MKRMCH ; Open up space at (DH,DL) for count of CH
CALL SCNRDX ; Put terminator table values in CX
RET
MKRCIX: POPF
RET
SCNRDX: XCHG AX,CX
CALL SCNRDT
XCHG AX,CX
RET
SUBTTL LINE WRAP LOGIC - Character wrap
;THE LINE WRAP LOGIC IS USED PRIOR TO OUTPUTTING CHARACTERS OR STRINGS
; IT WILL RESERVE THE NECESSARY NUMBER OF CHARACTERS ON THE CURRENT
; LOGICAL LINE OR WILL RETURN CARRY SET AND DX=POSN WHERE CHARACTER
; CAN BE OUTPUT(I.E. IT RETURNS A POSN LESS THAN CURRENT POSN)
;SUBROUTINE CHWRAP(CHAR): ; Do single character wrap
;** on entry: AX=character
;** DH=CSRX, DL=CSRY
;** on exit: if cannot wrap, CF=1
;** DX=posn where character can be output
;** cursor posn and terminator table are updated
;** NOTE: if CF=1 then DX may be set to a previous posn
;** where there is enough room to EOL.
;**
CHWRAP: PUSH AX
XOR CH,CH
OR AH,AH
JZ CHWRP0 ; BRIF Single byte character
MOV CH,LOW 1 ; It's two byte character
CHWRP0: MOV CL,CH
ADD CH,DH ; CH=column after char is output
CALL SCNRDT ; Read terminator
XCHG CX,AX
;** IF POSN .LT. EOL BEGIN
;** AT THIS POINT AH=POSN(WHERE GOING TO), DX=CURRENT POSN,
;** AL=LENGTH OF CHARACTER, CX=CURRENT TERMINATORS
PUSHF
CMP AH,BYTE PTR LINLEN
JA CHWRP1 ; BRIF not space before end of physical line
POPF
CALL MKRMCI ; If insert mode, open up space for character
;** *** IF NOT(LINEFEED .EQ. TERMINATOR(CURRENT_LINE) AND POSN .EQ. LINLEN)
;** *** *** RETURN, OUTPUT IS AT CURRENT POSN
JB CHWPXI ; EOL terminated, output at current posn
JZ CHWPLF ; BRIF LF terminated
CMP CL,LOW OFFSET TRMWRP
JZ CHWPXI ; BRIF WRAP(always room)
CMP AH,BYTE PTR LINLEN
JB CHWPXI ; BRIF NUL_WRAP and not overwriting NULL
MOV CL,LOW OFFSET TRMWRP
CHWPXI: JMP CHWRPX ; Overwriting NULL_WRAP, set to WRAP
CHWPLF: CMP AH,BYTE PTR LINLEN
JAE CHWPL1 ; LF terminated and no room for LF
INC AH ; Need to terminate at one past posn printing at
XCHG AX,CX
CMP AH,CH
MOV AH,CH
JA CHWPL0 ; BRIF current posn below terinator posn
CALL SCNWTT ; Terminate line at one more than print posn
CHWPL0: CLC
XCHG AX,CX
PUSHF
DEC AH ; Restore column actually printing at
JMP CHWRP9 ; Update LSTPOS, FSTPOS, cursor posn, exit
;** *** *** ELSE MOVE LINEFEED TO NEXT LINE
CHWPL1: CALL WRAPLF ; Move linefeed to next line
JB CHWRNI ; Error, output at posn-(char length)
CLC
PUSHF
MOV AH,CH
JMP CHWRP9 ; Exit without updating terminator
CHWRNI: JMP CHWRNO
;** *** END
;** *** DO CASE TERMINATOR(CURRENT_LINE) OF
;** *** There is not enough room on current line for character
CHWRP1: POPF
JB CHWREL ; BRIF EOL terminated
JZ CHWRLF ; BRIF LF terminated
;** *** CASE: WRAP; NULL_WRAP; BEGIN
;** *** *** *** SET WRAP TERMINATOR
CHWRWP: MOV CL,LOW OFFSET TRMWRP
MOV CH,BYTE PTR LINLEN
XCHG AX,CX
CALL SCNWTT ; Set wrap terminator at last column
CMP DL,BYTE PTR LSTLIN
JNZ CHWRN0 ; BRIF not on last line
INC BYTE PTR LSTLIN ; Wrap LSTLIN
MOV BYTE PTR LSTCOL,LOW 0 ; Force update of LSTCOL at CHWRPZ
CHWRN0: INC DL ; Next line
CALL SCNRDT ; Set up for write at new line
MOV DH,BYTE PTR WDOLFT ; First column is output posn
MOV CH,DH
ADD CH,CL ; CH=POSN going to
XCHG AX,CX
CALL MKRMCI ; If insert mode, open up space for character
CMP CL,LOW OFFSET TRMLNF
JNZ CHWRPX ; BRIF not linefeed terminated
XCHG AX,CX ; CH=POSN, AX=current terminators
INC CH ; Need terminator one beyond actual output
CMP AH,CH
MOV AH,CH
JA CHWRN2 ; BRIF Current terminator beyond posn for output
CALL SCNWTT ; Set current terminator to new max posn
CHWRN2: DEC CH ; Restore POSN going to
XCHG AX,CX
CHWRPX: CLC
JMP SHORT CHWRPZ ; All done
;** *** *** *** END
;** *** *** END
;** *** CASE: EOL
CHWREL: CALL MKRMNL ; Make room on next line(make it EOL term'd)
JB CHWRP3 ; If error, make room for char on this line
CALL SCNRDX ; Reread terminator for this line
JMP SHORT CHWRWP ; Wrap to next line
;** *** CASE: LF
CHWRLF: XCHG AX,CX
CALL WRAPLF ; First wrap LF to next line
MOV AL,LOW OFFSET TRMNWP ; Set to temporary NULL_WRAP at last column
MOV AH,BYTE PTR LINLEN
CALL SCNWTT
XCHG AX,CX
JNB CHWRWP ; Go do wrap for char
;No room, abort
CHWRP3: MOV AH,BYTE PTR LINLEN ; AH=POSN going to
CHWRNO: MOV DH,AH
SUB DH,AL ; DH=POSN-(char len)
STC ; Error return
;** *** END CASE TERMINATOR(CURRENT_LINE)
;** EXIT
CHWRPZ: PUSHF
XCHG AX,CX ; CH=POSN, AX=current terminators
CMP AH,CH
MOV AH,CH
JA CHWRP9 ; BRIF Current terminator beyond posn for output
PUSH AX
CALL SCNRDT
POP AX
CALL SCNWTT ; Set current terminator to new max posn
CHWRP9: MOV BYTE PTR CSRY,DL
CMP DL,BYTE PTR LSTLIN
JNZ CHWNTL ; BRIF not on last logical line
CMP AH,BYTE PTR LSTCOL
JB CHWNTL ; BRIF not new last position
MOV BYTE PTR LSTCOL,AH ; Set new last posn
CHWNTL: CMP DL,BYTE PTR FSTLIN
JNZ CHWNTF ; BRIF not on first logical line
CMP DH,BYTE PTR FSTCOL
JAE CHWNTF ; BRIF not new first position
MOV BYTE PTR FSTCOL,DH
CHWNTF: INC AH
MOV BYTE PTR CSRX,AH ; Set new posn(one past last posn printed at)
CMP BYTE PTR LINLEN,AH
JAE CHWNTG ; BRIF does not go beyond end of physical line
CALL SCNRDT
JB CHWNTG ; BRIF line does not continue
INC BYTE PTR CSRY ; Logical line continues, put cursor at
MOV AH,BYTE PTR WDOLFT ; start of next physical line
MOV BYTE PTR CSRX,AH
CHWNTG: POPF
POP AX
RET
;Wrap linefeed on end of line to next line
WRAPLF: PUSH WORD PTR TRMCUR
PUSH CX
PUSH DX
MOV DH,BYTE PTR LINLEN
MOV CH,LOW 1
CALL MKRMCH ; Insert one space before LF
POP CX
MOV CL,DL
POP DX
XCHG CX,DX
POP WORD PTR TRMCUR
RET
SUBTTL LINE WRAP LOGIC - Open next line for wrap
;SUBROUTINE MKRMNL(line) ; Make the next line a blank, empty line
;** on entry: DL=current line number
;** on exit: DL=current line number(may change from entry)
;** if CF=1 no room available
;**
MKRMNL: PUSH AX
PUSH BX
PUSH CX
PUSH DX
MKRMN0: CALL SCNRDT
JB MKRMN5
CMP DL,BYTE PTR WDOBOT
JZ MKRMN6
JB MKRMN4
MOV DL,BYTE PTR WDOBOT
JMP SHORT MKRMN0
MKRMN4: INC DL
JMP SHORT MKRMN0
;** IF CURRENT_PHYSICAL .LT. WINDOW_BOTTOM
MKRMN5: CMP DL,BYTE PTR WDOBOT
MKRMN6: POP DX
PUSH DX ; Get back posn to scroll from
JZ MKRMN7 ; BRIF at bottom of window(scroll up)
CMC
JB MKRMNZ ; BRIF outside of window
CMP DL,BYTE PTR WDOTOP
JB MKRMNZ ; BRIF outside of window
TEST BYTE PTR F_EDIT,LOW 377O
JZ MKRMNZ ; BRIF not editing, no need to scroll
INC DL ; Scroll down starting at next line
;** *** SCROLL DOWN
CALL SCRLD0 ; Scroll down to end of window
MKRMNY: CLC ; Indicate successful
MKRMNZ: POP DX ; Restore current line number
JMP SHORT MKRMNX
;** *** ELSE IF (FIRST_PHYSICAL(LOGICAL) .NE. WINDOW_TOP) OR NOT(INPUT_EDIT)
MKRMN7: TEST BYTE PTR F_EDIT,LOW 377O
JZ MKRMN9 ; BRIF not input edit, always allow scroll
MKRMN8: CALL CSRUP
JB MKRMNZ ; BRIF logical line starts at top of window(abort)
PUSH AX
CALL SCNRDT
POP AX
JNB MKRMN8 ; BRIF previous physical part of this logical
;** *** SCROLL UP
MKRMN9: POP DX
PUSH DX
CMP DL,BYTE PTR WDOBOT ; Full screen scroll?
JAE MKRMNF ; BRIF scroll up entire screen
CALL SCRLUD ; Scroll up from DL to WDOTOP
JMP SHORT MKRMNU
MKRMNF: CALL SCRLUP ; Scroll up entire window
MKRMNU: POP DX
CALL CSRUP ; Return line number of original line
CLC
MKRMNX: POP CX
POP BX
POP AX
RET
SUBTTL SCROLL ROUTINES - Scroll up and down
;Scroll up from DL to WDOTOP
SCRLUD: PUSH CX
MOV CL,DL
MOV DL,BYTE PTR WDOTOP
JMP SHORT SCRLU1
;SCROLL UP
SCRLUP: MOV DL,BYTE PTR WDOTOP ; Top line number
;Scroll up from DL to bottom
SCRLU0: PUSH CX
MOV CL,BYTE PTR WDOBOT
SCRLU1: PUSH AX
PUSH BX
PUSH DX
MOV AL,DL
MOV BL,DL ; From = To = Top line number
INC AL ; From = To + 1
MOV BH,BYTE PTR WDOLFT
MOV AH,BH ; From column = To column = left margin
SUB CL,BL ; CL = line count
JA SCRUL1 ; BRIF two or more line scroll
JB SCRUL4 ; BRIF TOP > BOTTOM(should never happen)
PUSH AX
MOV DL,BL
JMP SHORT SCRUL3 ; TOP=BOTTOM, just init line
SCRUL1: PUSH AX
MOV CH,BYTE PTR CRTWID ; Scroll entire lines
CALL SCROLL ; Scroll screen
;If CSRY, FSTLIN, LSTLIN are within scroll, decrement their values
ADD AL,CL ; AL=Last line scrolled + 1
DEC AL ; AL=Bottom line scrolled
; BL=Top line scrolled
MOV AH,LOW 255D ; decrement line# variables in scroll window
CALL TSTSCR
MOV DL,AL ; DL=bottom line of scroll (initialize it)
;Clear the last line of the scroll
SCRUL3: MOV DH,BYTE PTR WDOLFT
POP AX
OR CL,CL
JE SCRUL4 ; No scroll(one line init)
CALL SCRUTT ; Scroll up terminator table
SCRUL4: CALL PLINIT ; Init physical line from (DL,DH) to (DL,WDORGT)
POP DX
POP BX
POP AX
POP CX
RET
;TSTSCR is called after Scrolling Up or Down to update Line Number variables
; which may be in the scroll window
; Entry - BL=top line number of scroll window
; AL=bottom line number of scroll window
; AH=1 if line# variables are to be incremented, -1 if decremented
;
TSTSCR: PUSH SI
PUSH AX
MOV SI,OFFSET CSRY
CALL TSTWDO ; Adjust CSRY if its within scroll window
MOV AH,BYTE PTR WDOTOP
CMP BYTE PTR 0[SI],AH
JB TCSRY1 ; BRIF CSRY above top of window
MOV AH,BYTE PTR WDOBOT
CMP BYTE PTR 0[SI],AH
JNA CSRYOK ; BRIF CSRY didn't increment beyond bottom
TCSRY1: MOV BYTE PTR 0[SI],AH ; Bring it back to within scroll window
CSRYOK: MOV SI,OFFSET FSTLIN
POP AX
CALL TSTWDO ; Adjust FSTLIN if its within scroll window
MOV SI,OFFSET LSTLIN
CALL TSTWDO ; Adjust LSTLIN if its within scroll window
POP SI
RET
; If BL .LEQ. [SI] .LEQ. AL then [SI]=[SI]+AH
;
TSTWDO:
CMP AL,BYTE PTR 0[SI]
JB NINWDO ; BRIF [SI] not within scroll
CMP BL,BYTE PTR 0[SI]
JA NINWDO ; BRIF [SI] not within scroll
ADD BYTE PTR 0[SI],AH ; Adjust [SI] for scroll
NINWDO: RET
;SCROLL DOWN
SCRLDN: MOV DL,BYTE PTR WDOTOP
;Scroll down from DL to WDOBOT
SCRLD0: PUSH AX
PUSH BX
PUSH CX
MOV AL,DL
MOV BL,DL ; From = To = top of scroll
INC BL ; To = From + 1
MOV BH,BYTE PTR WDOLFT ; Column = left margin
MOV AH,BH
MOV CL,BYTE PTR WDOBOT
SUB CL,AL ; Count of lines =(window bottom)-top of scroll
PUSH AX
JBE SCRDL3 ; BRIF null scroll, just clear line
MOV CH,BYTE PTR WDORGT ; Scroll lines, not columns
SCRLD1: CALL SCROLL ; Scroll screen
;If CSRY, FSTLIN, LSTLIN are within scroll, increment their values
ADD AL,CL ; AL=Last line scrolled
DEC AL
MOV AH,LOW 1 ; increment line# variables in scroll window
CALL TSTSCR
;Clear the last line of the scroll(in DL)
SCRDL3: MOV DH,BYTE PTR WDOLFT
POP AX
OR CL,CL
JS SCRDL4 ; No scroll(out of window)
JE SCRDL4 ; No scroll(one line init)
CALL SCRDTT ; Scroll down term table(mark last line init'd)
SCRDL4: CALL PLINIT ; Init physical line from (DL,DH) to (DL,WDORGT)
POP CX
POP BX
POP AX
RET
;SCROLL DOWN current line to next line
SCRDLN: PUSH AX
PUSH BX
PUSH CX
MOV AX,DX ; Start of scroll is current line
MOV AH,BYTE PTR WDOLFT
MOV BX,AX
INC BL ; TO start is next line
MOV CH,BYTE PTR WDORGT
MOV CL,LOW 1 ; Scroll one entir line
PUSH AX
JMP SHORT SCRLD1 ; Do scroll and update LSTPOS, FSTPOS, CSRY
SUBTTL SCROLL ROUTINES - Support routines: scroll terminator table, line init
;Scroll up terminator table(same parameters as SCROLL)
; on entry: (see SCROLL)
; on exit: modifies AX, BX, CX
;
SCRUTT: PUSH DX
MOV DL,BL
CALL SCNRDT ; TRMCUR=address of top of scroll
MOV BX,WORD PTR TRMCUR
MOV CH,LOW 0
SCRUTL: MOV AX,WORD PTR LINTTB[BX] ; Get a terminator
MOV WORD PTR LINTTB[BX-2],AX ; Save a terminator
INC BX
INC BX
LOOP SCRUTL ; Continue till done
MOV BYTE PTR LINTTB[BX-2],LOW 0 ; Terminate end line of scroll
MOV BYTE PTR LINTTB[BX-1],LOW OFFSET TRMEOL
POP DX
RET
;Scroll down terminator table(same parameters as SCROLL)
; on entry: (see SCROLL)
; on exit: modifies AX, BX, CX
;
SCRDTT:
PUSH DX
MOV DL,AL
ADD DL,CL
CALL SCNRDT ; TRMCUR=displacement of bottom of scroll + 2
MOV BX,WORD PTR TRMCUR
MOV CH,LOW 0
SCRDTL: SUB BX,2 ; Next posn
MOV AX,WORD PTR LINTTB[BX-2] ; Get a terminator
MOV WORD PTR LINTTB[BX],AX ; Save a terminator
LOOP SCRDTL ; Continue till done
MOV BYTE PTR LINTTB[BX-2],LOW 0 ; Terminate end line of scroll
MOV BYTE PTR LINTTB[BX-1],LOW OFFSET TRMEOL
MOV DL,BYTE PTR WDOBOT
CALL SCNRTL
JB SCRDT1 ; EOL term'd, all done
JNZ SCRDT1
DEC AH
SCRDT1: MOV AL,LOW OFFSET TRMEOL
CALL SCNWTT ; Make sure last line in window is EOL term'd
POP DX
RET
;Physical line initialization
; on entry: (DH,DL) = start of initialization
;
PLINIT: PUSH CX
PUSH AX
CALL SCNRDT
MOV AH,DH
DEC AH
PUSH BX
MOV BX,WORD PTR TRMCUR ; Terminate line to left of DH
MOV BYTE PTR LINTTB[BX-1],LOW OFFSET TRMEOL
MOV BYTE PTR LINTTB[BX-2],AH
POP BX
POP AX
PLINI2: CALL CLREOL ; Clear to end of line from (DH,DL)
POP CX
RET
SUBTTL LABEL Key Processing
;LABELK - If function key display is off then turn on and exit.
; If function key display is on then advance display line and
; redisplay.
;ENTRY - DX = cursor position
;EXIT - DX unmodified
;USES - AX,BX,CX
;
EXTRN FKYADV:NEAR,KEYDSP:NEAR,FKYFMT:NEAR
DSEG SEGMENT PUBLIC 'DATASG'
EXTRN KEYSW:WORD
DSEG ENDS
LABELK: PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
CMP BYTE PTR KEYSW,LOW 0D ;Test for key on
CALL FKYADV ;If KEYSW was 0(ZF=0) then init PF start key,
; else advance to next set of PF keys
; return ZF=1 if advance beyond last of PF keys
JZ LABOFF ;Process key off request
MOV BYTE PTR KEYSW,LOW 255D ;Turn on key display flag
LABDSP: CALL KEYDSP ;Display function keys
POP DI
POP SI
POP DX
POP CX
POP BX
POP AX
RET
LABOFF:
MOV BYTE PTR KEYSW,LOW 0D ;Turn the key flag off
JMP SHORT LABDSP ;Go clear the function key display line
SUBTTL Miscellaneous editor interface routines
;SUBROUTINE SCNMRK ; Mark current position as first posn of logical
;** on entry: ZF=1 indicates INPUT statement, AL=1 indicates
;** EDIT statement.
;** on exit: -
;**
SCNMRK: PUSHF
MOV DL,BYTE PTR CSRY
MOV DH,BYTE PTR CSRX
DEC AL
JNZ SCNMK0 ; Not begin of EDIT statement
CALL LSTART ; Set (DH,DL)=start of current line
PUSH BX
JMP SHORT SCNMK2
;** IF NOT TOP OF WINDOW
SCNMK0: CALL CSRUP ; Move to previous line
JB SCNMK1 ; BRIF at top of window
;** *** TERMINATE PREVIOUS PHYSICAL LINE
CALL SCNRTL
MOV AL,LOW OFFSET TRMEOL ; Make sure current line is start of logical line
CALL SCNWTT
INC DL ; Restore current line number
;** IF LINE IS MARKED WITH NULL
SCNMK1: CALL SCNRDT
PUSH BX
MOV BX,WORD PTR TRMCUR
TEST BYTE PTR LINTTB[BX-1],LOW OFFSET TRMNUL
JZ SCNMK2 ; BRIF not specially marked line
PUSH DX
PUSH CX
;** SCAN LINE FOR NULL CHAR(255 DECIMAL)
MOV DH,BYTE PTR WDOLFT
MOV CL,BYTE PTR LINLEN
SCNMKL: CALL SCRINP
CMP AL,LOW 255D
JZ SCNML3 ; BRIF is specially marked line
SCNML2: INC DH
SUB CL,LOW 1
JA SCNMKL ; BRIF more chars to check
OR SP,SP
SCNML3:
POP CX
POP DX
JNZ SCNMK2 ; BRIF char was not on line, don't clear line
;** *** DELETE IT
CALL LDELET ; Delete this line
;** IF NOT DIRECT, SET LSTPOS, FSTPOS = CURRENT_POSN
SCNMK2:
MOV BYTE PTR CSRY,DL
MOV BYTE PTR CSRX,DH ; Update CURS_POSN in case of change
POP BX
POPF
JZ SCNMK3 ; INPUT statement, use current posn
MOV BYTE PTR LSTLIN,LOW 377O ; Direct, set FSTPOS, LSTPOS to min and max
MOV BYTE PTR FSTLIN,LOW 0
JMP SHORT SCNMKX
SCNMK3: MOV BYTE PTR LSTLIN,DL
MOV BYTE PTR FSTLIN,DL
DEC DH
MOV BYTE PTR LSTCOL,DH ; Mark LSTCOL one to left of current posn
INC DH
MOV BYTE PTR FSTCOL,DH
SCNMKX: RET
;** END SUBROUTINE SCNMRK
SUBTTL Read logical line
;SUBROUTINE SCNRDL ; Read a logical line
;** on entry: ZF=1 indicates ignore FSTPOS, LSTPOS(statement
;** line input).
;** DX=current posn(within logical line to return)
;** BX=buffer address
;** CX=max count
;** on exit: BX=last char address plus one
;** CX=CX - (count of chars moved)
;** DX=destroyed
;**
SCNRDL: PUSHF ; Save statement input flag
;** Set DX=start of move
;** WHILE ((DL .NE FSTLIN) AND DL IN_SAME_LOGICAL_LINE)
SCRD00: CMP DL,BYTE PTR FSTLIN
JZ SCRD01 ; Found first line of logical
;** *** DL = PREVIOUS LINE
CALL CSRUP
JB SCRD01 ; At top of window, stop here
CALL SCNRDT
JNB SCRD00 ; Still same logical, continue
INC DL ; Set DL = first physical of logical
;** IF (STATEMENT_INPUT OR (NOT ON FIRST_LINE))
SCRD01: POPF ; We have start line, now get start column
PUSHF
;** *** START_COLUMN=LEFT_MARGIN
MOV DH,BYTE PTR WDOLFT ; Assume start at left margin
JNZ SCRD02 ; BRIF statement input
CMP DL,BYTE PTR FSTLIN
JNZ SCRD02 ; BRIF not on FIRST_LINE
;** *** ELSE START_COLUMN=FIRST_COLUMN
MOV DH,BYTE PTR FSTCOL
;** WHILE (POSN IS ON SAME LOGICAL) AND ((POSN .LTE. LSTPOS) OR STATEMENT_INPUT) BEGIN
SCRD02: POPF
PUSHF
JNZ SCRD03 ; BRIF statement input, ignore LSTPOS
CMP DL,BYTE PTR LSTLIN
JA SCRDXZ ; **BRIF passed LSTPOS(was at prev. line term'r)
JNZ SCRD03 ; BRIF not at LSTPOS
CMP DH,BYTE PTR LSTCOL
JA SCRDXZ ; BRIF beyond LSTPOS, all done
;** *** READ A CHARACTER INTO THE BUFFER
;** *** DO CASE TERMINATOR OF LINEFEED, NULL_WRAP, WRAP, BEFORE EOL, AT EOL
SCRD03: CALL SCNRDT
PUSH AX
JB SCRD04 ; BRIF not reading a linefeed
JNZ SCRD04 ; BRIF not reading a linefeed
CMP AH,DH
JNZ SCRD04 ; BRIF not reading a linefeed
;** *** *** CASE: LINEFEED
SCRDLF: MOV AX,OFFSET CHRLNF+0
JMP SHORT SCRD08 ; At linefeed terminator, pass linefeed
SCRD04: CMP AH,DH
JA SCRD07 ; BRIF within data on screen
JB SCRD06 ; BRIF beyond terminator
;** *** *** CASE: NULL_WRAP
CMP AL,LOW OFFSET TRMNWP
JNZ SCRD07 ; BRIF not at NULL_WRAP terminator
SCRD06: CMP AL,LOW OFFSET TRMEOL
POP AX
JZ SCRDXZ ; BRIF beyond EOL
;** *** *** CASE: WRAP
INC DL ; Wrap to next line
MOV DH,BYTE PTR WDOLFT
JMP SHORT SCRD02
;** *** *** CASE: BEFORE EOL
SCRD07:
CLC ; Indicate call is from Screen Editor
CALL SCRINP ; AX=Character at (DH,DL)
SCRD08: MOV BYTE PTR 0[BX],AL
DEC CX
POP AX
JZ SCRDEX
CMP AL,LOW OFFSET TRMEOL
JNZ SCRD09 ; BRIF not at EOL
CMP AH,DH
JBE SCRDEX ; BRIF at EOL(or beyond), all done
SCRD09: INC BX
CALL CSRADV
JB SCRDXZ ; If end of window, all done
JMP SHORT SCRD02 ; Pass next character
;** *** *** CASE: AT(OR BEYOND) EOL
SCRDEX: INC BX ; Set BX= last posn written plus one
SCRDXZ: POPF
CALL SCNBRK ; Clear any flags associated with INPUT
RET
;** *** *** END
;** *** END
;** END SUBROUTINE SCNRDL
SUBTTL CONTROL CHARACTER ROUTINES