From a91deeb3477a3e4fdfd6634e48d731828859e017 Mon Sep 17 00:00:00 2001 From: Wayne Warthen Date: Fri, 28 Mar 2025 17:25:55 -0700 Subject: [PATCH] Add Peter Onion's ZDE ANSI Keyboard Support - Added new ANSI keyboard support from Peter Onion. - ZDE is now built as part of the RomWBW build itself. - Did not yet include support for modified ZDE escape character. - See Co-Authored-By: PeterOGB <7755057+peterogb@users.noreply.github.com> --- Binary/Apps/Clean.cmd | 1 + Binary/Apps/Makefile | 2 +- Binary/Apps/ZDE/Clean.cmd | 4 + Binary/Apps/ZDE/Makefile | 6 + Binary/Apps/ZDE/ReadMe.txt | 10 + Source/Apps/Build.cmd | 1 + Source/Apps/Clean.cmd | 1 + Source/Apps/Makefile | 2 +- Source/Apps/ZDE/Build.cmd | 35 + Source/Apps/ZDE/Clean.cmd | 9 + Source/Apps/ZDE/Makefile | 15 + Source/Apps/ZDE/ReadMe.md | 36 + Source/Apps/ZDE/zde16.z80 | 8111 ++++++++++++++++ Source/Apps/ZDE/zde16a.pat | 102 + Source/Apps/ZDE/zde17.z80 | 8111 ++++++++++++++++ Source/Apps/ZDE/zde18.z80 | 8567 ++++++++++++++++ Source/Apps/ZDE/zde19.z80 | 8598 +++++++++++++++++ Source/Images/Common/All/u15/ZDE.COM | Bin 18560 -> 18688 bytes .../Images/d_ws4/u1/{README.MD => ReadMe.md} | 7 +- Source/Images/d_ws4/u1/ZDE16.COM | Bin 16896 -> 0 bytes Source/Images/d_ws4/u1/ZDE16A.COM | Bin 16896 -> 0 bytes Source/Images/d_ws4/u1/ZDE18.COM | Bin 18560 -> 0 bytes Source/Images/fd_ws4.txt | 4 + Source/Images/hd_ws4.txt | 4 + Source/RomDsk/ROM_256KB/ZDE.COM | Bin 18560 -> 18688 bytes Source/RomDsk/ROM_384KB/ZDE.COM | Bin 18560 -> 18688 bytes Source/RomDsk/ROM_896KB/ZDE.COM | Bin 18560 -> 18688 bytes 27 files changed, 33623 insertions(+), 3 deletions(-) create mode 100644 Binary/Apps/ZDE/Clean.cmd create mode 100644 Binary/Apps/ZDE/Makefile create mode 100644 Binary/Apps/ZDE/ReadMe.txt create mode 100644 Source/Apps/ZDE/Build.cmd create mode 100644 Source/Apps/ZDE/Clean.cmd create mode 100644 Source/Apps/ZDE/Makefile create mode 100644 Source/Apps/ZDE/ReadMe.md create mode 100644 Source/Apps/ZDE/zde16.z80 create mode 100644 Source/Apps/ZDE/zde16a.pat create mode 100644 Source/Apps/ZDE/zde17.z80 create mode 100644 Source/Apps/ZDE/zde18.z80 create mode 100644 Source/Apps/ZDE/zde19.z80 rename Source/Images/d_ws4/u1/{README.MD => ReadMe.md} (87%) delete mode 100644 Source/Images/d_ws4/u1/ZDE16.COM delete mode 100644 Source/Images/d_ws4/u1/ZDE16A.COM delete mode 100644 Source/Images/d_ws4/u1/ZDE18.COM create mode 100644 Source/Images/fd_ws4.txt create mode 100644 Source/Images/hd_ws4.txt diff --git a/Binary/Apps/Clean.cmd b/Binary/Apps/Clean.cmd index 49043dc1..f486e41f 100644 --- a/Binary/Apps/Clean.cmd +++ b/Binary/Apps/Clean.cmd @@ -11,3 +11,4 @@ if exist Tunes\*.vgm del Tunes\*.vgm if exist bbcbasic.txt del bbcbasic.txt pushd Test && call Clean || exit /b 1 & popd +pushd ZDE && call Clean || exit /b 1 & popd diff --git a/Binary/Apps/Makefile b/Binary/Apps/Makefile index dc268ac8..c9ae6baf 100644 --- a/Binary/Apps/Makefile +++ b/Binary/Apps/Makefile @@ -1,6 +1,6 @@ TOOLS = ../../Tools MOREDIFF := $(shell $(TOOLS)/unix/casefn.sh *.com) -SUBDIRS = Test +SUBDIRS = Test ZDE include $(TOOLS)/Makefile.inc diff --git a/Binary/Apps/ZDE/Clean.cmd b/Binary/Apps/ZDE/Clean.cmd new file mode 100644 index 00000000..c79d414b --- /dev/null +++ b/Binary/Apps/ZDE/Clean.cmd @@ -0,0 +1,4 @@ +@echo off +setlocal + +if exist *.com del *.com diff --git a/Binary/Apps/ZDE/Makefile b/Binary/Apps/ZDE/Makefile new file mode 100644 index 00000000..2c13bd3c --- /dev/null +++ b/Binary/Apps/ZDE/Makefile @@ -0,0 +1,6 @@ +TOOLS = ../../../Tools + +include $(TOOLS)/Makefile.inc + +clean:: + @rm -f *.com diff --git a/Binary/Apps/ZDE/ReadMe.txt b/Binary/Apps/ZDE/ReadMe.txt new file mode 100644 index 00000000..220feba1 --- /dev/null +++ b/Binary/Apps/ZDE/ReadMe.txt @@ -0,0 +1,10 @@ +*********************************************************************** +*** *** +*** R o m W B W *** +*** *** +*** Z80/Z180 System Software *** +*** *** +*********************************************************************** + +This directory contains the ZDE executable binaries. They are +in their original, unconfigured state. diff --git a/Source/Apps/Build.cmd b/Source/Apps/Build.cmd index 92bcb2a1..9ea0ceb3 100644 --- a/Source/Apps/Build.cmd +++ b/Source/Apps/Build.cmd @@ -29,6 +29,7 @@ call :build Survey || exit /b call :build HTalk || exit /b call :build BBCBASIC || exit /b call :build copysl || exit /b +call :build ZDE || exit /b goto :eof diff --git a/Source/Apps/Clean.cmd b/Source/Apps/Clean.cmd index aee7b56c..2cef0cff 100644 --- a/Source/Apps/Clean.cmd +++ b/Source/Apps/Clean.cmd @@ -24,6 +24,7 @@ call :clean Survey || exit /b call :clean HTalk || exit /b call :clean BBCBASIC || exit /b call :clean copysl || exit /b +call :clean ZDE || exit /b goto :eof diff --git a/Source/Apps/Makefile b/Source/Apps/Makefile index f6abf7b2..dd96e897 100644 --- a/Source/Apps/Makefile +++ b/Source/Apps/Makefile @@ -1,5 +1,5 @@ SUBDIRS = HTalk XM FDU FAT Tune Test ZMP ZMD Dev VGM cpuspd reboot Survey BBCBASIC copysl \ - sysgen syscopy assign format talk mode rtc timer + sysgen syscopy assign format talk mode rtc timer ZDE TOOLS =../../Tools include $(TOOLS)/Makefile.inc diff --git a/Source/Apps/ZDE/Build.cmd b/Source/Apps/ZDE/Build.cmd new file mode 100644 index 00000000..280b92ee --- /dev/null +++ b/Source/Apps/ZDE/Build.cmd @@ -0,0 +1,35 @@ +@echo off +setlocal + +set TOOLS=../../../Tools + +set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%PATH% + +set TASMTABS=%TOOLS%\tasm32 + +set CPMDIR80=%TOOLS%/cpm/ + +:: These variations of ZDE are built here as reference copies. They +:: are not copied anywhere else during the build. +:: The resulting .COM files are manually +:: copied to /Source/Images/d_ws/u1 as needed. + +zxcc ZMAC -ZDE16 -/P -/H || exit /b +zxcc MLOAD25 ZDE16 || exit /b +copy /Y zde16.com ..\..\..\Binary\Apps\ZDE\ || exit /b + +zxcc ZMAC ZDE16A.PAT -/H || exit /b +zxcc MLOAD25 ZDE16A=ZDE16.COM,ZDE16A.HEX || exit /b +copy /Y zde16a.com ..\..\..\Binary\Apps\ZDE\ || exit /b + +zxcc ZMAC -ZDE17 -/P -/H || exit /b +zxcc MLOAD25 ZDE17 || exit /b +copy /Y zde17.com ..\..\..\Binary\Apps\ZDE\ || exit /b + +zxcc ZMAC -ZDE18 -/P -/H || exit /b +zxcc MLOAD25 ZDE18 || exit /b +copy /Y zde18.com ..\..\..\Binary\Apps\ZDE\ || exit /b + +zxcc ZMAC -ZDE19 -/P -/H || exit /b +zxcc MLOAD25 ZDE19 || exit /b +copy /Y zde19.com ..\..\..\Binary\Apps\ZDE\ || exit /b diff --git a/Source/Apps/ZDE/Clean.cmd b/Source/Apps/ZDE/Clean.cmd new file mode 100644 index 00000000..837287b3 --- /dev/null +++ b/Source/Apps/ZDE/Clean.cmd @@ -0,0 +1,9 @@ +@echo off +setlocal + +if exist *.prn del *.prn +if exist *.err del *.err +if exist *.rel del *.rel +if exist *.com del *.com +if exist *.hex del *.hex +if exist *.sym del *.sym diff --git a/Source/Apps/ZDE/Makefile b/Source/Apps/ZDE/Makefile new file mode 100644 index 00000000..de3c12e5 --- /dev/null +++ b/Source/Apps/ZDE/Makefile @@ -0,0 +1,15 @@ +# These variations of ZDE are built here as reference copies. They +# are not copied anywhere else during the build. +# The resulting .COM files are manually +# copied to /Source/Images/d_ws/u1 as needed. + +OBJECTS = zde16.com zde16a.com zde17.com zde18.com zde19.com +DEST = ../../../Binary/Apps/ZDE +TOOLS = ../../../Tools +OTHERS = *.hex + +include $(TOOLS)/Makefile.inc + +zde16a.com: zde16.com zde16a.pat + $(ZXCC) zmac zde16a.pat -/H + $(ZXCC) mload25 zde16a=zde16.com,zde16a.hex || exit /b diff --git a/Source/Apps/ZDE/ReadMe.md b/Source/Apps/ZDE/ReadMe.md new file mode 100644 index 00000000..ea103417 --- /dev/null +++ b/Source/Apps/ZDE/ReadMe.md @@ -0,0 +1,36 @@ +# ZDE 1.6 (Z-System Display Editor) reconstituted source - MECPARTS +11/19/2020 + +Using the source code of [VDE 2.67] +(http://www.classiccmp.org/cpmarchives/cpm/Software/WalnutCD/enterprs/cpm/utils/s/vde267sc.lbr) +as a guide, I've reconstituted the source code for [ZDE 1.6](http://www.classiccmp.org/cpmarchives/cpm/Software/WalnutCD/cpm/editor/zde16.lbr). + +The source has been assembled with: + +* Al Hawley's ZMAC: assemble as is. +* MicroSoft's M80: rename to ZDE16.MAC, un-comment the first two lines + and assemble. Use RELHEX to create ZDE16.HEX. +* ZASM (Cromemco's ASMB): Rename to ZDE16.Z80 and assemble. Use RELHEX +to create ZDE16.HEX. + +Use MLOAD to create ZDE16.COM. + +There are still a couple of routines new to ZDE that I haven't figured +out (yet). But most of them have been sussed out. + +## ZDE 1.7 - MECPARTS 11/24/2020 + +I've fixed the "doesn't preserve timestamps for files larger than a +single extent under ZSDOS" bug that was present in v1.6. The existing +ZDENST16.COM program will work with the 1.7 to set the program up for +your terminal and printer. + +## ZDE 1.8 - Lars Nelson 12/3/2022 + +Added routine to save create time stamp under CP/M Plus since +CP/M Plus, unlike ZSDOS, has no native ability to set time stamps. + +## ZDE 1.9 - Peter Onion 03/27/2025 + +- Added support for ANSI PgUp, PgDn, Home, & End. +- Support ANSI F1 key for menu/error escape. diff --git a/Source/Apps/ZDE/zde16.z80 b/Source/Apps/ZDE/zde16.z80 new file mode 100644 index 00000000..568bd090 --- /dev/null +++ b/Source/Apps/ZDE/zde16.z80 @@ -0,0 +1,8111 @@ + ;Assembles with Al Hawley's ZMAC as is + ;Rename to ZDE16.Z80 for ZASM (Cromemco ASMB) +; .Z80 ;Uncomment these two lines and rename +; ASEG ;to ZDE16.MAC for M80 + ;(use RELHEX to convert ZDE16.REL to ZDE16.HEX) +; +;*** ZDE assembly sequence +; +CR EQU 0DH ;ASCII stuff +LF EQU 0AH +FF EQU 0CH +BS EQU 08H +TAB EQU 09H +ESC EQU 1BH +DEL EQU 7FH +BEL EQU 07H +EOF EQU 1AH +X EQU 80H ;hibit +; +BDOSep EQU 0005h ;BDOS stuff +FCB EQU 005Ch +FCBt1 EQU FCB+9 +FCBex EQU FCB+12 +FCBs1 EQU FCB+13 +FCBd0 EQU FCB+16 +FCBcr EQU FCB+32 +FCBr0 EQU FCB+33 +FCBr1 EQU FCB+34 +FCBr2 EQU FCB+35 +DMA EQU 0080h +; +LSTO EQU 5 +UCON EQU 6 +CPMV EQU 12 +RSTD EQU 13 +SELD EQU 14 +FOPN EQU 15 +FCLO EQU 16 +SRCH EQU 17 +SRCN EQU 18 +FDEL EQU 19 +RSEQ EQU 20 +WSEQ EQU 21 +FMAK EQU 22 +FREN EQU 23 +GDRV EQU 25 +SDMA EQU 26 +USRN EQU 32 +RSTV EQU 37 +ERRM EQU 45 +DOSV EQU 48 +FTRU EQU 99 +GETF EQU 100 +SETF EQU 101 +GETS EQU 102 +SETS EQU 103 +; +Z3NdrL EQU 16 ; length of NDR dir/pwdstring +Z3NdrM EQU 8 ; length of NDR name to match +Z3NDR EQU 0015H ; offset to NDR address in Z3ENV +Z3MSG EQU 0022H +MsgUsr EQU 64 ; User area offset in message buffer +MsgNmU EQU 16 ; # of user registers +TPAful EQU 12 ; Z33 TPA full error code +ErrBit EQU 00000010B +EcpBit EQU 00000100B +ExtBit EQU 00001000B +; +;ErrSta is the value to be returned in the Z33 Message Buffer command +;status to inform the command processor that an error has occurred in +;an external program and that the error handler should be invoked. +; +ErrSta EQU ErrBit+EcpBit+ExtBit +; +;*** ZDE.ASM - Z-System Display Editor +;*** Universal Version - (c)1988 Eric Meyer +;*** Z-System Version - (c)1989 Carson Wilson +; ------------------- +; VDE,VDE-2 - 9-12/84 - Enhanced VDO, added functions +; VDE-OS,OX - 7/85-1/86 - Small additions and fixes +; VDE-PX - 7-9/85 - Epson Geneva terminal version +; VDE 1.2-3 - 9/85-1/86 - Generic terminal version +; VDE/M 2.0 - 4/86 - Generic memory map version; CP/M+ support; additions +; 2.1 - 6/86 - New Keys 0-9; window; undo; directory; new pagination, +; compression, block marker, scroll; etc. +; 2.2 - 8/86 - WS-like commands; left mrgn, hyphenation; macros +; 2.3 - 9/86 - VINSTALL; Print options; word fns; real ^QA; RstDrv +; 2.4 - 1/87 - vidRAM/window redone; "W" mode; ^OZ,^QP; block print +; 2.5 - 3/87 - User#s; "N" mode; ^OS, ^OV/+/-; new block fns; hard-CRs +; 2.6 - 7/87 - Allow blank filename; ^U abort; new toggles; ruler; +; ^O; AltBit fixes; works w/o curpos; key buffer; faster +; scrolling; case insensitive searches; no fake "VIDRAM" +; 2.61 - 8/87 - Bug fixes (incl FastFi), improved hyphenation +; 2.62 - 11/87 - ^JKL synonyms; ^W prefix; ^OH; several small fixes +; 2.63 - 1/88 - ^KV; WS style ^W/^Z; chgs to ^OP, ^OI/N, word fns +; 2.64 - 3/88 - ^OQ,^QT,^QI; ^KD; ^QA fixes; dbl spc; top margin; +; backward find; ShoRCu +; 2.65 - 4/88 - ^OI/N args; Esc-TAB; ^OA; menu removal; minor fixes +; 2.66 - 6/24/88 - Printer margins; Minor fixes. LAST RELEASE! +; 2.67b - 10/14/88 - Minor fixes +; ZDE 1.0 - 3/10/89 - Z-System Display Editor +; 1.3 - 8/26/89 +; 1.6 - 6/2/90 +; 1.6 - 11/19/20 - ZDE 1.6 source reconstituted using VDE 2.67 +; source as a guide +; ------------------- +; + ORG 0100H +; + JP Start ;Entry and exit vectors + DB 'Z3ENV' + DB 1 +Z3Env: DW 0 +Boot: JP 0 + DW 0 +; +;Following VINSTALL data MUST be at 0110-0121 +; + DW 1006H ;Version compatibility + DW UsrPat + DB UPatL + DW PSTbl + DB PsL + DW MnuSt + DW KMnuSt + DW EMnuSt + DW OMnuSt + DW QMnuSt + ;version message (28 chars, used in menu) +; [----5----10---15---20---25--] +VersID: DB 'ZDE 1.6, Copr. 1990 C.Wilson',0 +; +; +;USER PATCHABLE VALUES +; + ORG 0140H +BAKFlg: DB 0FFH ;0140H - create BAK files (y/n) +DFMode: DB 'A' ;default file modem W/A/N +FDflt1: DB 'Z80N' ;1st default override +FDflt2: DB 'WS W' ;2nd +FDflt3: DB 'CMDN' ;3rd +FDflt4: DB 'LIBN' ;4th +InsFlg: DB 0FFH ;defulat insert on (y/n) +RulFlg: DB 0FFH ;default rules on (y/n) +HCDflt: DB 0FFH ;default HCR disp on (y/n) +HypFlg: DB 0FFH ;enable hyphenation (y/n) +PSFlg: DB 0 ;default proportional flag (y/n) +PSokFl: DB 0FFH ;default allow proportional flag (y/n) +DfltLM: DB 1 ;left margin column (1=OFF) +DfltRM: DB 65 ;right margin column (1=OFF) +Ovlap: DB 2 ;scroll overlap (0=none) +DirSys: DB 0 ;include SYS files (y/n) +FixDsk: DB '@@' ;fixed drives +Ring: DB 0FFH ;error ring bell (y/n) +Help: DB 0FFH ;use help menus (y/n) +AltHdr: DB 0FFH ;use alt video in header (y/n) +NoHdrF: DB 0 ;suppress header +MHz: DB 40H ;clock speed (40h=4MHz) +Timer: DB 38H ;horiz scroll delay (01..FF) +TabCnt: DB 7 ;hard tab cols -1 (1/3/7/15) +VTList: DB 6,11,16,21 ;variable tab columns (8) + DB 0,0,0,0 +VTNum EQU $-VTList +WildCd: DB EOF ;wildcard character +BlkChr: DB 0 ;block characters (^@) +TogTbl: DB 02H,04H,13H,19H ;toggles ^B,^D[^T],^S,^Y +NTgTbl: DB 11H,17H,5,12H ;switches ^Q,^W,^E,^R (last 015C) +; +;INSTALLATION +; + ORG 180H +Z3tcap: DB 'Generic CRT ' ;ID + ORG 190H +View: DB 80 ;viewable columns (max 128) +AuWrap: DB 0FFH ;does autowrap cursor +Lines: DB 24 ;lines +UsrKys: DB 0FFH ;DEL key + DB 0FFH ;arrow up + DB 0FFH ;arrow down + DB 0FFH ;arrow right + DB 0FFH ;arrow left + DB 0 +CIL: DB 0,0,0,0,0,0,0 ;clear to end of line, 6 bytes +TInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal init, 7 bytes +TUInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal uninit +AltOn: DB 0,0,0,0,0,0,0 ;alt video on, 6 bytes +AltOff: DB 0,0,0,0,0,0,0 ;alt video off +AltBit: DB 0 ;high bit gives alt video? +Filter: DB 7FH ;highest ASCII to send to screen +PosMod: DB 'N' ;curpos mode (Std/Rev/ANSI/None) +PCu: DB 1EH,0,0CH,0 ;position cursor to (0,0) +PosDly: DB 0 ;delay after curpos (00-FF) +InsL: DB 0,0,0,0,0,0,0 ;insert line [1], 6 bytes +DelL: DB 0,0,0,0,0,0,0 ;delete line [1], 6 byts +OddDel: DB 0 ;ins/del line specific? +CsrOff: DB 0,0,0,0,0,0,0 ;cursor off +CurOn: DB 0,0,0,0,0,0,0 ;cursor on +; + ORG 01F0H ;Printer codes + DB 'Teletype ' ;ID + ORG 0200H +UseLF: DB 0FFH ;use LF after CR in print? +FormL: DB 54 ;form length (0=no pag) +PTMarg: DB 0 ;top margin skip +DotPO: DB 0 ;left margin skip +PInit: ;printer init, 19 bytes + ORG 0218H +PUInit: ;printer uninit, 7 bytes + ORG 0220H +PCodes: DB 0,0,0,0,0,0,0,0 ;^B toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^T [^D] toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^S toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^Y toggle on + DB 0,0,0,0,0,0,0,0 ;...and off +UCodes: DB 0,0,0,0,0,0,0,0 ;sw 1 (^Q) + DB 0,0,0,0,0,0,0,0 ;sw 2 (^W) + DB 0,0,0,0,0,0,0,0 ;sw 3 (^E) + DB 0,0,0,0,0,0,0,0 ;sw 4 (^R) +; + ORG 0280H +UsrPat: ;0280-02AFH - User Patch Area +;(Can extend back into UCodes section if fewer switches used) +; + ORG 02B0H ;02B0-030EH - Proportinal table +UPatL EQU $-UsrPat +PSTbl: DB 0,-12, 0, 0, 0, 6, 6,-12 ;" "-";" + DB -6, -6, 0, 0,-12, 0,-12, 0 ;"("-"/" + DB 0, 0, 0, 0, 0, 0, 0, 0 ;"0"-"7" + DB 0, 0,-12,-12, 0, 0, 0, 0 ;"8"-"?" + DB 6, 6, 6, 6, 6, 6, 6, 6 ;"@"-"G" + DB 6, -6, 0, 6, 6, 12, 6, 6 ;"H"-"O" + DB 6, 6, 6, 6, 6, 12, 6, 12 ;"P"-"W" + DB 6, 6, 0, -6, 0, -6, 0, 0 ;"X"-"_" + DB -12, 0, 6, 0, 6, 0, -6, 6 ;"'"-"g" + DB 6,-12, -6, 6,-12, 12, 6, 0 ;"h"-"o" + DB 6, 6, 0, 0, -6, 6, 6, 12 ;"p"-"w" + DB 0, 6, 0, -6,-12, -6, 0 ;"x"-"~" +PsL EQU $-PSTbl +; + ORG 0310H ;0310-04AFH - Macro keys +Keys: DS 2 ;free count (VDE does this) + DS 510 +KT: +; +; +;----- EXECUTION BEGINS HERE ------- +; + ORG 0510H +; +Start: SUB A ;check for Z80 + RET PE + LD SP,Stack + LD HL,Data ;zero out data area + LD DE,Data+1 + LD BC,DataLn-1 + LD (HL),0 + LDIR + LD C,CPMV + CALL BDOSep + LD (DOSVer+1),A ;CP/M version + CP 30H + JR NC,ItsCP3 + LD C,DOSV + CALL BDOSep ; what kind of enhanced BDOS + LD A,H + CP 'S' + JR Z,ZxDOS + CP 'D' + JR NZ,ItsCP3 +ZxDOS: LD (DOSVer+1),A ; store ZS/ZDDOS version + LD C,GETF ; get ZSDOS flags + CALL BDOSep + LD (ZDflgs+1),HL + EX DE,HL + RES 1,E ; public files are R/O + LD C,SETF + CALL BDOSep ; set ZSDOS flags +ItsCP3: CALL DOSVer + LD C,ERRM ; set action on hardware error + LD E,0FEH ; return error code to program + CALL NC,BDOSep ; for anything other than CP/M 2.2 + LD C,GDRV + CALL BDOSep ;save logged drive + LD (CurDsk),A + INC A + LD (FCB),A ; store A=1..P=16 in FCB->drive + LD C,USRN ;and user + LD E,0FFH + CALL BDOSep + LD (CurUsr),A + LD (FCBU),A + LD A,(Lines) + LD (PhysLn),A + CALL AdjLns + LD A,(FormL) + LD (PgLen),A + LD HL,(DfltLM) + LD (LfMarg),HL + LD A,(BlkChr) + LD (BadTbl),A + LD A,(UseLF) + CPL + OR LF + LD (LFChr),A + LD HL,MacStr + DEC (HL) ;make a FF terminator + XOR A ;a bad load will exit and invoke Z33's + LD (BadLdX+1),A ;error handler +; + LD HL,DMA + LD A,(HL) + INC HL + CALL Parse ;parse command line +; + CALL VerKey ;verify keys + LD HL,TInit + CALL CtlStr ;Clear and home cursor + JR Edit ;start editing. +; +;Clear it all out and start over. +; +Restrt: LD A,1 ;a bad load will not exit and invoke + LD (BadLdX+1),A ;Z33's error handler + LD HL,LoadQ + CALL NewNam + LD A,(EdErr) ;bad name? + OR A + JR NZ,BadLdX +; +;Start editing a File +; +Edit: CALL IniRAM ;initialize memory + CALL DfltM ;adjust defaults + CALL DoHdr ;show header + CALL Top ;Start at TOF + CALL Error0 ;No errors + LD A,(FCB+1) + CP ' ' ;Filename blank? + JR Z,Edit1 + CALL SavNam ;save it for LoadIt kludge + CALL LoadIt ;Get input file + LD A,(EdErr) + CP 1 ;is it too big? + JR NZ,Edit1 +BadLdX: LD A,0 ;a non-zero value will set up Z33's message + OR A ;buffer to have the Z33 error handler handle + JR NZ,BadLd ;the 'TPA full' condition when we exit + LD BC,Z3MSG + CALL Z3EAdr + JR Z,BadLd + LD H,B + LD L,C + LD (HL),TPAful ; Z3MSG error byte: file too big + INC HL + INC HL + INC HL ; point HL at Z3MSG command status byte + LD (HL),ErrSta ; error, ECP running, external invocation + JP QuitY +BadLd: CALL DoErr ;Too big, or bad name + CALL BlkFCB ;(Other error means new file) + JR Edit +Edit1: LD A,(MSIFlg) ;set up BAKflag + LD HL,BAKFlg + AND (HL) + LD (FilFlg),A + XOR A + LD (Modify),A +; +Reset: LD SP,Stack ;recover from ^U prompt abort + CALL ShoLn1 +; +; +;MAIN LOOP: SHOW TEXT, GET KEY +; +Ready: CALL Orient ;Get bearings + LD HL,(OldLin) ; ### + LD (SavLin),HL ; ### + LD A,(OldCol) ; ### + LD (SavCol),A ; ### + LD A,(MacFlg) ; ### + OR A ; ### + JR NZ,RdyMac ; ### + LD HL,(CurLin) ; ### + LD (OldLin),HL ; ### + LD A,(CurCol) ; ### + LD (OldCol),A ; ### +RdyMac: CALL ShoTx ; then show text as needed + CALL Cursr ;position cursor + CALL TRptKy ;Get input + PUSH AF + CALL Error0 ;Clear error indicator + CALL SetNo ;default NO redisp + POP AF + CALL AdjKey ;translate arrows/DEL +; +DoKey: CALL Case ;try to match control code? + DB MnuLn/3 + DW IChar ;Default : Insert character +MnuSt EQU $ + DB 0 ;(internal use: null key) + DW CKCan + DB 80H ;DEL + DW Delete + DB 81H ;Up arrow + DW Up + DB 82H ;Down + DW Down + DB 83H ;Right + DW Right + DB 84H ;Left + DW Left + DB ESC + DW Escape + DB '^'-40H + DW UpLow + DB '\'-40H + DW Repeat ;Synonym for ^L + DB 'A'-40H + DW WordLf + DB 'B'-40H + DW Reform + DB 'C'-40H + DW PageF + DB 'F'-40H + DW WordRt + DB 'G'-40H + DW EChar + DB 'I'-40H + DW TabKey + DB 'J'-40H + DW DoMnu + DB 'K'-40H + DW CKKey + DB 'L'-40H + DW Repeat + DB 'M'-40H + DW ICR + DB 'N'-40H + DW ICRA + DB 'O'-40H + DW Onscrn + DB 'P'-40H + DW CtlP + DB 'Q'-40H + DW Quick + DB 'R'-40H + DW PageB + DB 'T'-40H + DW WordDl + DB 'U'-40H + DW Undel + DB 'V'-40H + DW IToggl + DB 'W'-40H + DW Scr1LU + DB 'Y'-40H + DW Eline + DB 'Z'-40H + DW Scr1LD +MnuLn EQU $-MnuSt +; +Sk1Ed: LD A,(EdErr) ;Check for error, repeat main loop + OR A + CALL NZ,DoErr + JP Ready +; +;Block commands: ^K toggle is on +; +CKKey: LD HL,CKTog + CALL Prefix +CKSyn: CALL XCase ;Entry for ESC synonyms + CALL Case + DB KMnuLn/3 + DW Error2 ;complain if unknown +KMnuSt EQU $ + DB 'B'-40h + DW Block + DB 'C'-40h + DW Copy + DB 'D'-40h + DW Done + DB 'E'-40h + DW Era + DB 'F'-40h + DW Dir + DB 'H'-40h + DW DoMnu + DB 'I'-40h + DW Info + DB 'K'-40h + DW Termin + DB 'L'-40h + DW Load + DB 'N'-40h + DW ChgNam + DB 'P'-40h + DW Print + DB 'Q'-40h + DW Quit + DB 'R'-40h + DW Read + DB 'S'-40h + DW Save + DB 'U'-40h + DW Unmark + DB 'V'-40h + DW MovBlk + DB 'W'-40h + DW Write + DB 'X'-40h + DW Exit + DB 'Y'-40h + DW EBlock + DB ESC + DW CKCan + DB ' ' + DW CKCan +KMnuLn EQU $-KMnuSt +CKCan: RET +; +;ESC commands: ESC toggle is on. +; +Escape: LD HL,ESCTog + CALL Prefix + CALL AdjKey + CALL UCase + CP '0' + JR C,Esc01 ;macro Keys: special case + CP '9'+1 + JP C,UseKey +Esc01: CALL Case + DB EMnuLn/3 + DW CKSyn ;default: ^K synonym +EMnuSt EQU $ + DB 81H ;Up arrow + DW ShftU + DB 82H ;Down + DW ShftD + DB 83H ;Right + DW ShftR + DB 84H ;Left + DW ShftL + DB '[' ;ANSI cursor sequences + DW ANSIcu + DB TAB + DW TaBack + DB 'M' + DW DoMac + DB '#' + DW MacKey + DB '!' ;macro prog stmts + DW MacJmp + DB '=' + DW MacTst + DB '~' + DW MacTsX + DB '+' + DW ChainK + DB ';' + DW Wait +EMnuLn EQU $-EMnuSt + RET +; +;Onscreen commands. ^O toggle is on. +; +Onscrn: LD HL,COTog + CALL Prefix + CALL XCase ;force to ctl + CALL AdjKUp ;adjust UP ARROW ONLY + CALL Case ;What function? + DB OMnuLn/3 + DW Error2 ;complain if unknown +OMnuSt EQU $ + DB 81H ;up + DW MakTop + DB 'A'-40h + DW AITog + DB 'C'-40h + DW Center + DB 'D'-40h + DW HCRTog + DB 'F'-40h + DW Center ;same fn as 'C' + DB 'H'-40h + DW HypTog + DB 'I'-40h + DW VTSet + DB 'J'-40h + DW PSTog + DB 'L'-40h + DW SetLM + DB 'N'-40h + DW VTClr + DB 'P'-40h + DW PgSet + DB 'Q'-40h + DW NoHdr + DB 'R'-40h + DW SetRM + DB 'S'-40h + DW DblTog + DB 'T'-40h + DW Ruler + DB 'V'-40h + DW VTTog + DB 'W'-40h + DW Window + DB 'X'-40h + DW RelM + DB 'Z'-40h + DW Blank + DB ESC + DW COCan + DB ' ' + DW COCan +OMnuLn EQU $-OMnuSt +COCan: RET +; +;Quick commands. ^Q toggle is on. +; +Quick: LD HL,CQTog + CALL Prefix + CALL XCase + CALL AdjKey ;translate arrow/DEL + CALL Case ;What function? + DB QMnuLn/3 + DW Error2 ;complain if unknown +QMnuSt EQU $ + DB 80H ;DEL + DW EBLine + DB 81H ;Up arrow + DW QuikUp + DB 82H ;Down + DW QuikDn + DB 83H ;Right + DW QuikRt + DB 84H ;Left + DW QuikLf + DB 'A'-40h + DW Rplace + DB 'B'-40h + DW QikBlk + DB 'C'-40h + DW Bottom + DB 'F'-40h + DW Find + DB 'Q'-40h + DW Queue + DB 'I'-40h + DW ZipTo + DB 'P'-40h + DW QuikLc + DB 'R'-40h + DW Top + DB 'T'-40h + DW E2Char + DB 'U'-40h + DW UndlLn + DB 'Y'-40h + DW EOLine + DB 'Z'-40h + DW QuikMk + DB ESC + DW CQCan + DB ' ' + DW CQCan +QMnuLn EQU $-QMnuSt +CQCan: RET +; +; +; +Prefix: PUSH HL ;show prefix, get suffix + LD DE,DspEsc + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + LD B,1 + CALL BBlank + LD DE,DspEsQ ;position cursor + CALL GoTo + CALL RptKey ;get suffix + PUSH AF + LD A,(NoHdrF) + OR A + JR NZ,PrefNH + LD DE,DspEsc + CALL GoTo + LD B,4 ;clean up + CALL BBlank + CALL UnAlt + POP AF + RET +PrefNH: CALL UnAlt ;(if no header) + CALL ShoLn1 + CALL RulFix + POP AF + RET +; +; +;Return to CP/M ... With or without saving +; +Exit: CALL Save ;Save the file + LD A,(EdErr) ;Was it ok? + OR A + RET NZ ;No, do not quit + JR QuitY1 +; +Done: CALL Save ;Save, and load new + LD A,(EdErr) + OR A + RET NZ + JP Restrt +; +Quit: LD A,(Modify) ;Quit to CP/M + OR A + JR Z,QuitY1 + LD HL,QuitQ + CALL Prompt + CALL Confrm ;warn if file changed... + JP NZ,ShoLn1 +QuitY1: XOR A ;### + LD (WinFlg),A ;### + CALL AdjLns ;### + LD BC,Z3MSG ;### + CALL Z3EAdr ;### + JR Z,QuitY ;### + LD HL,MsgUsr ;### offset to user area in message buffers + ADD HL,BC ;### + LD DE,CurLin ;### store the current line# in the Z3 + EX DE,HL ;### + LD BC,2 ;### + LDIR ;### +QuitY: LD HL,TUInit ;Clear screen + CALL CtlStr + LD A,(CurDsk) ;restore logged disk + LD E,A + LD C,SELD + CALL BDOS + LD A,(CurUsr) ;and user + LD E,A + LD C,USRN + CALL BDOSep + CALL DOSVer + JP C,Boot ;### restart if CP/M 2.2 + CP 'S' ;### + JR Z,ZSErrR ;### + CP 'D' ;### + JR NZ,CPM3xt ;### +ZSErrR: LD C,SETF ;### restore ZxDOS flags +ZDflgs: LD DE,0 ;### + CALL BDOSep ;### +CPM3xt: LD C,ERRM ;### reset ZxDOS, CP/M 3 error mode + LD E,0 ;### + CALL BDOSep ;### + JP Boot ;### and restart +; +;Error handler +; +DoErr: CALL Loud ;Show error message, wait for ESC + CALL SetNo + LD A,(MacFlg) + OR A ;### + CALL NZ,RstI1x ;### + XOR A ;### + LD (MacFlg),A ;### kill any running macro + LD A,(EdErr) + CP 10 + JP NC,SetAl ;error 10 does NOT show + LD A,(Ring) + OR A + LD E,BEL + CALL NZ,ShutUp ; ring bell + CALL MakAlt + CALL UpLft + CALL Dspl + DB X,31,'[[','['+X,0 + LD A,(EdErr) + ADD A,A ;Double the code + LD L,A + LD H,0 + LD DE,ErrTab + ADD HL,DE + LD E,(HL) ;Get msg addr from table + INC HL + LD D,(HL) + EX DE,HL + CALL DspLp ;show it + CALL DsplC + DB ' ]]]',CR,0 + CALL UnAlt + CALL ESCLp + LD A,(EdErr) + CP 1 + JR Z,DoErr2 + CP 5 + JR Z,DoErr2 + CP 9 + JP C,ShoLn1 ;(errors 2-8 need no redisp) +DoErr2: JP SetAl +ESCLp: CALL RptKey ;await ESC from console + CP ESC + RET Z + CP ' ' + JR NZ,ESCLp + RET +; +Error0: LD A,0 ;clear error (don't change flags) + JR ErrSet +Error1: LD A,1 ;error set fns + JR ErrSet +Error2: LD A,2 + JR ErrSet +Error3: LD A,3 + JR ErrSet +Error4: LD A,4 + JR ErrSet +Error5: LD A,5 ;6 currently not used + JR ErrSet +Error7: LD A,7 + JR ErrSet +Error8: LD A,8 + JR ErrSet +Error9: LD A,9 + JR ErrSet +Eror10: LD A,10 +ErrSet: LD (EdErr),A + RET +; +; +;INPUT ROUTINES +; +KeyIn: LD HL,(Timer) ;Get key, regardless + LD H,0 + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL + INC HL +KyIn1: PUSH HL + CALL KyStat + POP HL + DEC HL + JR NZ,Keybd ;read key if got one + LD A,(HorFlg) + LD E,A + LD A,(KeyFlg) + OR E + OR H + OR L ;allow redisp for horizontal scroll? + JR NZ,KyIn1 + CPL + LD (HorFlg),A ;yep (just once) + CALL ShoAll + CALL Cursr + JR KyIn1 +; +Keybd: CALL KyStat ;Get key, or 0 if none + RET Z + LD HL,ConBuf + DEC (HL) ;uncount it + INC HL + LD A,(HL) ;here it is + LD D,H + LD E,L + INC HL + LD BC,ConBufL-1 + LDIR ;remove it + AND 7FH ;strip parity + RET +; +KyStat: CALL CONSt ;Console status with buffering + JR Z,ConChk ;all quiet + LD HL,ConBuf ;got key + INC (HL) ;ok, count it + LD E,(HL) + LD D,0 + ADD HL,DE ;point there + LD (HL),A ;put it in + LD A,E + CP ConBufL ;buffer full? + JR C,ConChk +ConBsy: LD A,0C9H ;(RET) + LD (Plug),A ;plug up the console until buffer empty +ConChk: LD A,(ConBuf) ;check buffer (FAST) + OR A + RET NZ + LD (Plug),A ;buffer empty, unplug console + RET +; +CONSt: XOR A +Plug: NOP ;<--- RET plugs up console + LD E,0FFH ;console status/input + LD C,UCON + CALL BDOSep + OR A ;test for null + RET +; +KyPeek: CALL KyStat ;key available? + RET Z ;no + LD A,(ConBuf+1) ;return 1st char in buffer + AND 7FH ;strip parity + RET +; +; +Confrm: CALL RptKey ;get a Y/N answer + CALL UCase + CP 'Y' ;return Z if confirmed + RET Z + CP 'U'-40h + JR Z,IsCtlU + CP ESC ;allow this too +IsCtlU: JP Z,Reset + CP 'N' + JR NZ,Confrm +CnfNo: OR A + RET +; +;Translate four arrow keys and BS,DEL +; +AdjKey: CP BS ;First handle ^H (special case) + JR NZ,AdjK0 + LD C,80h ;make it DEL + LD HL,UsrKys + CP (HL) ;Is it installed as DEL? + JR Z,AKret + LD C,84h ;no, then it's Left arrow + CP A + JR AKret +AdjK0: LD B,5 ;Not ^H, try the rest + JR AdjK1 +AdjKUp: LD B,2 ;only do (DEL and) UP arrow +AdjK1: LD HL,UsrKys + LD DE,WSKys + LD C,7FH ;encode 80h=DEL, 81h=up, etc. +AKlp: INC C + CP (HL) + JR Z,AKret + EX DE,HL + INC DE + CP (HL) + JR Z,AKret + INC HL + DJNZ AKlp + CP C + LD C,A ;NO match: return NZ, char in A and C +AKret: LD B,A ;MATCH: return Z, code in A, char in C + LD A,C + LD C,B + RET +WSKys: DB DEL,'E'-40H,'X'-40H,'D'-40H,'S'-40H +; +; +ANSIcu: CALL RptKey ;Handle ANSI cursor keys ESC-[... + SUB 'A' + JP Z,Up + DEC A + JP Z,Down + DEC A + JP Z,Right + DEC A + JP Z,Left + JP Error2 +; +;Get string input +; +GetStr: LD A,LinLen+1 ;string length +1 +GSEnt: LD (GSlen+1),A ;(entry for GetNum and NewNam) + LD HL,DMA ;*** MUST be 0080h *** +Lp1GSx: EXX + POP HL ;word after call + PUSH HL + LD E,(HL) ;storage/recall buffer address + INC HL + LD D,(HL) + LD (GSbufA),DE + EXX +Lp1GSy: XOR A + LD (RclFlg),A +Lp1GS: LD A,L + SUB DMA ;length +GSlen: CP 0 ;<---- max length pastes in here + JR NC,GSBS ;full? + LD A,(RclFlg) + OR A + JR NZ,GSrcl + PUSH HL + CALL RptKey ;Get next input + CALL AdjKey ;translate key + POP HL + CP 80H ;corrections? DEL, + JR Z,GSBS + CP 84H ;left + JR Z,GSBS + CP 83H ;right + JR Z,GSrcl ;recall a char + CP CR ;CR ends + JR Z,GSCR + CP 'U'-40H ;^U aborts operation + JP Z,Reset + CP 'P'-40H ;^P for ctlcode + JR Z,GSctl + LD A,C ;restore orig char + CP 'X'-40H ;wipeout + JR Z,GSwipe + CP 'R'-40H + JR Z,GSrcl ;recall the last string +; +Sk1GS: LD (HL),A ;Store byte + INC HL ;Move along + CP 20H ; ctl char? + PUSH HL + JR NC,Sk2GS ;no, just a normal char + ADD A,40H ;ctls are hili letters + PUSH AF + CALL AltY + POP AF + CALL PutChA + CALL UnAltY + JR Sk3GS +Sk2GS: CALL PutChA ;show byte +Sk3GS: POP HL + JR Lp1GS +; +GSBS: CALL GSBSsb + JR Lp1GSy +GSwipe: CALL GSBSsb + JR NZ,GSwipe + JR Lp1GSx +GSBSsb: LD A,DMA ;Are we at start + CP L + RET Z ;return Z if so + DEC HL ;back up pointer + LD E,BS ;wipe out char + CALL PutCh + LD E,' ' + CALL PutCh + LD E,BS + CALL PutCh + OR 1 ;clear flags + RET +; +GSrcl: EX AF,AF' ;save original char + EXX ;save HL + LD HL,(GSbufA) ;recall buffer ptr + LD A,H + OR L + EXX ;restore HL + JP Z,Lp1GS ;no recall buffer + EXX ;recall buffer ptr in HL + LD A,(HL) ;fetch char from recall buffer + EXX ;restore HL + OR A ;any char? + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + CP 0FFH + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + EXX ;recall buffer pre in HL + INC HL ;point to next char + LD (GSbufA),HL ;update recall buffer ptr + EXX ;restore HL + EX AF,AF' ;restore original char + CP 'R'-40h ;^R? (whole string) + JR NZ,GSrclX ;no, just a single char + LD (RclFlg),A +GSrclX: EX AF,AF' ;restore char from recall buffer + JR Sk1GS ;store char +; +GSCR: LD (HL),0 ;terminator + LD A,L + SUB DMA ;Compute input length (Z=zero) + POP DE ;skip over buffer address + INC DE + INC DE + PUSH DE + RET ;HL points past end of string +; +GSctl: PUSH HL + CALL RptKey + CALL XCase + POP HL + JP Sk1GS +; +;Get numeric input (0-65535 decimal), return C if bad +; +GetNbr: PUSH BC ;BC = default if no input + LD A,5+1 + CALL GSEnt ;get up to 3 digits + DW 0 + POP DE + JR NZ,GNyes + LD B,D + LD C,E + LD A,B ;no entry, use default + OR C + RET +GNyes: LD DE,DMA ;fall thru to GetNNN +; +GetNNN: PUSH HL ;gets decimal # pointed by DE + LD H,D + LD L,E + LD B,0 +GNL: LD A,(HL) + CP '0' + JR C,GotN ;terminated by any nondigit. + CP '9'+1 + JR NC,GotN + INC HL + INC B + LD A,B + CP 5+1 + JR NC,GNErr ;5 digits max. + JR GNL +GotN: LD A,B ;okay, do them + LD BC,0 + OR A ;digits? + JR Z,GNErr + CP 2 + JR Z,Got2 + JR C,Got1 + CP 4 + JR Z,Got4 + JR C,Got3 + CP 5 + JR NZ,GNErr +Got5: LD HL,10000 + CALL GNNdig + JR C,GNErr +Got4: LD HL,1000 + CALL GNNdig + JR C,GNErr +Got3: LD HL,100 + CALL GNNdig + JR C,GNErr +Got2: LD HL,10 + CALL GNNdig + JR C,GNErr +Got1: LD HL,1 + CALL GNNdig + JR C,GNErr + POP HL + LD A,B + OR C + RET +GNErr: POP HL + SCF ;error + RET +; +GNNdig: LD A,(DE) ;do a digit: HL=power of 10 + INC DE +GNNLp: CP '0' + RET Z + DEC A + PUSH HL + ADD HL,BC + LD B,H + LD C,L + POP HL + RET C ;overflow + JR GNNLp +; +;Versions of above for 0...255 only: GetNum, GetNN take # in A +; +GetNum: LD C,A + LD B,0 + CALL GetNbr + JR GetNN1 +GetNN: CALL GetNNN +GetNN1: RET C + XOR A + OR B + JR NZ,GetNNX + OR C ;result in A, OK + RET +GetNNX: SCF ;oops, too big + RET +; +; +;Convert 16-bit number in HL to a one to five +;digit decimal number in the area pointed to by DE +; +BCDCon: LD IX,P10Tab ;Point at table + PUSH DE ;Save output pointer +BCDlp1: LD B,(IX+1) + LD C,(IX) + LD A,C ;low byte + CP 1 ;Clear carry flag + JR Z,BCDend + SBC HL,BC ;Subtract from input + JR NC,BCDok ;Got one in range + ADD HL,BC ;Restore it + INC IX + INC IX + JR BCDlp1 ;Try next one +; +BCDok: LD A,'1' + LD (DE),A ;Set initial digit +BCDlp2: SBC HL,BC ;Subtract again + JR C,BCDsk1 ;Went negative + EX DE,HL + INC (HL) ;Increment digit + EX DE,HL + JR BCDlp2 +; +BCDsk1: ADD HL,BC ;Restore it + INC DE ;Bump output + INC IX + INC IX + LD C,(IX) + LD B,(IX+1) + LD A,C + CP 1 ;Is this last entry + JR Z,BCDend + LD A,'0' + LD (DE),A + JR BCDlp2 +; +BCDend: LD A,L + OR '0' + LD (DE),A + INC DE + EX DE,HL + POP BC + SBC HL,BC ;Number filled + LD A,5 ; needed + SUB L ; to do + RET Z + ADD HL,BC ;Restore pointer +BCDlp3: LD (HL),' ' ;Clear field + INC HL + DEC A + JR NZ,BCDlp3 + RET +; +P10Tab: DW 10000,1000,100,10,1 +; +; +; +;PRINT text from memory +; +Print: LD HL,PgLen ;set defaults + XOR A + CP (HL) + JR NZ,Pr00 + INC A ;bit 0 set if no pagn +Pr00: LD (POByt),A + XOR A + LD (HdrLen),A + LD (POff),A + CPL + LD (PNum),A + LD (PrFlg),A + LD A,1 + LD (Copies),A + LD (PBeg),A + LD A,(DotPO) + LD (PrLMrg),A + LD A,(PTMarg) + LD (PrTMrg),A + LD HL,PrtQ ;options? + CALL Prompt + CALL GetStr ;get string into 80 + DW 0 +PO1st: LD DE,DMA ;point to option string +PrOlp: LD A,(DE) + INC DE + LD HL,POByt ;set up bit flags + LD BC,PrOlp + PUSH BC ;(return) + CALL UCase + CP ' ' ;eat spaces + RET Z + CP 'B' + JR Z,POBlk + CP 'D' + JR Z,PODblS + CP 'P' + JR Z,POPau + CP 'L' + JR Z,POLMrg + CP 'T' + JR Z,POTMrg + CP '*' + JR Z,POCpy + CP '^' + JR Z,POCtl + CP '@' + JR Z,POBeg + CP '#' + JR Z,PONum + CP '=' + JP Z,POPgS + CP '"' + JP Z,POHdrT + POP BC ;kill return + OR A + JP NZ,Error7 ;unexpected char + LD A,(PrFlg) + LD B,A + XOR A ;zero PrFlg + LD (PrFlg),A + OR B + JR NZ,PO1st + JP PORdy +; +PrFlg: DB 0 +; +POCpy: CALL GetNN ;"*" sets copy count + JP C,POBad + LD (Copies),A + RET +POLMrg: CALL GetNN ;"Lnn" sets left margin + JP C,POBad + LD (PrLMrg),A + RET +POTMrg: CALL GetNN ;"Tnn" sets top margin + JR C,POBad + LD (PrTMrg),A + RET +POPau: SET 4,(HL) ;bit 4 is for "P" + RET +PODblS: SET 3,(HL) ;bit 3 is for "D" + RET +POCtl: SET 2,(HL) ;bit 2 is for "^" + RET +POBlk: LD A,(HL) + AND 11000010B ;bits 1,6,7 must be clear + JR NZ,POBad + SET 5,(HL) ;set bit 5 (BLOCK) + RET +POBeg: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"@" page beginning + JR C,POBad + OR A + JR Z,POBad + LD (PBeg),A + SET 6,(HL) ;bit 6 is for "@" (suppresses output) + SET 7,(HL) ;so is bit 7 (multicopy) + INC A + NEG ;255-@ is most # can be + LD B,A + LD A,(PNum) + CP B + RET C ;okay, less + LD A,B + LD (PNum),A + RET +PONum: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"#" page count + JR C,POBad + OR A + JR Z,POBad + LD B,A + LD A,(PBeg) + ADD A,B ;@ + # cannot exceed 255 + JR C,POBad + LD A,B + LD (PNum),A + RET +POPgS: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"=" starting pagination + JR C,POBad + OR A + JR Z,POBad + LD (POff),A ;offset beginning page + RET +POHdrT: BIT 0,(HL) ;must be paginating + JR NZ,POBad + SET 1,(HL) ;bit 1 requests header + LD (HdrPtr),DE ;point to header text + LD B,50 ;and figure its length +POHlp: LD A,(DE) + INC DE + CP '"' + JR Z,POHlpF + DJNZ POHlp + JR POBad ;too long +POHlpF: LD A,50 + SUB B ;length + LD (HdrLen),A + RET +POBad: POP HL ;eat return + JP Error7 +; +PORdy: CALL IOon ;say Wait + LD HL,PInit ;init string? + LD B,(HL) + INC HL + CALL LSTStr + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;move to top of file + LD A,(POff) + OR A + JR NZ,PORdy0 + LD A,(PBeg) +PORdy0: LD HL,PBeg + SUB (HL) ;adjust starting page offset + LD (POff),A + LD HL,POByt + BIT 5,(HL) + JR Z,PORdy1 + CALL IsBlk ;block print requested + BIT 1,A ; must be marked + JP Z,PrOops + INC DE + PUSH HL + SBC HL,DE + POP HL + RET Z ;block empty + DEC HL + EX DE,HL + JR PORdy2 +PORdy1: CALL NdCnt ;print whole file + JP C,PrDone ;file empty + LD HL,(AftCu) + LD DE,(EndTx) +PORdy2: LD (StPrt),HL + LD (EndPr),DE + CALL PCR ;### +; +RePrt: LD HL,POByt ;[reprint reentry] + BIT 7,(HL) + JR Z,PRP0 + SET 6,(HL) ;remember if "@" was used +PRP0: XOR A + LD (PageN),A + INC A + LD (IgnFlg),A ;TOF is start of line (DotChk) + LD A,(PgLen) ;start first page + LD B,A + OR A + PUSH AF ;### + CALL Z,DoPOf ;### + POP AF ;### + CALL NZ,PgBrk + JR C,Sk4Pr + LD HL,(StPrt) ;Point at first one + LD C,0 ;Initialize GetNx +Lp1Pr: CALL GetNx ;Get a character + CALL DotChk ;(maybe ignore dot command lines) + CP CR + JR NZ,Sk2Pr + CALL PrOut ;It's a CR + PUSH BC + PUSH HL + CALL Keybd + CP ESC ;Abort request? + POP HL + POP BC + JR Z,Sk1Pr + LD A,(POByt) + BIT 3,A ;doublespacing? do extra CR(LFCR)LF + JR Z,Sk0Pr + CALL PLF + CALL PCR + LD A,B ;count it (if paginating) + OR A + JR Z,Sk0Pr + DEC B + JR Z,Sk01Pr +Sk0Pr: LD A,B + OR A ;Not paginating? B is and stays 0 + LD A,(LFChr) ;Add usual line feed + JR Z,Sk2Pr + DJNZ Sk2Pr +Sk01Pr: CALL PgBrk ;time for NEW PAGE + JR C,Sk4Pr ;done? + JR Sk2aPr +Sk1Pr: LD A,1 ;abort + LD (Copies),A + JR Sk3Pr +Sk2Pr: CALL ChekC ;Check for masking + CALL PrOut ;Output char + XOR A + CP C ;Hidden space waiting? + JR NZ,Lp1Pr +Sk2aPr: LD DE,(EndPr) ;At end? + LD A,E + SUB L + LD A,D + SBC A,H + JR NC,Lp1Pr ;Loop if more to go +Sk3Pr: CALL PCR ;last CRLF for some matrix printers + LD A,(LFChr) + LD C,A + LD A,(PgLen) + OR A ;Finish page? + JR Z,Sk3aPr + LD C,FF +Sk3aPr: LD A,C + CALL PrOut +Sk4Pr: LD HL,PCodes ;undo toggles if on + LD DE,16 + LD B,4 +Lp2Pr: BIT 7,(HL) + JR Z,Lp2PrF + RES 7,(HL) + PUSH BC + PUSH DE + PUSH HL + LD DE,8 + ADD HL,DE + LD B,(HL) + INC HL + CALL LSTStr + POP HL + POP DE + POP BC +Lp2PrF: ADD HL,DE + DJNZ Lp2Pr + LD HL,Copies ;more copies? + DEC (HL) + JP NZ,RePrt + LD HL,PUInit ;uninit string? + LD B,(HL) + INC HL + CALL LSTStr + JR PrDone +PrOops: CALL Error7 +PrDone: LD HL,(LastCu) ;all finished + DEC HL + CALL MoveR ;go back to position + CALL IOoff + JP ShoLn1 +; +PgBrk: PUSH BC ;call this for new page (returns C for EOP) + PUSH HL + LD A,(PageN) + OR A + LD A,FF ;start new sheet IF not 1 + CALL NZ,PrOut + LD A,(POByt) + BIT 4,A ;pause requested? + JR Z,NP00 + CALL IOoff ;do it + LD HL,RdyQ + CALL Prefix + CP ESC + JP Z,NPquit + CALL IOon +NP00: LD HL,PageN + INC (HL) + JP Z,NPquit ;255 page limit. + LD C,(HL) ;check "#" limit? + LD A,(PBeg) + LD E,A + LD A,(PNum) ;Pnum+Pbeg-1 = Lastpage# + DEC A + ADD A,E + JP C,NPquit ;255 page limit + CP C + JP C,NPquit ;"#" pages printed... quit. + LD A,(PBeg) + LD C,A + LD A,(PageN) + CP C + LD HL,POByt + JR C,NP10 ;are we "@" yet? + RES 6,(HL) ;yes (start) printing + LD A,0C9H ;begin with margin offset + LD (DoPOf),A +NP10: LD A,(PrTMrg) + OR A + JR Z,NP20 + LD B,A +NP11Lp: CALL PCRLF ;top margin? + DJNZ NP11Lp +NP20: LD HL,POByt + BIT 1,(HL) + JR Z,NPnoh ;want header? + LD A,(HdrLen) + ADD A,6 + LD B,A + LD A,(RtMarg) ;column for page no. + SUB B + JR NC,NPlp + LD A,70 ;default if margin unusable + SUB B +NPlp: PUSH AF ;space over to right justify header + CALL PrSpc + POP AF + DEC A + JR NZ,NPlp + LD HL,(HdrPtr) ;put out header + LD A,(HdrLen) + LD B,A + CALL POStr + CALL PrSpc + LD A,(PageN) ;put out page + LD HL,POff + ADD A,(HL) ;adjust for "=" option + LD L,A + LD H,0 + LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + CALL POStr + CALL PCRLF + CALL PCRLF ;two blank lines + CALL PCRLF +NPnoh: XOR A + LD (DoPOf),A + CALL DoPOf + POP HL + POP BC + LD A,(PgLen) ;reset TOP + LD B,A + OR A + RET +NPquit: POP HL + POP BC + SCF + RET +PNBuf: DB 'nnnnn',0 ;(also used elsewhere) +; +DotChk: CP CR ;may ignore dot commands + JR Z,DotCCR + CP '.' + JR Z,DotCDt +DtC01: EX AF,AF' ;ordinary char + LD A,(IgnFlg) + CP 0FFh ;ignoring chars? + RET Z ;(returns 0FFh, nonprinting) + XOR A + LD (IgnFlg),A ;nope, clear dot search +DtCRet: EX AF,AF' ;no action, accept char + RET ;leave it 0FFh (ignore) +DotCCR: CALL DtC01 + EX AF,AF' + LD A,1 ;1 = ready to ignore if next char dot + LD (IgnFlg),A + EX AF,AF' + RET +DotCDt: EX AF,AF' + LD A,(FMode) ;Only ignore dotcmds in "W" mode + CP 'W' + JR NZ,DtCRet + LD A,(IgnFlg) + OR A + JR Z,DtCRet + LD A,0FFh ;FF = dot seen, ignore + LD (IgnFlg),A + RET +; +ChekC: CP ' ' ;may mask ctl chars + RET NC + CP CR ;exceptions: CR,LF,BadTbl + RET Z + CP LF + RET Z + PUSH HL + PUSH BC + LD HL,BadTbl + LD BC,BadLen + CPIR + POP BC + POP HL + RET Z + PUSH AF + LD A,(POByt) + BIT 2,A + JR NZ,CMask + POP AF + RET +CMask: LD A,'^' ;mask: print "^", + CALL PrOut + POP AF + OR 40H ;turn ^A into A, etc. + RET +; +PCR: LD A,CR + JR PrOut +PrSpc: LD A,' ' +PrOut: CP 0FFH ;(FF=dummy code, ignore) + RET Z + PUSH BC ;Print byte + PUSH DE + PUSH HL + LD HL,POByt ;printing yet? + BIT 6,(HL) + JR NZ,Sk2PO + CP ' ' + JR NC,Sk1PO ;non-ctl + LD HL,BadTbl + LD BC,BadLen + CPIR + JR Z,Sk2PO ;ILLEGAL + LD HL,TogTbl + LD BC,4 + CPIR ;toggle? + JR Z,Sk3PO + LD BC,4 + CPIR ;switch? + JR NZ,Sk1PO ;arbitrary ctl-code + LD A,4-1 + SUB C ;nontog# (0..n) + ADD A,A + ADD A,A + ADD A,A ;*8 + LD E,A + LD D,0 + LD HL,UCodes + ADD HL,DE +Sk00PO: LD B,(HL) + INC HL ;string to send +Sk0PO: CALL LSTStr + JR Sk2PO +Sk3PO: LD A,4-1 + SUB C ;tog# (0..n) + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;*16 + LD E,A + LD D,0 + LD HL,PCodes + ADD HL,DE + BIT 7,(HL) ;toggle status? + JR NZ,Sk3aPO + LD B,(HL) ;off, turn on + SET 7,(HL) + INC HL + JR Sk0PO +Sk3aPO: RES 7,(HL) ;on, turn off + LD DE,8 + ADD HL,DE + JR Sk00PO +Sk1PO: LD E,A ;byte to send + PUSH AF + CALL LSTOut + POP AF + LD HL,LFChr + CP (HL) + CALL Z,DoPOf ;LF? need margin skip +Sk2PO: POP HL + POP DE + POP BC + RET +; +DoPOf: NOP + LD A,(PrLMrg) ;do printer margin offset + OR A + RET Z + LD B,A +DoPOfL: CALL PrSpc + DJNZ DoPOfL + RET +; +PCRLF: CALL PCR ;do CR(LF?) +PLF: LD A,(LFChr) + JP PrOut +; +POStr: LD A,B ;send B chars at (HL) to PrOut + OR A + RET Z + LD A,(HL) + CALL PrOut + INC HL + DJNZ POStr + RET +; +LSTStr: LD A,B ;send B chars at (HL) to LST directly + OR A + RET Z + LD E,(HL) + PUSH BC + PUSH HL + CALL LSTOut + POP HL + POP BC + INC HL + DJNZ LSTStr + RET +; +LSTOut: LD C,LSTO ;print char in E + JP BDOSep +; +; +; +; ASSORTED SUPPORT ROUTINES +; +;RAM initialization functions +; +IniRAM: LD HL,MnuEnd ;Figure what used to be TxtOrg + LD A,(Help) ;help menus disabled? + OR A + JR NZ,IniR02 + LD HL,HelpY ;yes, use that memory for editing +IniR02: LD (BegTx),HL + LD HL,(BDOSep+1) ;BDOS origin (xx06) + LD L,-4 ;a few bytes room + DEC H ;back a page + LD (EndTx),HL + XOR A ;initialize screen + LD (NSkip),A + INC A + LD (Horiz),A + LD (Vert),A + LD (CurCol),A + LD (OldCol),A ;### + LD HL,1 + LD (CurPg),HL + LD (CurPgL),HL + LD (CurLin),HL + LD (OldLin),HL ;### + LD HL,(BegTx) ;set up cursor gap, mark CRs at ends + DEC HL + LD (BefCu),HL + LD (HL),CR + LD HL,(EndTx) + INC HL + LD (AftCu),HL + LD (HL),CR + RET +; +;Case selection subroutine +; CALL Case +; DB # of entries in list +; DW Default subroutine if no match +; DB value1 +; DW subroutine1.... +; +; +Case: POP HL + LD B,(HL) ;entries + INC HL + LD E,(HL) ;DE=default sbr + INC HL + LD D,(HL) + INC HL +Lp1Ca: CP (HL) ;Value matches? + INC HL + JR NZ,Sk2Ca + LD E,(HL) ;yes, get address + INC HL + LD D,(HL) + JR Sk3Ca ;finish up +; +Sk2Ca: INC HL ;No match, skip ahead +Sk3Ca: INC HL + DJNZ Lp1Ca ;Try again + EX DE,HL ;Swap sbr and return + PUSH DE ;Store return (end of list) + JP (HL) ;Go do sbr (LAST match) +; +; +XCase: CALL UCase ;force A to ctl-codes + CP '@' + RET C + CP '_'+1 + RET NC + AND 1FH + RET +UXCase: CP ESC ;uppercase A if letter OR ctl-code + JR NC,UCase + ADD A,40H + RET +UCase: CP 'a' + RET C ;uppercase A if letter + CP 'z'+1 + RET NC + AND 5FH + RET +; +; +Wait: LD A,(MacFlg) ;Macro Pause function + OR A + JP Z,Error2 + LD A,3 ;Wait about 3/2 sec + JR Dly0 +; +Delay: LD B,A ;Delay about A/2 sec + LD A,(MacFlg) ;but NOT if Macro going + OR A + RET NZ + LD A,B +Dly0: ADD A,A + ADD A,A +Dly1: PUSH AF + CALL BDly + POP AF + DEC A + JR NZ,Dly1 + RET +BDly: LD A,(MHz) + LD B,A + LD C,0 +BDlyLp: DEC BC + LD A,B + OR C + JR NZ,BDlyLp + RET +; +; +; UR-ROUTINES +; +Fill: LD (DE),A ;fill B bytes at DE with A + INC DE + DJNZ Fill + RET +; +GpCnt: LD BC,(BefCu) ;Count cursor gap size + LD HL,(AftCu) + DEC HL + DEC HL +SubDP: PUSH HL ;Double precision subtract + OR A ;BC = HL - BC + 1 + SBC HL,BC + LD B,H + LD C,L + INC BC + POP HL + RET +; +BgCnt: LD HL,(BegTx) ;Count bytes before cursor +LCnt: LD B,H + LD C,L + PUSH HL + LD HL,(BefCu) + CALL SubDP + POP HL + RET +NdCnt: LD HL,(EndTx) ;Count bytes after cursor +RCnt: LD BC,(AftCu) + JR SubDP +; +;Move bytes across cursor gap so the gap moves left. +;HL points to what will become BefCu. +; +MoveL: CALL LCnt ;bytes to move + RET C + LD DE,(AftCu) + DEC DE + LD HL,(BefCu) + LDDR + LD (BefCu),HL + INC DE + LD (AftCu),DE + RET +; +;MoveR - Moves gap right. HL will become BefCu. +; +MoveR: CALL RCnt + RET C + LD DE,(BefCu) + INC DE + LD HL,(AftCu) + LDIR + LD (AftCu),HL + DEC DE + LD (BefCu),DE + RET +; +;CrLft - Find CRs to left of cursor (up to E) +; +CrLft: CALL BgCnt + JR NC,Sk1Lf + XOR A ;no bytes, return with C and no Z + SUB 1 + RET +Sk1Lf: CALL FetchB + CP CR ;Is cursor on a CR + JR NZ,Sk2Lf + LD A,1 + CP E + JR NZ,Sk2Lf + SCF ;Asked for 1, and already there: ret C and Z + RET +Sk2Lf: LD A,CR +Lp3Lf: CPDR ;find a CR + JP PO,Sk4Lf ;count exhausted? + DEC E + JR NZ,Lp3Lf ;Do more? + INC HL ;Back up to before CR + INC HL + XOR A ;Found AOK, ret Z and no C + RET +Sk4Lf: INC HL ;Back to first byte + SCF + CCF ;Clear C + JR Z,Sk5Lf ;Was first byte CR + DEC E ;No, reduce count + RET +Sk5Lf: INC HL ;Back after CR + DEC E ;the one we wanted? + RET Z + DEC HL ;No, back in front of it + DEC E + RET +; +;CrRit - same, to right. +; +CrRit: CALL NdCnt + JR NC,Sk1Ri + XOR A + SUB 1 ;no bytes, return C and no Z + RET +Sk1Ri: LD D,E + LD A,CR + LD HL,(AftCu) +Lp2Ri: CPIR + JP PO,Sk3Ri + DEC E + JR NZ,Lp2Ri + SCF + CCF ;found AOK, ret Z and no C + RET +Sk3Ri: LD A,D + CP E + JR NZ,Sk4Ri + SCF ;none found, return C and Z + RET +Sk4Ri: LD HL,(EndTx) + DEC HL + LD A,CR + LD BC,0FFFFh + CPDR + INC HL + INC HL + OR 1 ;some but not enough, ret no C and no Z + RET +; +;cursor positioning subroutines +; +TopV: LD A,1 + JR LoadV +MidV: LD A,(TxtLns) + SRL A + JR LoadV +DecV: EXX + LD HL,(CurLin) + DEC HL + LD (CurLin),HL + EXX +DecVO: LD A,(Vert) ;returns Z if cannot Dec + CP 1 + JR Z,LoadV + DEC A + JR LoadV +IncV: EXX + LD HL,(CurLin) + INC HL + LD (CurLin),HL + EXX +IncVO: LD A,(Vert) ;returns Z if cannot Inc + EXX + LD HL,TxtLns + CP (HL) + EXX + JR Z,LoadV + INC A + JR LoadV +BotV: LD A,(TxtLns) +LoadV: LD (Vert),A + RET +LftH: LD A,1 + JR LoadH +LTabH: LD A,(Horiz) + DEC A + JR Z,RitH + CALL WhatC ;ouch, got to calculate + LD HL,NSkip ;Horiz = CurCol-NSkip + SUB (HL) + JR C,RitH + JR LoadH +DecH: LD A,(Horiz) + DEC A + RET Z + JR LoadH +TabH: LD A,(Horiz) + DEC A + EXX + LD HL,TabCnt + OR (HL) + EXX + INC A + JR IncT +IncH: LD A,(Horiz) +IncT: EXX + LD HL,View + CP (HL) + EXX + RET NC + INC A + JR LoadH +RitH: LD A,(View) +LoadH: EX AF,AF' ;### + LD A,(CurCol) ;### + INC A ;### + JR NZ,LoadH2 ;### + EX AF,AF' ;### + RET ;### +LoadH2: EX AF,AF' ;### + LD (Horiz),A + RET +; +; +;Get next text character from memory +;(HL and C keep track across repeated calls) +; +GetNx: XOR A + CP C ;Have we a hidden space? + JR NZ,Sk1Gt + LD A,(HL) ;No, get next byte + INC HL + CP 80H ;Does it have hidden space? + JR NC,Sk2Gt ;Yes, note and remove + CP CR + RET +Sk1Gt: DEC C ;Fetch hidden space + LD A,' ' + CP CR ;Set Z flag if CR + RET +Sk2Gt: AND 7FH + INC C + CP CR ;Set Z flag if CR + RET +; +;Hide any hideable spaces. (NEW ALGORITHM) +; +Cmprs: CALL BgCnt ;bytes to left + JR C,Sk2Cm ;none? + LD D,H + LD E,L + DEC DE +Lp1Cm: LD A,(HL) ;Get a byte + CP ' ' ;Nonspace? fine + JR NZ,Sk1Cm + LD A,(DE) ;Last byte CTL? fine + CP 20H + LD A,' ' + JR C,Sk1Cm + LD A,(DE) ;Hidden space already? fine + BIT 7,A + LD A,' ' + JR NZ,Sk1Cm + LD A,(DE) + OR 80h ;Got to hide the space. + DEC DE +Sk1Cm: INC DE ;Store byte + LD (DE),A + INC HL ;Bump input + DEC BC + LD A,B + OR C ;more to do? + JR NZ,Lp1Cm + LD (BefCu),DE ;This is now BefCu +; +Sk2Cm: CALL NdCnt ;How many after cursor? + RET C + LD HL,(EndTx) ;work back from end + LD D,H + LD E,L + INC DE +Lp3Cm: LD A,(DE) + CP ' ' ;Last byte space? + JR NZ,Sk3Cm + LD A,1FH ;This byte CTL? + CP (HL) + JR NC,Sk3Cm + BIT 7,(HL) ;This byte already hiding? + JR NZ,Sk3Cm + SET 7,(HL) ;Got to hide that space + INC DE +Sk3Cm: DEC DE + LDD ;Store byte, Bump input + INC DE + JP PE,Lp3Cm ;more to do? + LD (AftCu),DE ;This is now AftCu + RET +; +;Set BC to gap size (make room if needed, or set EdErr) +; +Space: LD L,A ;Save A + PUSH HL + CALL GpCnt ;Count gap size + CALL C,Cmprs ;No room? Hide spaces + CALL GpCnt ;Room now? + CALL C,Error1 ;out of memory + POP HL + LD A,L + RET +; +InsSpc: LD A,' ' +; +;Put ordinary byte in A into text at cursor. +; +Insrt: CALL Space ;Insert Before cursor + RET C + CP EOF + JR Z,Insrt1 + LD HL,BlkChr + CP (HL) + JR Z,Insrt1 + LD HL,Modify + LD (HL),0FFh +Insrt1: LD HL,(BefCu) ;Bump pointer + INC HL + LD (HL),A ;Store byte + LD (BefCu),HL + OR A ;Clear flags + RET +InsrtA: CALL Space ;same, but After cursor + RET C + LD HL,Modify + LD (HL),0FFh +InsrA1: LD HL,(AftCu) + DEC HL + LD (HL),A + LD (AftCu),HL + OR A + RET +; +;Compute absolute line number +; +CountS: LD HL,1 ;Hard way: from start + LD (CurLin),HL + CALL BgCnt + JR Sk0CL +CountL: LD HL,(LastCu) ;same but faster, using LastCu + INC HL + CALL LCnt +Sk0CL: RET C ;(At start, or have not moved) + LD DE,0 + LD A,CR + LD HL,(BefCu) +Lp1CL: CPDR + JR NZ,Sk1CL + INC DE + JP PE,Lp1CL +Sk1CL: LD HL,(CurLin) + ADD HL,DE + LD (CurLin),HL + RET +CountR: LD HL,(LastCu) ;same, but for backward move + DEC HL + CALL RCnt + RET C ;(have not moved) + LD DE,0 + LD A,CR + LD HL,(AftCu) +Lp1CR: CPIR + JR NZ,Sk1CR ;(have not moved) + INC DE + JP PE,Lp1CR +Sk1CR: LD HL,(CurLin) + OR A + SBC HL,DE + LD (CurLin),HL + RET +; +; +;MACRO functions +; +MacKey: LD HL,KeyQ + CALL Prompt + CALL RptKey ;which key? + CALL UCase + LD (MKsav),A + CP 'N' ;no-rpt request? + JR Z,MK0 + CP 'Q' ;no-rpt & macro request? + JR NZ,MK00 +MK0: CALL Echo ;show N or Q, get next + CALL RptKey +MK00: SUB '0' + JP C,Error7 + CP 10 + JP NC,Error7 + LD D,A ;save key + LD A,0FFH + LD HL,MacStr + LD BC,StrSiz+1 ;find end + CPIR + LD A,StrSiz + SUB C ;figure length + LD E,A ;save it + LD HL,Keys+2 + LD A,D + OR A + JR Z,MKlp1F +MKlp1: LD C,(HL) + LD B,0 ;find key in list + ADD HL,BC + INC HL + DEC A + JR NZ,MKlp1 +MKlp1F: LD A,(HL) ;old length + OR A + JR Z,MK1 + PUSH DE + PUSH HL ;delete old one + LD E,(HL) + LD D,0 + LD (HL),0 + INC HL + EX DE,HL + ADD HL,DE + LD B,H + LD C,L + PUSH HL + LD HL,Keys+200H + OR A + SBC HL,BC ;bytes to move + LD B,H + LD C,L + POP HL + LDIR + CALL VerKey + POP HL + POP DE +MK1: LD A,E ;anything to add? + OR A + JR Z,MKDone + LD A,(Keys+1) ;will it fit + OR A + JR NZ,MK1a + LD A,(Keys) + SUB E + JP C,Error1 ;out of memory +MK1a: LD (HL),E ;yes + INC HL + LD C,E + LD B,0 + PUSH HL + LD HL,Keys+200H-1 + LD D,H + LD E,L + OR A + SBC HL,BC ;from here + POP BC + PUSH HL + SBC HL,BC ;bytes to move + LD B,H + LD C,L + INC BC ;inclusive + POP HL + LDDR ;make room + LD C,(HL) + LD B,0 + INC HL + EX DE,HL + LD HL,MacStr + PUSH DE + LDIR ;insert new one + POP HL + LD A,(MKsav) + CP 'N' ;take care of N/Q request + JR Z,MK2 + CP 'Q' + JR NZ,MKDone + DEC HL + LD A,(HL) ;Q only works if length >1 + CP 2 + INC HL + JR C,MK2 + INC HL + SET 7,(HL) ;indicate quiet + DEC HL +MK2: SET 7,(HL) ;indicate no-rpt +MKDone: CALL VerKey + JP ShoLn1 +; +; +VerKey: LD B,10 ;verify key area + LD HL,200H-12 + LD D,0 + LD IX,Keys+2 +VKlp: LD A,StrSiz ;check size + CP (IX) + JR C,VKwipe + LD E,(IX) + SBC HL,DE ;decrement + JR C,VKwipe + ADD IX,DE ;move to next + INC IX + DJNZ VKlp + LD (Keys),HL ;free bytes + LD A,H + OR L + RET Z ;full? +VKlp2: LD (IX),0 + INC IX ;zero fill + DEC HL + LD A,H + OR L + JR NZ,VKlp2 + RET +VKwipe: LD HL,200H-12 ;oops, bad + LD (Keys),HL + LD IX,Keys+2 + LD HL,200H-2 + JR VKlp2 +; +ChainK: LD HL,MacFlg ;chain to new macro + BIT 0,(HL) ;(used only if macro going) + RET Z + CALL RstI1x ;reset INS to saved state + CALL RptKey ;get key # + CP '0' + JP C,Error8 + CP '9'+1 + JP NC,Error8 + PUSH AF + CALL Loud + XOR A + LD (MacFlg),A + POP AF + JR UK0 +; +UseKey: LD HL,MacFlg ;macro going already? + BIT 0,(HL) + RET NZ ;YES, this is just a label +UK0: SUB '0' ;NO, retrieve key 0-9 + LD B,A + LD HL,Keys+2 + JR Z,UKlp1F +UKlp1: LD E,(HL) + LD D,0 ;find it + ADD HL,DE + INC HL + DJNZ UKlp1 +UKlp1F: LD A,(HL) ;length + INC HL + OR A + JP Z,Error7 ;none? + LD C,A + LD B,0 + PUSH BC ;on stack for Mac00 entry + LD DE,DMA + PUSH DE + LDIR ;fetch it in + POP HL ;point to it + BIT 7,(HL) + RES 7,(HL) + JR Z,Mac00 ;not no-rpt? go ask, etc. + INC HL + BIT 7,(HL) + RES 7,(HL) + CALL NZ,Quiet ;quiet? + LD A,'1' + JR Mac0 ;go do just once +; +DoMac: LD HL,MacroQ ;get Macro defn + CALL Prompt + CALL GetStr + DW MacStr ;### + OR A + JR Z,MacDel ;none? delete + LD C,A ;save count + LD B,0 + PUSH BC +Mac00: LD HL,RptcQ ;(entry for normal Key) + CALL Prompt + CALL RptKey + CALL UCase + CP 'Q' + JR NZ,Mac0 + CALL Echo + CALL Quiet ;Q? do quiet, get rpt cnt + CALL RptKey +Mac0: POP BC ;string cnt (entry for no-rpt Key) + PUSH AF ;save rpt cnt + LD A,C + OR A ;null string? + JR Z,Mac1 + LD HL,DMA ;move in string + LD DE,MacStr + LDIR + EX DE,HL + LD (HL),0FFh ;terminator +Mac1: CALL ShoLn1 + POP AF + LD B,255 + CP '*' ;figure rpt cnt + JR Z,Mac2 ;(* is maximal) + LD B,0 ;(0 is default) + SUB '0' + JR C,Mac2 + CP 9+1 + JR NC,Mac2 + LD B,A +Mac2: LD A,B ;set rpt cnt + LD (RptCnt),A + OR A + JP Z,Loud ;oops, rpt=0 +Mac3: LD HL,MacStr ;Point to it + LD (CmdPtr),HL + LD A,0FFH ;Okay, here goes + LD (MacFlg),A + LD HL,InsFlg ;save INSERT toggle + LD A,(HL) + LD (SavIns),A ;turn INSERT off if on + BIT 7,(HL) + CALL NZ,ToggHL + RET +MacDel: LD A,0FFH + LD (MacStr),A + JP ShoLn1 +; +;"Macro Programming Language" +; +MacJmp: LD A,(MacFlg) ;jump to a label + OR A + JP Z,Error8 ;macro must be going + LD (JmpFlg),A ;say Jump in progress + CALL RptKey + LD HL,JmpFlg + LD (HL),0 + CP '[' ;TOF/EOF? + JR Z,MJtop + CP ']' + JR Z,MJend + CP '>' ;move/loops? + JR Z,MJRt + CP '<' + JR Z,MJLf + LD E,A ;key to find + LD HL,MacStr + LD B,StrSiz +MJlp: LD A,(HL) ;search along + INC HL + CP 0FFH + JP Z,Error8 + CP ESC + JR Z,MJlp01 + DJNZ MJlp + JP Error8 +MJlp01: LD A,E ;found ESC... right one? + CP (HL) + JR NZ,MJlp + INC HL ;yep + LD (CmdPtr),HL + RET +; +MJtop: LD HL,MacStr ;redo it from the top + LD (CmdPtr),HL + RET +MJend: XOR A ;quit + LD (MacFlg),A + LD E,A + CALL RstI1x + JP Loud +MJRt: CALL NdCnt ;right/left jump loops + JP C,Error7 ;stop at EOF + CALL Right + JR MJredo +MJLf: CALL BgCnt + JP C,Error7 + CALL Left +MJredo: LD HL,(CmdPtr) + DEC HL ;back up to the ESC to repeat + DEC HL + DEC HL + DEC HL + LD (CmdPtr),HL + RET +; +MacTst: LD A,0CAH ;(JP Z) + JR MacT1 +MacTsX: LD A,0C2H ;(JP NZ) +MacT1: LD (MacT),A + LD A,(MacFlg) + OR A ;macro must be going + JP Z,Error8 + CALL RptKey ;get char to match + LD E,A + CALL Fetch ;char at cursor + CP E +MacT: JP Z,MacJmp ;yes? jump <--- can be JP NZ too + JP RptKey ;no, just eat label +; +;Get the next key stroke (check Macro first.) +; +TRptKy: XOR A ;enable redisp Timer + JR RK0 +RptKey: LD A,0FFH +RK0: LD (KeyFlg),A + LD A,(MacFlg) + OR A ;macro waiting? + JP Z,KeyIn ;no. +MacIn: CALL Keybd ;YES, check keyboard for abort + CP ESC + JR NZ,MacIn1 + LD HL,(CmdPtr) ;abort, make this last char + LD E,(HL) + LD HL,MacFF+1 ;### + LD (CmdPtr),HL ;### + JR MacIn3 +MacIn1: LD HL,(CmdPtr) ;OK, take waiting char + LD A,(HL) + INC HL ;bump pointer + LD (CmdPtr),HL +MacFF: CP 0FFH ;### + JR Z,MacFFx ;### + LD E,A ;### + LD A,(HL) ;end of macro now? (FF) + INC A + JR NZ,MacIn2 ;NO, return char + LD A,(JmpFlg) ;jump in progress? + OR A + JR NZ,MacIn2 + LD HL,RptCnt ;need to repeat? + LD A,(HL) + INC A + JR Z,McIn1a + DEC (HL) + JR Z,MacIn3 +McIn1a: LD HL,MacStr ;repeat: reset pointer + LD (CmdPtr),HL + JR MacIn2 +MacIn3: CALL Loud +MacIn2: LD A,E + AND 7FH ;strip parity, return char + RET +MacFFx: XOR A ;NO, stop macro execution + LD (MacFlg),A + CALL RstI1x ;restore saved INS state + JP KeyIn +; +; +;Unconditional Q/L for Macros +; +Quiet: LD HL,ShutUp + LD (HL),0C9H ;(RET) + RET +Loud: LD HL,ShutUp + XOR A ;(NOP) + CP (HL) + RET Z + LD (HL),A + JP HoldSc ;gotta see... +; +RstI1x: LD A,(SavIns) + LD HL,InsFlg + CP (HL) + CALL NZ,ToggHL ;switch INS to match the saved state + RET +; +;Conditional Q/L for formatting etc. +; +; +XQuiet: LD HL,ShutUp + LD A,(HL) + LD (HL),0C9H ;(RET) + LD (SavQ),A + RET +XLoud: LD A,(SavQ) + OR A ;(NOP) + RET NZ + LD (ShutUp),A + RET ;do NOT need redisp here +; +;Force loud for header display +; +Force: LD HL,ShutUp + LD A,(HL) + LD (HL),00H ;(NOP) + LD (SavQ2),A + RET +UForce: LD A,(SavQ2) + CP 0C9H ;(RET) + RET NZ + LD (ShutUp),A + RET +; +; +; VDE EDITING FUNCTIONS +; +; +;Show information +; +Info: CALL MakAlt ;show this first for entertainment + CALL UndrHd + CALL Dspl + DB X,26,0 + LD HL,VersID + CALL DspLp + CALL Cmprs ;pack spaces + CALL GpCnt ;count gap size + PUSH BC + LD H,B + LD L,C + LD DE,FreNNN ;show it as "free space" + CALL BCDCon + LD HL,(EndTx) + INC HL + LD DE,(BegTx) + OR A + SBC HL,DE + POP BC + SBC HL,BC ;memory used + LD DE,UsdNNN + CALL BCDCon ;show it as "used" + LD HL,(BegTx) + LD DE,(BefCu) + CALL FSzSbr ;figure actual disk file size + PUSH BC + LD HL,(AftCu) + LD DE,(EndTx) + CALL FSzSbr + POP HL + ADD HL,BC + LD DE,SizNNN ;show it as "file size" + CALL BCDCon + LD A,(Modify) + OR A ;file changed? + LD A,'Y' + JR NZ,Info2 + LD A,'N' +Info2: LD (ModQQQ),A + LD HL,InfMsg ;now display the data + CALL DspLp + CALL UnAlt + CALL ESCLp + JP SetAl +; +FSzSbr: LD BC,0 ;count a block +FSzLp: LD A,E ;done? + SUB L + LD A,D + SBC A,H + RET C + LD A,(HL) + INC HL + INC BC ;count character + CP CR + JR Z,FSz1 ;and (missing) LF? + CP X + JR C,FSzLp ;and (hidden) space? +FSz1: INC BC + JR FSzLp +; +; +; Blank the screen +; +Blank: LD A,(WinFlg) ;window off first (will lose text) + OR A + CALL NZ,Window + LD HL,CsrOff ;### + CALL CtlStr ;### + LD HL,TInit + CALL CtlStr + CALL ESCLp + CALL DoHdr + JP SetAl +; +; +;Move cursor to the beginning of text +; +Top: LD HL,(BegTx) + CALL MoveL ;Move + CALL TopV ;Adjust cursor + CALL LftH + LD HL,1 + LD (CurLin),HL + JP SetAl +; +; +;Move cursor to the last character of text +; +Bottom: LD HL,(BefCu) ;for CountL + LD (LastCu),HL + LD HL,(EndTx) + CALL MoveR ;Move + CALL BotV ;Adjust cursor + CALL RitH + CALL CountL + JP SetAl +; +; +; Queue: move to next line in ZCPR queue +; +Queue: LD BC,Z3MSG + CALL Z3EAdr + JP Z,Error7 ; no Z3 message buffers + LD D,B ; addr of Z3MSG to DE + LD E,C + LD HL,RegNum+1 ; current register addr + LD A,(HL) + CP MsgUsr-2+MsgNmU ; time to wrap around? + JR NZ,QueNxt +QueWrp: LD A,MsgUsr-2 ; yes + LD (HL),A ; update it +QueNxt: INC (HL) ; next register + INC (HL) +RegNum: LD HL,MsgUsr-2 + ADD HL,DE ; point to next line # + LD C,(HL) + INC HL + LD B,(HL) ; line # to BC + LD A,B + OR C + JP NZ,ZipTo2 ; go to it + LD HL,RegNum+1 ; is first register empty? + LD A,(HL) + CP MsgUsr + JP Z,Error7 ; yes, error + JR QueWrp ; no, wrap around +; +; +;QUICK cursor movements +; +QuikMk: CALL NdCnt ;look for next place marker + JR C,QkMk1 + LD HL,(AftCu) + LD A,EOF ;marker + CPIR + JP Z,QikB1 ;found? rest same as ^QB +QkMk1: CALL BgCnt ;not? try from top + JR C,QkMk2 + LD HL,(BegTx) + LD A,EOF + CPIR + JP Z,QikB0 ;found? rest same as ^QB +QkMk2: JP Error7 ;not? error. +; +QuikLf: LD E,1 ;move left to start of line + CALL CrLft + RET C + LD A,1 + LD (CurCol),A ;(useful for format subroutines) + CALL MoveL + CALL LftH + JP IfScl +; +QuikRt: CALL NdCnt ;move right to end of line + JP C,ColCnt + CALL Fetch + JP Z,ColCnt + CALL Right + RET C + JR QuikRt +; +QuikUp: LD A,(Vert) ;move up to top of screen + DEC A + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QUlp: PUSH BC + CALL Up + POP BC + DJNZ QUlp + CALL SetNo + POP AF ;restore col + JP SkQUD +; +QuikDn: LD A,(TxtLns) ;move down to end of screen + LD HL,Vert + SUB (HL) + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QDlp: PUSH BC + CALL Down + POP BC + DJNZ QDlp + CALL SetNo + POP AF + JP SkQUD +; +ZipTo: LD HL,PageQ ;zip to given page + LD A,(PgLen) + OR A + JR Z,ZipTo0 + LD A,(FMode) + CP 'N' + JR NZ,ZipTo1 +ZipTo0: LD HL,LineQ ;or line, in N mode +ZipTo1: CALL Prompt + LD BC,1 + CALL GetNbr + JP C,Error7 + JP Z,Error7 + LD A,(FMode) + CP 'N' + JR Z,ZipTo2 + LD A,(PgLen) ;(calculate line) + OR A + JR Z,ZipTo2 + LD D,0 + LD E,A + LD L,D + LD H,D + DEC BC +ZipMul: LD A,B + OR C + JR Z,ZipMF + ADD HL,DE + DEC BC + JR ZipMul +ZipMF: INC HL +ZipMF2: LD B,H + LD C,L +ZipTo2: PUSH BC + CALL Top + POP DE ;desired line + LD A,D + OR E + JR Z,ZipXit + DEC DE ;lines to move down + XOR A + OR D + JR Z,ZipLpF +ZipLp: PUSH DE ;do multiples of 256 + LD E,0 ;(256) + CALL CrRit + DEC HL + CALL MoveR + POP DE + DEC D + JR NZ,ZipLp +ZipLpF: XOR A + OR E + JR Z,ZipTo3 + CALL CrRit ;do remainder + DEC HL + CALL MoveR +ZipTo3: CALL MidV + CALL RitH + CALL CountS +ZipXit: JP SetAl +; +; +;Move cursor up. +; +Up: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,2 ;start of last line + CALL CrLft + RET NZ ;TOF? quit + PUSH HL + CALL EdgeU + CALL DecV + POP HL + CALL MoveL +SkUpDn: LD A,(CurCol) ;where we were +SkQUD: CALL GoCol + RET Z ;exact? + JP IfScl ;may need to scroll +; +; +;Move cursor down. +; +Down: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,1 ;start of next line + CALL CrRit + DEC HL + JR NC,Sk1Dn ;was there one? + RET NZ ;EOF? quit + LD HL,(EndTx) + LD A,(HL) ;Get that last byte + CP CR + RET NZ ;no next line +Sk1Dn: PUSH HL + CALL EdgeD + CALL IncV + POP HL + CALL MoveR + JR SkUpDn +; +QuikLc: LD HL,(SavLin) + CALL ZipMF2 + LD A,(SavCol) +; +; +GoCol: DEC A ;restore cursor to column A + RET Z + LD HL,(HorFlg) ;don't change show status + PUSH HL + PUSH AF + CALL ColCnt ;where are we? + LD IY,CurCol + JR GRCent +GRCLp: CALL NdCnt + JR C,GRCF ;stop at EOF + CALL Fetch + JR Z,GRCF ;stop at CR + CP TAB ;tabs are special + JR NZ,GRC1 + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A +GRC1: INC (IY) ;Keep CurCol updated + CALL Right +GRCent: POP AF + PUSH AF + CP (IY) ;there yet? + JR NC,GRCLp +GRCF: POP AF + POP HL + LD (HorFlg),HL + INC A + SUB (IY) ;set Z if exact + RET +; +; +;Move cursor one to the left (C=cannot) +; +Left: CALL Space ;Any space left? + RET C + CALL BgCnt ;Are we at front? + RET C + CALL EdgeL + LD HL,(BefCu) ;Look back + LD A,(HL) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1Lt ;No, just move + RES 7,(HL) ;Yes, unhide it + LD A,' ' + INC HL +Sk1Lt: DEC HL ;Back up + LD (BefCu),HL + CALL InsrA1 ;store byte ahead + CP TAB ;Was a TAB moved + JR Z,LftTab + CP CR ;Was a CR moved? + JR Z,LftCR + CALL DecH ;no + OR A + RET NZ + JP IfScl ;at left mgn...scroll? +; +LftCR: CALL RitH ;special cases - scrolling + CALL DecV + CALL ColCnt + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl + OR A + RET +LftTab: LD A,(Horiz) + DEC A + CALL Z,HorScl ;need to scroll if at left + CALL LTabH + OR A + RET +; +; +;Move cursor one to the right +;(return C if can't, char passed in A) +; +Right: CALL Space ;Any room left? + RET C + CALL NdCnt ;Already at end? + RET C + CALL EdgeR + CALL Fetch + JR NZ,Sk0Rt + PUSH HL + CALL TestCu ;change of line: no delays + CALL NZ,ShoCu1 + POP HL +Sk0Rt: LD A,(HL) + BIT 7,A ;Hidden space? + JR Z,Sk1Rt ;No, just move + LD (HL),' ' ;Yes, unhide it + AND 7FH + DEC HL +Sk1Rt: INC HL ;Bump pointer + LD (AftCu),HL + CALL Insrt1 ;put byte in behind + OR A ;and return it + PUSH AF + CP TAB ;TAB and CR are special + JR Z,RtTab + CP CR + JR Z,RtCR + CALL IncH ;no, just move + POP AF + RET +; +RtCR: CALL IfScl ;may have to scroll + CALL IncV ;adjust + CALL LftH + LD A,1 + LD (CurCol),A + POP AF + RET +; +RtTab: LD A,(View) + DEC A + LD HL,TabCnt + SUB (HL) + LD HL,Horiz + SUB (HL) + CALL C,HorScl ;at right, need to scroll + CALL TabH + POP AF + RET +; +; +;Word tab, delete +; +WdMxCh EQU 255 ;max chars to loop +; +WordRt: CALL Fetch ;Word tab right + JP Z,Right ;at EOL? special case + CALL IsBlnk ;on break? just find nonbreak + JR Z,WRlpF + LD B,WdMxCh +WRlp: CALL WRfBrk + JR Z,WRlpF + CP CR ;quit at CR + RET Z + DJNZ WRlp +WRlpF: LD B,WdMxCh +WRlp2: CALL WRfBrk + RET NZ + DJNZ WRlp2 + RET +WRfBrk: PUSH BC + CALL Right + JR C,WRfBrX + CALL IsBlnk ;then nonbreak + CALL NZ,IsPunc + PUSH BC +WRfBrX: POP BC + POP BC + RET +; +WordLf: CALL FetchB ;Word tab left + CP CR ;at BOL? Special case + JP Z,Left + LD B,WdMxCh +WLlp: CALL IsParB ;find a nonbreak + CALL NZ,IsPunB + JR NZ,WLlpF + CP CR ;quit at CR + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp +WLlpF: CALL Left + LD B,WdMxCh +WLlp2: CALL IsParB ;then a break + CALL NZ,IsPunB + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp2 + RET +; +WordDl: CALL Fetch ;Word Delete + JP Z,EChar ;at BOL? special case + CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNB ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNB: LD B,WdMxCh +WDlp2: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak + CP CR ;but quit at CR + RET Z + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2 + RET +WDlB: LD B,WdMxCh +WDlp: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET Z ;delete till reak + PUSH BC + CALL EChar + POP BC + DJNZ WDlp + RET +; +Join: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNBx ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNBx: LD B,WdMxCh +WDlp2x: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak (including CRs) + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2x + RET +; +IsPaPu: CALL IsPara + CALL NZ,IsPunc + RET +; +; +;Move cursor ahead one page +; +PageF: CALL SetAl + LD A,(TxtLns) + DEC A + LD E,A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgF1 + INC A + LD E,A +PgF1: CALL CrRit ;Point that many CRs down + DEC HL ;Back off one byte + JP C,Bottom + JP NZ,Bottom + LD DE,(BefCu) ;Prepare Count + LD (LastCu),DE + CALL MoveR ;Move cursor gap + CALL CountL + JR LDaGoC ;relocate cursor +; +; +;Move cursor back one page +; +PageB: CALL SetAl + LD A,(TxtLns) + LD E,A + DEC A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgB1 + ADD A,2 + LD E,A +PgB1: CALL CrLft ;Point that many CRs back + JP C,Top + JP NZ,Top + LD DE,(AftCu) ;Prepare Count + LD (LastCu),DE + CALL MoveL ;Move cursor gap + CALL CountR +LDaGoC: LD A,(CurCol) + JP GoCol ;relocate cursor +; +; +;Scroll screen 1/4 vertically +; +ShftD: LD A,(TxtLns) ;Down + SRL A + SRL A + INC A + LD B,A +LDLp: PUSH BC + CALL DecVO + JR NZ,LDLpF + CALL Down ;oops, cursor already on top + CALL DecVO +LDLpF: POP BC + DJNZ LDLp + JP SetAl +; +ShftU: LD A,(TxtLns) ;same, up + SRL A + SRL A + INC A + LD B,A +LULp: PUSH BC + CALL IncVO + JR NZ,LULpF + CALL Up ;oops, cursr already on bottom + CALL IncVO +LULpF: POP BC + DJNZ LULp + JP SetAl +; +Scr1LD: CALL DecVO ;FAST one-line scrolls + JR NZ,ScLD1 + CALL Down ;oops, already on top + CALL DecVO +ScLD1: LD HL,DelL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + LD A,(TxtLns) + LD B,A + JP ShoLn ;re-show last line +; +Scr1LU: LD HL,(CurLin) + LD DE,(Vert) + LD D,0 + OR A + SBC HL,DE + RET Z ;oops, nowhere to go + CALL IncVO + JR NZ,ScLU1 + CALL Up ;oops, already on bottom + CALL IncVO +ScLU1: LD HL,InsL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + JP ShoLn1 +; +;Scroll screen 32 cols horizontally +; +ShftR: LD HL,Horiz ;INcrease screen scroll (right) + LD A,(HL) + SUB 32+1 + RET C + INC A + LD (HL),A + LD HL,NSkip + LD A,(HL) + ADD A,32 + JR ShftX +; +ShftL: LD A,(Horiz) ;DEcrease scroll (left) + ADD A,32 + LD HL,View + CP (HL) + RET NC + LD (Horiz),A + LD HL,NSkip + LD A,(HL) + SUB 32 + RET C +; +;Make current line top +; +ShftX: LD (HL),A + JP SetAl +; +MakTop: CALL TopV ;gee boss, that was easy, huh? + JP SetAl +; +; +;FIND/REPLACE +; +;Find next occurance of a given string. +; +Find: CALL FndSub + JP C,Error7 + CALL ShoLn1 +; + LD A,(FGlobl) + OR A + JR Z,RpFind + LD A,(FBackw) ;global search: backwards? + OR A + JR Z,FndBck + CALL Bottom ;...yes, goto bottom of file + JR RpFind +FndBck: CALL Top ;...no, goto top of file +RpFind: LD A,(FndStr) ;length + OR A + RET Z ;no string, quit + LD A,(FBackw) + OR A ;backward? + JR NZ,RpF5 + CALL NdCnt ;number to scan + JP C,Err4x + LD HL,(EndTx) + LD DE,(FndStr) ;string length + XOR A + LD D,A ;extend to 16 bits + SBC HL,DE +RpSsLp: INC HL + BIT 7,(HL) ;soft space? + JR Z,RpSsNo ;nope + INC A ;count soft spaces? +RpSsNo: DEC E ;decrement string length + JR NZ,RpSsLp + ADC A,C + LD C,A + LD A,B + ADC A,0 + LD B,A + LD HL,FndStr + LD A,C + SUB (HL) + LD C,A ;less string length + LD A,B + SBC A,0 + LD B,A + JR C,Err4x + INC BC ;in case last + LD HL,(BefCu) + LD (LastCu),HL ;Mark position + LD HL,(AftCu) + LD A,(ChgFlg) ;was last operation change? + OR A + JR NZ,RpF1 + INC HL ;NO, start at next byte + DEC BC ;YES, start at this byte +RpF1: LD A,B + OR C + JR Z,Err4x ;gotta have bytes + LD A,(FUCase) + CP 0C3H ;ucase? (groan) + JR Z,SlowFi + LD A,(FndStr) ;only one char? (groan) + DEC A + JR Z,SlowFi + LD DE,(FndStr+1) ;space in char 1 or 2? (groan) + LD A,' ' + CP D + JR Z,SlowFi + CP E + JR Z,SlowFi + JR FastFi +; +Err4x: LD A,(FGlobl) + OR A + JP Z,Error4 ;not found + LD HL,(OldLin) + CALL ZipMF2 + LD A,(OldCol) + CALL GoCol + JP Error5 +; +RpF5: CALL BgCnt ;backward: number to scan + JR C,Err4x ;EOF? + LD HL,(AftCu) + LD (LastCu),HL ;Mark position + LD HL,(BefCu) + JR BackFi +; +FastFi: LD A,B ;find lead char FAST with CPIR + OR C + JR Z,Err4x + LD A,(FndStr+1) + CPIR + JP PE,FstFi1 ;jump if P/V=1 (BC-1 is not 0) + JR NZ,Err4x ;NOT found +FstFi1: PUSH BC + PUSH HL + LD C,0 ;no hidden spaces involved + CALL FndChk ;rest of string? + POP HL + POP BC + JR NZ,FastFi ;no match, keep going + LD C,0 + JP Found +; +SlowFi: LD A,(FndStr+1) ;find lead char the slow way + LD (LdChar+1),A ;(spaces or upcase involved) + LD D,H + LD E,L + ADD HL,BC + EX DE,HL + LD C,0 +Lp1Fi: LD (FindSv),BC ;save hidden space status + CALL GetNx + CALL FUCase +LdChar: CP 0 ;<---- + JR Z,Lp1Fi1 ;got one +Lp1Fi0: LD A,H + XOR D + JR NZ,Lp1Fi + LD A,L + XOR E + JR NZ,Lp1Fi + JR Err4x +Lp1Fi1: PUSH BC + PUSH DE + PUSH HL + CALL FndChk ;rest of string? + POP HL + POP DE + POP BC + JR NZ,Lp1Fi0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR Found +; +BackFi: LD A,(FndStr+1) ;find lead char backwards + LD (LdChr2+1),A + PUSH HL + OR A + SBC HL,BC + PUSH HL + POP DE + POP HL + INC HL + INC HL ;adjust for kludge below + LD C,0 +Lp1BF: LD A,C + LD (FindSv),A ;clear hidden space status + OR A + JR Z,Lp1BFa + DEC C + LD A,' ' + JR Lp1BFb +Lp1BFa: DEC HL ;back up + DEC HL + LD A,(HL) + INC HL ;simulate GetNx in reverse + BIT 7,A + JR Z,Lp1BFb + INC C +Lp1BFb: AND 7Fh + CALL FUCase +LdChr2: CP 0 ;<----- + JR Z,Lp1BF1 ;got one +Lp1BF0: LD A,H + XOR D + JR NZ,Lp1BF + LD A,L + XOR E + JR NZ,Lp1BF + JP Err4x +Lp1BF1: PUSH HL + PUSH DE + PUSH BC + CALL FndChk ;rest of string? + POP BC + POP DE + POP HL + JR NZ,Lp1BF0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR FoundB +; +FndChk: LD A,(FndStr) ;is (HL) a hit? + DEC A + RET Z ;just one char: already matched + LD B,A + LD DE,FndStr+2 ;start at char2 +Lp1FC: CALL GetNx + CALL FUCase + EX DE,HL + CP (HL) + EX DE,HL + JR Z,Sk1FC + LD A,(DE) ;hmm, no match + PUSH HL + LD HL,WildCd ;consider wildcard + CP (HL) + POP HL + RET NZ ;NOPE. +Sk1FC: INC DE ;match, keep on + DJNZ Lp1FC + RET ;YES. +; +; +Found: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back to char1 + DEC HL ;put cursor BEFORE char1 + CALL MoveR + LD HL,(AftCu) ;Hidden space there? + BIT 7,(HL) + JR Z,Found1 + OR A ;need to be on it? + JR Z,Found1 + LD A,(HL) + AND 7FH ;Yep, unhide it + LD (HL),' ' + CALL Insrt1 +Found1: CALL MidV ;Center on screen +Chged0: CALL CountL ;Adjust line number +Chged: CALL RitH ;Adjust cursor + LD HL,ChgFlg + BIT 0,(HL) + JP Z,SetAl ;find? redisplay + LD HL,FndStr + XOR A + ADD A,(HL) + JR Z,Chgd1 + LD C,A ;change: CR involved? + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl ;yes +Chgd1: LD HL,ChgStr + XOR A + ADD A,(HL) + JP Z,SetCu ;no + LD C,A + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl + JP SetCu +; +FoundB: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back before char1 + CALL MoveL ;Move to found string + LD HL,(AftCu) ;hidden space there? + BIT 7,(HL) + JR Z,FounB1 + OR A ;yes, need to be on it? + JR Z,FounB1 + LD A,(HL) ;Yes, unhide it + AND 7Fh + LD (HL),' ' + CALL Insrt1 +FounB1: CALL MidV ;Center on screen + CALL RitH ;Adjust cursor + CALL CountR ;Adjust line number + JP SetAl +; +FndSub: LD HL,FindQ ;Get Find string + CALL Prompt + CALL GetStr ;Put string in 80 + DW FndStr+1 + LD DE,FndStr + LD (DE),A + RET Z ;no string + INC DE + XOR A + LD (ChgFlg),A ;find, not change + LD (FBackw),A ;not (yet) backwards + LD (FGlobl),A ;not (yet) global + LD A,0C3H ;(JP) + LD (FUCase),A ;ignore case + LD HL,DMA + LD A,(HL) + CP '/' + JR NZ,FndSb2 + INC HL +FndSL1: LD A,(HL) + INC HL + OR A + RET Z + CP '/' ;do /options/ + JR Z,FndSb2 + CALL UCase + CP 'C' + JR Z,FOptC + CP 'B' + JR Z,FOptB + CP 'G' + JR Z,FOptG + SCF + RET +FOptC: LD A,0C9H ;(RET) respect case + LD (FUCase),A + JR FndSL1 +FOptB: LD (FBackw),A ;backward + JR FndSL1 +FOptG: LD A,0FFH + LD (FGlobl),A + JR FndSL1 +FndSb2: LD B,0 +FndSL2: LD A,(HL) ;move string in + INC HL + CALL FUCase + OR A + LD (DE),A + JR Z,FndSLF + INC DE + INC B + JR FndSL2 +FndSLF: LD A,B ;count + LD (FndStr),A + RET +; +FUCase: JP UCase ;<--- becomes RET +; +;Change found string [this entry NOT currently in use] +; +;Change: CALL ChgSub ;get string +; +RepChg: LD HL,(BefCu) ;mark position + LD (LastCu),HL + LD A,(FndStr) + OR A + JR Z,RpCh1F ;no string + LD B,A ;count to erase +RpCh1: PUSH BC + CALL EChar + POP BC + JP C,Error7 + DJNZ RpCh1 +RpCh1F: LD HL,ChgStr ;point to string + LD A,(HL) ;count to replace + OR A + JR Z,RpCh3 ;quit if no new string + LD B,A + PUSH BC +RpCh2: INC HL + PUSH BC + PUSH HL + LD A,(HL) + CALL Insrt + POP HL + POP BC + CALL C,Error1 ;out of memory + DJNZ RpCh2 + POP BC + LD A,(FBackw) + OR A +RpCh3: JP Z,Chged0 +RpCh4l: PUSH BC + CALL Left + POP BC + RET C + DJNZ RpCh4l + CALL CountR + JP Chged +; +ChgSub: LD A,0FFH ;say we've done a change + LD (ChgFlg),A + LD HL,ChgQ + CALL Prompt + CALL GetStr ;Put string in 80 + DW ChgStr+1 + PUSH AF + CALL ShoLn1 ;may need this later + POP AF + LD DE,ChgStr + LD (DE),A + RET Z ;do not LDIR with B=0 + INC DE + LD C,A + LD B,0 + LD HL,DMA + LDIR ;Move string in + XOR A + LD (DE),A ;zero terminate it + RET +; +;Global replace +; +Rplace: LD A,0FFH + LD (YNFlg),A + CALL FndSub + JP C,Error7 + LD A,(FndStr) + OR A + JP Z,ShoLn1 ;no string? + LD A,(FGlobl) ;global replace? + OR A + JR Z,RplcGo + LD A,(FBackw) ;backward? + OR A + JR Z,RplTop + CALL Bottom ;goto end + JR RplcGo +RplTop: CALL Top ;goto start +RplcGo: LD A,(MacFlg) + PUSH AF ;(got to do this before Chg Input) + CALL ChgSub + POP AF + OR A + CALL NZ,Global ;within Macro: force Global + CALL RepFCh ;do first one + JR C,RplLpQ ;none found? +RplLp: CALL Keybd + CP ESC ;abort? + JR Z,RplLpX + XOR A + LD (FGlobl),A ;turn off global + CALL RepFCh + JR NC,RplLp +RplLpX: LD A,(EdErr) + CP 4 ;suppress "not found" error + CALL Z,Error0 +RplLpQ: CALL XLoud ;turn CONOut back on + JP SetAl +; +;Repeat last find/replace +; +Repeat: LD A,0FFH + LD (YNFlg),A + CALL RepFCh + LD A,(YNFlg) + OR A + JR Z,RplLp + RET +; +RepFCh: CALL RpFind ;[entry from Replace] + LD A,(EdErr) ;return Carry if not found or error + OR A + SCF + RET NZ ;not found + LD A,(ChgFlg) + OR A + RET Z ;find only, all done + CALL ShoAll ;replace, gotta show it + CALL YesNo ;..and ask + JR C,RepFC0 + JR Z,RepFC1 + LD A,(FBackw) ;NC,NZ = No + OR A + LD A,(FndStr) + CALL Z,GoRtA ;skip ahead + OR A + RET +RepFC0: RET NZ ;C,NZ means Esc: abort +RepFC1: CALL RepChg ;Z (C or NC) means Yes + LD A,(EdErr) + CP 1 ;error? set carry + CCF + RET +; +YesNo: LD A,(YNFlg) ;return C=abort, Z=yes + OR A + SCF + RET Z ;"*" mode? Z,C = yes,global + CALL Loud ;MUST see this +YesNo1: LD DE,DspEsc ;entry for hyphenation Y/N + CALL GoTo + CALL MakAlt + LD HL,YNMsg ;say "Y/N/*" + LD B,4 + CALL BHLMsg + CALL UnAlt + CALL Cursr + CALL KeyIn ;MUST come from keyboard + PUSH AF + LD DE,DspEsc ;clean up + CALL GoTo + LD A,(NoHdrF) + OR A + CALL Z,MakAlt + LD B,4 + CALL BBlank + CALL UnAlt + POP AF + CP ESC ;abort? + JR NZ,YN1 + OR A + SCF ;C, NZ = yes + RET +YN1: CP '*' + JR NZ,YN2 +Global: CALL XQuiet + XOR A + LD (YNFlg),A ;set global flag + SCF + RET ;Z,C = yes,globally +YN2: AND 5FH ; upper case + CP 'Y' + RET Z ;Z,NC = yes,once + CP 'N' + JR NZ,YesNo1 + OR A + RET ;NZ,NC = no +; +; +;Variable Tabs. +;"VTList" is a list of settings, increasing order, zero fill +; +VTTog: LD HL,VTFlg ;toggle variable on/off + CALL ToggHL + CALL RulFix +VTshow: LD A,(VTFlg) ;requires header display + OR A + LD HL,VTon + JR NZ,VTsho1 + LD HL,TogOff +VTsho1: LD DE,DspTab + JP TogSho +; +; +VarTab: CALL ColCnt ;advance to next VT setting + LD B,VTNum + LD HL,VTList +VTlp1: CP (HL) ;find it + JR C,VTb2 + INC HL + DJNZ VTlp1 + RET ;none, no action. +VTb2: LD A,(HL) + PUSH HL + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl ;may need to scroll + POP HL + LD A,(InsFlg) + OR A ;is insert on? + LD A,(HL) ;column to move to + JP Z,MvCol + JP MvColI ;move by inserting spaces +; +TaBack: CALL ColCnt ;retreat to last tab setting + DEC B + RET Z + LD A,(VTFlg) + OR A + JR Z,BThard + LD C,B + XOR A + LD B,VTNum + LD HL,VTList+VTNum-1 +BTlp1: CP (HL) ;skip 0s + JR NZ,BTb1 + DEC HL + DJNZ BTlp1 + RET ;no tabs at all, no action +BTb1: LD A,C +BTlp2: CP (HL) ;find it + JR NC,BTb2 + DEC HL + DJNZ BTlp2 + JP QuikLf ;no more left, go to col 1 +BTb2: LD A,(HL) ;that's it + JR BTabX +BThard: LD A,(TabCnt) ;back to last multiple + CPL + DEC B + AND B + INC A +BTabX: PUSH AF + CALL QuikLf ;go all the way back + POP AF + JP MvCol ;then go there +; +; +VTSet: LD HL,ColQ ;Set tab(s) + CALL Prompt + CALL GetStr + DW 0 + LD A,(CurCol) ;default is Here + JR Z,VTSt01 ;nothing entered? + LD HL,DMA + LD A,(HL) + CP '@' + JR Z,VTSInt ;interval specified? + CP '#' + JR Z,VTSGrp ;group? + EX DE,HL + CALL GetNN ;nope, single tab set + JR Z,VTErr +VTSt01: CALL VTStCl + JR C,VTErr + JR VTStX +VTStCl: LD E,A ;[sbr: set VT here] + LD A,(VTList+VTNum-1) + OR A + SCF + RET NZ ;must be room in list + LD BC,VTNum + LD HL,VTList +VTSlp1: LD A,(HL) ;find it + OR A + JR Z,VTSt1 + CP E + RET Z ;(quit if already set) + JR NC,VTSt2 + INC HL + DEC C + JR NZ,VTSlp1 + DEC HL ;last place +VTSt1: LD (HL),E ;add at end + OR A + RET +VTSt2: LD A,E + LD HL,VTList+VTNum-2 ;make room here + LD DE,VTList+VTNum-1 + DEC BC + LDDR + LD (DE),A ;put it in + OR A + RET +VTErr: JP Error7 +; +VTSInt: LD DE,VTList ;"@" interval specified + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL + INC DE + CALL GetNN + OR A + JR Z,VTStX + LD C,A + INC A ;"@n" means n+1, 2n+1 etc + LD DE,VTList + LD B,VTNum +VTSlp2: LD (DE),A + INC DE + ADD A,C + JR C,VTStX + DJNZ VTSlp2 + JR VTStX +VTSGrp: LD DE,VTList ;'#' group specivied + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL +VTGlp: INC DE + CALL GetNN ;get one from list + OR A + PUSH DE + CALL NZ,VTStCl ;set it? + POP DE + JR C,VTErr + LD A,(DE) + OR A + JR NZ,VTGlp +VTClX: +VTStX: CALL ShoLn1 ;all done + JP RulFix +; +; +VTClr: LD HL,ColQ ;clear a tab + CALL Prompt + LD A,(CurCol) ;default is Here + CALL GetNum + JR C,VTErr + JR Z,VTErr + LD B,VTNum + LD HL,VTList +VTClp1: CP (HL) ;find it + JR Z,VTCl2 + INC HL + DJNZ VTClp1 + JR VTErr ;wasn't set +VTCl2: LD (HL),0 + DEC B + JR Z,VTClX ;was last, all done + LD D,H + LD E,L + INC HL + LD C,B + LD B,0 + LDIR ;delete it + XOR A + LD (DE),A ;zero fill + JR VTClX +; +; +; INSERTION FUNCTIONS +; +;Store a ctl-code in text +; +CtlP: LD HL,CPTog ;say "^P-_", get key + CALL Prefix + CALL XCase + CP DEL + JR Z,CtlP1 + CP ' ' ;error if not now ctl-char + RET Z ;(space cancels) + JP NC,Error2 ;invalid key +CtlP1: LD HL,BlkChr + CP (HL) ;don't allow block char + JP Z,Error2 ;invalid key + CP TAB ;tabs are special + JR Z,ITab + CP CR ;so are CRs + JP Z,ICRB1 + JR Sk2IC +; +IChar: CP ' ' ;Main menu entry: no control codes allowed + RET C +Sk2IC: PUSH AF + CALL ChkLM ;Check for left margin + JR NC,Sk2aIC + CALL UpToLM + CALL SetCu +Sk2aIC: POP AF + LD E,A + CP 7FH ;redo line if DEL/ctl + CCF + JR C,Sk3IC + CP ' ' +Sk3IC: CALL C,SetRCu + PUSH DE + CALL NC,XPutCh ;just show nice chars + POP DE + PUSH DE + LD A,E + CALL Insrt ;Put byte in + POP DE + RET C ;Full? + PUSH DE + LD A,(Horiz) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if at edge + CALL IncH ;Move cursor + CALL ChkIns ;adjust for insert mode + POP DE + LD A,E + CP ' ' + RET Z ;if not space + CP EOF + RET Z + LD HL,BlkChr + CP (HL) + RET Z + JP WdWrap ;check wordwrap +; +TabKey: LD A,(VTFlg) + OR A + JP NZ,VarTab ;maybe variable tabbing +ITab: LD A,TAB + CALL Insrt + RET C + CALL SetCu + CALL ChkIns + LD A,(Horiz) + LD HL,TabCnt + ADD A,(HL) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if needed + JP TabH +; +;Do a carriage return +; +ICR: LD A,(DSFlg) + OR A + CALL NZ,ICR1 +ICR1: LD A,(InsFlg) + BIT 7,A ;Is insert flag on? + JR NZ,ICRB1 + CALL QuikRt ;noo... + LD A,(FMode) + CP 'N' + JR Z,ICR01 +ICR00: CALL FetchB ; in Document: make HCR + CP ' ' + JR NZ,ICR01 + CALL Delete + JR ICR00 +ICR01: CALL Cursr ;may need to show new HCR + CALL NdCnt ;Are we at end? + JR C,ICRB1 ;Yes, add a new line + CALL IfScl ;no, just move cursor + CALL Right + JP ChkAI +ICRB: CALL ICRB1 +ICRB0: LD A,(DSFlg) + OR A + RET Z + CALL InsSpc ;doublespace? add soft CRLF +ICRB1: XOR A + LD (NumTab),A + CALL IfScl + LD A,CR + CALL Insrt ;Put it in + RET C + LD A,(Vert) + LD HL,TxtLns + CP (HL) + CALL Z,ScrlU2 ;end of screen? scroll + CALL SetDn + CALL IncV ;Move cursor down + CALL LftH ;Move to start of line + JR ChkAI +ICRA: CALL ICRA1 + LD A,(DSFlg) + OR A + RET Z + LD A,' ' ;doublespace? add soft CRLF + CALL InsrtA +ICRA1: LD A,CR ;Used as ^N routine only + CALL InsrtA + RET C + CALL FetchB + CP CR + JR NZ,ICRAx + LD HL,InsL + CALL ScrUDx + RET NC +ICRAx: JP SetDn +; +; +;Check for insert mode +; +ChkIns: LD A,(InsFlg) + OR A ;INSERT on? + JP NZ,SetRCu ;Yes, all done + LD HL,(BefCu) + LD A,(HL) + CP EOF + JP Z,SetRCu + LD HL,BlkChr + CP (HL) + JP Z,SetRCu + LD HL,(AftCu) ;No, Look at the character + LD A,CR + CP (HL) ;Is it a CR? + RET Z ;Yes, leave it + LD A,TAB + CP (HL) ;TAB? redo line + CALL Z,SetCu + LD A,(ShoFlg) + PUSH AF + CALL EChar ;overwrite character + POP AF + LD (ShoFlg),A + RET +; +;Check for auto indent mode +; +ChkAI: LD A,(AIFlg) ;AI on? + OR A + RET Z + LD A,(DSFlg) + OR A + RET NZ ;done if doublespacing + CALL NdCnt ;add text at cmd? + JR C,ChkAll + LD A,(InsFlg) ;insert on? + OR A + JR Z,ChkALp +ChkAll: CALL QuikLf ;#inline version of IndPL + CALL BgCnt ;# / + RET C ;# / + CALL Up ;#/ + CALL CntSpc ;get indentation + PUSH BC ;back to this line + CALL QuikRt ;#inline version of IndNL + CALL Right ;#these are just like RfmNL/PL, + POP BC ;#except they DON'T skip over blank lines + LD A,B + CP TAB + LD A,(NumTab) + JR Z,ChkAtb + INC A + JP MvColI ;do it +ChkALp: CALL Fetch ;NO, just move to first nonspace + CP ' ' + JR Z,ChkAI1 + CP TAB + RET NZ +ChkAI1: CALL Right + JR ChkALp +ChkAtb: OR A + RET Z + DEC A + PUSH AF + CALL ITab + POP AF + JR ChkAtb +; +; +; DELETION FUNCTIONS +; +;UNdelete a character +; +Undel: CALL GpCnt ;Anything to undelete? + RET C + CALL ELret2 + LD HL,(AftCu) + DEC HL ;here goes + LD (AftCu),HL + LD A,(HL) + CP CR ;was it a CR? + JP Z,SetDn + JP SetRCu +; +UndlLn: CALL GpCnt ;Do a whole line + RET C + CALL ELret2 + LD A,B + OR A ;max 256 chars + JR Z,UdLn1 + LD BC,256 +UdLn1: LD HL,(AftCu) + DEC HL + DEC HL + LD A,CR + CPDR ;look for CR + RET NZ + INC HL + INC HL ;start of line + LD (AftCu),HL + JP SetDn +; +; +;Erase character to left of cursor (C=error) +; +Delete: CALL Left + RET C ;Fall through to EChar +; +; +;Erase character to right of cursor (C=error) +; +EChar: CALL NdCnt ;Anything to erase? + RET C + CALL ELret2 + CALL SetRCu + LD HL,(AftCu) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1EC + CALL GpShft ;unhide it + LD HL,(AftCu) + LD A,(HL) + LD (HL),' ' + AND 7FH + DEC HL + LD (HL),A + RET +Sk1EC: LD A,(HL) + INC HL ;Move up, past character + LD (AftCu),HL ;Store updated value + CP CR + CALL Z,SetDn ;ate a CR? + OR A + RET +; +GpShft: CALL GpCnt ;Shift gap contents left (for Undel sake) + RET C + DEC BC + LD A,B + OR C + SCF + RET Z + LD HL,(BefCu) + INC HL + LD A,B + SUB 08H ;Maximum 2k worth + JR C,GpS1 + LD B,08H + ADD A,H + LD H,A +GpS1: LD D,H + LD E,L + INC HL + LDIR + OR A + RET +GpCR: CALL GpShft ;mark BOL for ^QU + RET C + LD A,CR + LD (DE),A + RET +; +; +;Line erase functions +; +Eline: LD HL,(AftCu) ;first left end + PUSH HL + CALL QuikLf + POP HL + LD (AftCu),HL + LD E,1 ;now right end + CALL CrRit + JR NC,Eline1 ;found CR? good + JR NZ,Eline2 ;EOF? return + LD HL,(EndTx) ;Cursor is in last line + INC HL +Eline1: LD (AftCu),HL +Eline2: CALL ELret2 + LD HL,DelL + CALL ScrUDx + JP C,SetDn + LD A,(TxtLns) + LD B,A + JP ShoLn +; +EOLine: LD E,1 ;Erase to EOL + CALL CrRit + JR NC,Sk1EO ;Found CR? good + RET NZ ;EOF? return + LD HL,(EndTx) ;cursor is in last line + LD A,(HL) + CP CR ;Is last byte a CR? + INC HL + JR NZ,Sk2EO ;No +Sk1EO: DEC HL ;Point at trailing CR +Sk2EO: PUSH HL + JR EBLret ;delete to there +; +EBLine: LD HL,(AftCu) ;Erase to BOL + PUSH HL + CALL QuikLf +EBLret: CALL GpCR ;delete to there + POP HL + CALL SetRCu +ELret: LD (AftCu),HL +ELret2: LD A,0FFh + LD (Modify),A + RET +; +E2Char: LD HL,CQTTog ;Erase to character + CALL Prefix + CP ESC + RET Z + CP 'U'-40h ;^U? + RET Z + LD (PrevCh),A +E2CLp: CALL EChar ;always eat first char + CALL NdCnt + RET C + CALL Keybd + CP ESC + RET Z + CALL Fetch + LD HL,PrevCh + CP (HL) + JR Z,E2CLpF + LD (PrvCh2),A + JR E2CLp +E2CLpF: CP CR + RET NZ + LD A,(FMode) + CP 'N' + RET Z + LD HL,PrvCh2 ;CR means HARD CR in Doc modes + LD A,(HL) + CP ' ' + RET NZ + LD (HL),CR + JR E2CLp +; +; +; BLOCK FUNCTIONS +; +;MARK Block start and termination +; +Block: CALL UnBlAb ;Remove any markers above + CALL UnBlB1 ;Remove all but last marker below +Blk01: LD A,(BlkChr) ;mark it now + JP Sk2IC +; +Termin: CALL UnBlA1 ;Remove all but first marker above + CALL UnBlBl ;Remove any markers below + JR Blk01 +; +Unmark: CALL UnBlAb ;Remove all block markers + CALL UnBlBl + RET +; +;Move cursor to block start +; +QikBlk: CALL IsBlk + EX DE,HL + INC HL + BIT 0,A + JP Z,Error7 ;must be marked + BIT 6,A + JR NZ,QikB1 +QikB0: CALL MoveL ;before cursor (entries from QuikMk) + JR QikB2 +QikB1: DEC HL ;after cursor + CALL MoveR +QikB2: CALL CountS ;Adjust count + CALL RitH ;Adjust cursor + CALL MidV + JP SetAl +; +;Basic query returns: +; A= {bit 7=gap in block; 6=start after gap; 1=block marked; 0=start marked} +; DE,HL= start, end (if marked) +; +IsBlk: LD IX,IsBVal + LD (IX),0 ;result byte + CALL BgCnt + JR C,IsB1 + LD A,(BlkChr) ;look before cursor + CPIR + JR NZ,IsB1 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + JP PO,IsB0 + CPIR + JR NZ,IsB0 + SET 1,(IX) ;found end + DEC HL +IsB5: LD A,(IX) ;exit + RET +IsB0: SET 7,(IX) ;straddle + JR IsB1a +IsB1: SET 6,(IX) ;block after cursor +IsB1a: CALL NdCnt ;now look after cursor + JR C,IsB5 + LD HL,(AftCu) +IsB3: LD A,(BlkChr) ;search loop + CPIR + JR NZ,IsB5 + BIT 0,(IX) + JR NZ,IsB2 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + LD A,B + OR C + JR Z,IsB5 + JR IsB3 +IsB2: SET 1,(IX) ;found end + DEC HL + JR IsB5 +; +; +UnBlA1: CALL BgCnt ;undo all but 1st marker above + RET C + LD A,(BlkChr) + CPIR + JP PE,UnBA01 ;one? leave and look for more + RET ;no more, finished +UnBlAb: CALL BgCnt ;undo all markers above + RET C +UnBA01: LD A,(BlkChr) + CPIR + RET NZ ;none, finished + CALL SetAl + PUSH BC + PUSH HL + LD D,H + LD E,L + DEC DE + CALL LCnt + JR C,UnBA02 + LDIR ;remove it +UnBA02: DEC DE + LD (BefCu),DE + POP HL + DEC HL + POP BC + LD A,B + OR C + JR NZ,UnBA01 + RET +; +UnBlB1: CALL NdCnt ;undo all but 1st marker below + RET C + LD HL,(EndTx) + LD A,(BlkChr) + CPDR + JP PE,UnBB01 ;one, leave and continue + RET ;none, finished +UnBlBl: CALL NdCnt ;undo all markers below + RET C + LD HL,(EndTx) +UnBB01: LD A,(BlkChr) + CPDR + RET NZ ;none, finished + CALL SetDn + PUSH BC + PUSH HL + LD D,H + LD E,L + INC DE + CALL RCnt + JR C,UnBB02 + LDDR ;remove it +UnBB02: INC DE + LD (AftCu),DE + POP HL + INC HL + POP BC + LD A,B + OR C + JR NZ,UnBB01 + RET +; +;Erase Block +; +EBlock: CALL IsBlk + BIT 1,A ;must be marked + JP Z,Error7 + BIT 7,A + JR NZ,EPrt3 ;straddles cursor? + BIT 6,A ;is it after cursor? + JR NZ,EPrt2 + LD B,H ;no, before cursor + LD C,L + LD HL,(BefCu) + SBC HL,BC ;bytes to move + PUSH HL + LD H,B + LD L,C + POP BC + JR Z,EPrt1a + INC HL + LDIR +EPrt1a: DEC DE + LD (BefCu),DE + JR EPrtRt +EPrt2: EX DE,HL ;it's after cursor + LD BC,(AftCu) + PUSH HL + SBC HL,BC + LD B,H + LD C,L + POP HL + JR Z,EPrt2a + DEC HL + LDDR +EPrt2a: INC DE + LD (AftCu),DE + JR EPrtRt +EPrt3: DEC DE ;cursor straddles it + LD (BefCu),DE + INC HL + LD (AftCu),HL +EPrtRt: CALL RitH ;Adjust cursor + CALL CountS + CALL ELret2 + JP SetAl +; +;Block Copy +; +Copy: CALL IsBlk + AND 82H ;must be marked, not straddled + CP 2 ;(bit 1 set, 7 clear) + JP NZ,Error7 + CALL CmpLng ;compute length + RET Z ;was empty + CALL CpSafe + JR NC,Copy02 ;okay, go do it + CALL Cmprs ;try to get more room + CALL IsBlk + CALL CmpLng ;compute length now + CALL CpSafe ;well? + JP C,Error1 ;REALLY won't fit +Copy02: LDDR + INC DE + LD (AftCu),DE + CALL RitH ;adjust cursor + CALL CountS + CALL ELret2 + JP SetDn +; +CmpLng: DEC HL + INC DE + PUSH HL + INC HL + SBC HL,DE ;compute length now + LD B,H + LD C,L + POP HL + LD DE,(AftCu) + DEC DE + RET +; +CpSafe: PUSH HL ;Set C if BC bigger than gap + PUSH BC + CALL GpCnt + LD H,B + LD L,C + POP BC + SCF ;(just to be safe) + SBC HL,BC + POP HL + RET +; +;Block Move +; +MovBlk: CALL Copy ;first copy + LD A,(EdErr) + OR A + RET NZ + JP EBlock ;then delete +; +; +; DISK FUNCTIONS +; +;View Directory +; +Dir: LD HL,DirQ + CALL Prompt + LD A,8+1 ;ask for Duu: or NDR name (8 chars max) + CALL GSEnt + DW 0 + PUSH AF + LD A,(FCB) ;defaults + LD B,A + LD A,(FCBU) + LD C,A + POP AF + JR Z,Dir00 + LD B,A + LD HL,DMA +DirULp: LD A,(HL) + CALL UCase ;new D (?) + LD (HL),A + INC HL + DJNZ DirULp + CP ':' + JR NZ,Dir0x ;jump if not a ":" + DEC HL + LD (HL),0 +Dir0x: LD DE,DMA + CALL NdrChk + JR NZ,Dir00 ;is an NDR name + LD A,(DE) ;new D (?) + CP '0' + JP C,Error7 ;<'0', not even a user # + CP '9'+1 + JR C,Dir0 ;jump is just a user # + SUB 'A'-1 + CP 17 ;drive letter > 'P'? + JP NC,Error7 ;yep.. a no no + LD B,A + INC DE +Dir0: PUSH BC + CALL GetNN ;new uu + POP BC + JR NC,Dir0a + LD A,(FCBU) ; fetch user # + JR Dir0y +Dir0a: CP 32 ;0-31 ok + JP NC,Error7 +Dir0y: LD C,A +Dir00: PUSH BC + LD E,C + LD C,USRN + CALL BDOSep ;set user + POP BC + LD HL,FCBBuf + LD (HL),B ;and drive + INC HL + LD (HL),'?' ;set up *.* FCB + LD DE,FCBBuf+2 + LD BC,10+1 + LDIR ; wildcard filename, type and extent + LD (HL),0 + LD BC,19 + LDIR ; zero out S1, S2, RC and alloc. map + CALL MakAlt + LD DE,010Fh ;position to col 2 + LD A,(RulFlg) + OR A + JR Z,Dir1 + INC D ;move down a line to preserve the ruler +Dir1: CALL GoTo + LD A,(View) ;initialize + SUB 14 + LD (HPos),A + LD A,(TxtLns) ;lines free on screen + DEC A + LD (DirLns),A + LD A,(View) ;columns free + LD HL,DirCls + LD (HL),A + XOR A + RRD ;cols=view/16 + LD C,(HL) + DEC C + PUSH BC + LD DE,FCBBuf ;first file? + LD C,SRCH + CALL BDOS ; search for first matching file + POP BC + CP 0FFH + JR NZ,Sk1Dir + CALL DsplC + DB 'N','o'+X,'File',CR,0 + JP Sk3Dir +; +Lp3Dir: PUSH BC + LD DE,FCBBuf ;next one... + LD C,SRCN + CALL BDOS ; search for next matching file + POP BC + CP 0FFH + JP Z,DirEnd ;all done? +Sk1Dir: ADD A,A + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;desired FCB is at 32*A + DMA + LD E,A + LD D,0 + LD HL,DMA + ADD HL,DE + INC HL ;point to filename + EX DE,HL + LD HL,9 + ADD HL,DE ;test SYS attribute + BIT 7,(HL) + JR Z,Sk2Dir + LD A,(DirSys) ;yes, include? + OR A + JR Z,Lp3Dir ;no +Sk2Dir: EX DE,HL + PUSH HL + LD B,11 +Lp4Dir: RES 7,(HL) ;strip flags + INC HL + DJNZ Lp4Dir + LD DE,4 + ADD HL,DE + LD (HL),0 ;terminator + DEC HL + LD A,' ' ;separator + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD D,H + LD E,L + DEC HL + LD A,C ;save DirCls + LD BC,3 ;move TYP + LDDR + EX DE,HL + LD (HL),'.' ;punctuate + POP HL + LD C,A ;save DirCls + PUSH BC + CALL DspLp ;SHOW IT + POP BC + DEC C + JR NZ,Lp3Dir ;finish line? + LD HL,DirLns + DEC (HL) + JR Z,DirFul ;out of room? + LD A,CR + CALL DsByt ;okay, new line + LD A,(DirCls) + LD C,A + JR Lp3Dir +; +DirFul: CALL DsplC ;ran out of lines + DB '...',CR,0 + JR Sk3Dir +DirEnd: LD A,C ;done, need CR? + LD HL,DirCls + CP (HL) + JR Z,Sk3Dir + LD A,CR + CALL DsByt +Sk3Dir: CALL UnAlt + CALL IfSpLn + LD A,(FCBU) + LD E,A + LD C,USRN ;reset user + CALL BDOSep + CALL SetAl + JP ESCLp ;wait for ESC to clear +; +;Load a new file. +; +Load: LD A,(Modify) + OR A + JR Z,LoadY + LD HL,QuitQ ;warn if old file was changed + CALL Prompt + CALL Confrm + JP NZ,ShoLn1 +LoadY: JP Restrt ;go do it +; +;Erase a disk file. +; +Era: CALL SavNam ;save old FCB + LD HL,EraQ + CALL NewNam + LD A,(EdErr) + OR A + JR NZ,EraDon + CALL ZeroS1 + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD C,FDEL + CALL BDOSfc + INC A + CALL Z,Error7 +EraDon: CALL GetNam ;restore FCB + JP ShoLn1 +; +; +;Read text from disk file to cursor location. +; +Read: CALL SavNam ;save old FCB + LD HL,ReadQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,RdDone +; +LoadIt: CALL IOon ;say wait + CALL Cmprs ;need all our room + CALL GpCnt + JR C,Sk1Rd ;No room? + LD HL,(BefCu) ;Start here + CALL MSIn ;Read it in + JR NZ,Sk2Rd ;Worked? +Sk1Rd: CALL Error1 ;no, out of room + JR RdDone +Sk2Rd: JR NC,Sk3Rd ;Okay? + CALL Error3 ;no, I/O error + JR RdDone +Sk3Rd: LD DE,(BefCu) ;Get old BefCu + LD (BefCu),HL ;Set new one + EX DE,HL + INC HL ;Point at first byte loaded + CALL MoveL ;Move the cursor +RdDone: CALL GetNam ;restore FCB + CALL IOoff + CALL ELret2 + JP SetAl +; +; +;Write the whole file out to disk. +; +Save: LD A,(FCB+1) ;must have filename + CP ' ' + JR NZ,Save00 + CALL ChgNam + LD A,(EdErr) + OR A + RET NZ +Save00: LD A,(Modify) + OR A + JR NZ,Save01 + LD HL,UnchgQ ;hey, no changes! + CALL Prompt + CALL Confrm + PUSH AF + CALL ShoLn1 + POP AF + RET NZ +Save01: CALL IOon ;say wait + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL NdCnt ;count number of bytes + JR NC,Save02 + LD BC,0 +Save02: LD HL,(AftCu) ;point at first byte + CALL MSOut ;write it out + JR NC,Save03 + CALL Error3 ;I/O error + JR Save04 +Save03: XOR A + LD (Modify),A ;clean slate +Save04: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + JP IOoff +; +; +;Write block text to a disk file. +; +Write: CALL SavNam ;save orig FCB + LD HL,WritQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,WrXit + CALL IOon ;say wait + LD HL,(AftCu) ;save position + LD (LastCu),HL + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL IsBlk + BIT 1,A ;must be marked + JR Z,WrOops + INC DE ;point to it + SBC HL,DE ;size of block + EX DE,HL + LD B,D + LD C,E + CALL MSOut + JR NC,WrDone +WrOops: CALL Error7 +WrDone: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + CALL IOoff +WrXit: CALL GetNam ;restore orig FCB + JP ShoLn1 +; +; +SavNam: LD HL,FCB ;Preserve main filename + LD DE,FCBBuf + LD BC,12 + LDIR ; copy drive, file name and type + XOR A + LD (FCBd0),A + LD A,(FCBU) ;and user, W/A, FilFlg + LD (DE),A ; set user number in FCBBuf+13 + INC DE + LD A,(FMode) + LD (DE),A ; set S1 + INC DE + LD A,(FilFlg) + LD (DE),A ; set S2 + RET +GetNam: LD HL,FCBBuf ;And restore them + LD DE,FCB + LD BC,12 + LDIR + XOR A + LD (FCBd0),A + LD A,(HL) + LD (FCBU),A + LD E,A + INC HL + LD A,(HL) + LD (FMode),A + INC HL + LD A,(HL) + LD (FilFlg),A + LD C,USRN + JP BDOSep +; +; +;Accept a new file name to be used for disk i/o. +; +ChgNam: CALL SavNam + LD HL,NameQ + CALL NewNam + LD A,(EdErr) + OR A + CALL NZ,GetNam ;bad? restore + CALL DfltM ;may have changed modes + CALL DoHdr + CALL ELret2 + JP ShoLn1 +; +NewNam: CALL Prompt ;subroutine entry + LD A,24+1 + CALL GSEnt ;Ask for input + DW FNamBf + JP Z,Error7 ;Error if no input + LD B,A + PUSH BC + LD HL,DMA ;uppercase it +NNUlp: LD A,(HL) + CALL UCase + LD (HL),A + INC HL + DJNZ NNUlp + POP BC ;restore length + LD HL,DMA + LD A,(HL) + CP '/' ;watch for mode only + JR NZ,NNMod + INC HL + CP (HL) ;second '/' + DEC HL + JR NZ,NNMod2 +NNMod: LD A,B + CALL Parse ;parse DU:FN.T /O + JP C,Error7 ;check bad entry + XOR A + LD (FilFlg),A ;kill fileflg + RET +NNMod2: INC HL + LD A,(HL) ;do mode only + CP 'W' ;WordStar + JR Z,NNMdOK + CP 'A' ;ASCII + JR Z,NNMdOK + CP 'N' ;non document + JP NZ,Error7 +NNMdOK: LD (FMode),A + RET +; +DfltM: LD HL,0101H + LD (LMSav),HL ;margins set + LD A,(FMode) ;doc or nondoc mode? + CP 'N' + JR Z,Dflt2 + XOR A + LD (AIFlg),A + DEC A + LD (VTFlg),A + LD A,(HCDflt) + LD (HCRFlg),A ;HCR display? + LD A,(RtMarg) ;If RM set, avoid wierd WW/AI conflict + DEC A + JR NZ,DfltX + LD HL,(DfltLM) ;from NONdoc: reset margins + LD (LfMarg),HL +DfltX: LD A,';' ;punctation chars: , ; : - . ? ! + JR DfltX2 +Dflt2: LD HL,0101H ;NONdocument mode + LD (LfMarg),HL + XOR A + LD (VTFlg),A ;varitabs off + LD (HCRFlg),A ;HCR display off + DEC A + LD (AIFlg),A ;auto indent ON + LD A,':' ;punctation chars: , : - . ? ! (NOT ;) +DfltX2: LD (PunTbl+1),A + JP RulFix +; +; +;Toggle case of character at cursor +; +UpLow: CALL Fetch ;also points to byte with (HL) + AND 5FH ;strip off both hidden space and case + CP 'A' + JR C,UpLo1 ;leave alone if not letter + CP 'Z'+1 + JR NC,UpLo1 + BIT 5,(HL) ;toggle case + RES 5,(HL) + JR NZ,UpLo0 ;was lower, now up + SET 5,(HL) ;was upper, now low +UpLo0: CALL ELret2 +UpLo1: CALL Right ;move right for next(?) + JP SetRCu +; +; +;Set page length +; +PgSet: LD HL,PgLnQ + CALL Prompt + LD A,(FormL) ;default value + CALL GetNum + JP C,Error7 + LD (PgLen),A + CALL DoHdr + JP ShoLn1 +; +; +;VARIOUS TOGGLES +; +;Simple on/off toggles +; +HCRTog: CALL SetAl ;HCR display + LD HL,HCRFlg +ToggHL: LD A,(HL) + CPL + LD (HL),A + RET +; +;These require header display +; +HypTog: LD HL,HypFlg ;hyphenation + CALL ToggHL +HYshow: LD HL,HYon + LD A,(FMode) + CP 'N' ;irrelevant in N mode + JR Z,HYsho0 + LD A,(HypFlg) + OR A + JR NZ,HYsho1 +HYsho0: LD HL,TogOff +HYsho1: LD DE,DspHyp + JP TogSho +; +IToggl: LD HL,InsFlg ;INSERT + CALL ToggHL +ITshow: LD A,(InsFlg) + LD HL,MacFlg + BIT 7,(HL) + JR Z,ITsho0 + LD A,(SavIns) +ITsho0: OR A + LD HL,INSon + JR NZ,ITsho1 + LD HL,TogOff +ITsho1: LD DE,DspIns + JP TogSho +; +DblTog: LD HL,DSFlg ;double spacing + CALL ToggHL + OR A + CALL NZ,AIoff ;turn off auto ident if double spacing +DblSho: LD A,(DSFlg) + OR A + LD HL,DSon + JR NZ,DSsho1 + LD HL,TogOff +DSsho1: LD DE,DspSpc + JP TogSho +; +AIoff: LD HL,AIFlg + INC (HL) + DEC (HL) + RET Z ;fall thru to turn off auto indent if it's on +; +AITog: LD HL,AIFlg ;auto indentation + CALL ToggHL + OR A + JR Z,AIshow + LD HL,DSFlg ;is double spacing on? + INC (HL) + DEC (HL) + CALL NZ,ToggHL ;turn it off if so + CALL NZ,DblSho ;turn off the old DS display + LD A,1 + CALL SLM1 ;reset left margin to 1 +AIshow: LD A,(AIFlg) + OR A + LD HL,AIon + JR NZ,AIsho1 + LD HL,TogOff +AIsho1: LD DE,DspInd + JP TogSho +; +PSTog: LD A,(PSokFl) + OR A + JP Z,Error2 ;invalid key + LD HL,PSFlg + CALL ToggHL + LD A,(RMSav) + DEC A + RET NZ ;margins released? then we're done +PSDisp: LD A,(FMode) + CP 'N' + JR Z,PSTogU ;no PS in nondocument mode + LD A,(PSFlg) + OR A + LD HL,PSon ;proportional spacing on + JR NZ,PSTogX +PSTogU: LD HL,TogOff ;turn off margin release +PSTogX: LD DE,DspMrg + JP TogSho +; +; +;TEXT FORMAT functions +; +SetRM: CALL StMrCm ;Same for left and right + LD C,A + LD A,(LfMarg) + CP C + JR C,SRM1 ;inside LM? + LD A,1 + LD (LfMarg),A ;if so, reset LM +SRM1: LD A,C + LD (RtMarg),A + JR StMgEn +; +SetLM: CALL StMrCm ;Same for left and right + LD HL,RtMarg + CP (HL) + JR NC,MrgErr +SLM1: LD (LfMarg),A + DEC A + CALL NZ,AIoff +StMgEn: CALL RulFix + JP ShoLn1 +; +StMrCm: LD A,(FMode) ;Set right margin + CP 'N' ;(must be Document mode) + JR Z,MrgErr + LD A,(RMSav) ;okay, do it + DEC A + CALL NZ,RelM ;(undo Margin Release) + LD HL,ColQ + CALL Prompt + LD A,(CurCol) ;default: cursor column + CALL GetNum + JR Z,MrgErr + RET NC +MrgErr: POP HL + JP Error7 +; +RelM: CALL RelLM ;release both margins (Toggle) + LD HL,RtMarg + LD DE,RMSav + CALL RelSb + CALL MRshow + JP RulFix +; +RelLM: LD HL,LfMarg ;SBR: release left only + LD DE,LMSav +RelSb: LD A,(HL) ;common subroutine + CP 1 + JR Z,Rel1 + LD (DE),A ;note: if RMSav>1, margins released + LD (HL),1 + RET +Rel1: LD A,(DE) + LD (HL),A + LD A,1 + LD (DE),A + RET +; +;Check the right margin +; +ChkRM: LD A,(CurCol) ;be sure this is up to date + LD B,A + LD A,(RtMarg) + INC A + LD C,A + SUB B ;set C if over + RET NC + CALL IgnCtl ;yes, ignore ctlchars + LD A,C ;try arithmetic once again + ADD A,E + SUB B + RET ;now C set if really over +; +IgnCtl: CALL Fetch ;count ctlchars to be ignored + LD E,0 ;(up to present cursor) + LD HL,(BefCu) + JR NZ,IgnC1 +IgnCLp: LD A,(HL) ;count em + DEC HL + CP CR ;quit at BOL + RET Z +IgnC1: CP TAB ;tabs don't count + JR Z,IgnCLp + CP 20H + JR NC,IgnCLp + INC E ;others do + JR IgnCLp +; +;Check left margin, space over if needed +; +ChkLM: LD A,(LfMarg) + LD B,A + LD A,(CurCol) + SUB B ;be sure this is uptodate + RET ;ret Z if at, C if over +; +UpToLM: LD A,(LfMarg) ;git on over to the LM column +; +MvCol: PUSH AF ;move to col A saving any existing text + CALL GoCol + POP AF +MvColI: LD HL,CurCol ;move to col A inserting spaces + SUB (HL) + RET C ;we're past already + RET Z ;we're there + LD B,A + CALL SetCu ;this is going to hurt +MvClp: PUSH BC ;insert B spaces + CALL InsSpc + POP BC + RET C ;quit if out of space + CALL IncH + DJNZ MvClp + RET +; +DoLM: LD A,(LfMarg) ;create whole left margin + DEC A + RET Z + LD B,A + JR MvClp +; +;Handle former margin for reformat +; +CntSpc: CALL QuikLf ;count lead spaces/tabs on line + CALL Fetch + LD B,A + EXX + XOR A +CSpLp: LD (NumTab),A + PUSH AF + CALL Fetch + CP ' ' + JR Z,CSpL1 + CP TAB + JR NZ,CSpLpF +CSpL1: EXX + CP B + EXX + JR NZ,CSpLpF + CALL Right ;move 1 char right + POP AF + INC A ;incr # tabs + JR CSpLp +CSpLpF: CALL QuikLf ;back to start + EXX +CntSpX: POP AF + RET +; +EatSpc: OR A ;eat up to A lead spaces on line + RET Z +ESpLp: PUSH AF + CALL Fetch + CP TAB + JR Z,ESpLpF + CP ' ' + JR NZ,CntSpX +ESpLpF: CALL EChar + POP AF + DEC A + JR NZ,ESpLp + RET +; +; +;Update CurCol and return it in A and B +;(NOTE: slow. When possible, LDA CurCol.) +; +ColCnt: CALL WhatC + LD (CurCol),A + RET +; +WhatC: CALL FetchB ;col 1 is spcl case + CP CR + LD A,1 + LD B,A + RET Z + LD E,1 + CALL CrLft ;start of line + LD BC,0 +; +CCLp: CALL GetNx ;get a char + CP TAB + JR NZ,CC1 + LD A,B ;tabs are special + PUSH HL + LD HL,TabCnt + OR (HL) ;round up + POP HL + LD B,A +CC1: INC B ;count char + LD A,B + CP 254 + JR Z,CC2 ;too long? return column 255 forever + XOR A + CP C + JR NZ,CCLp ;get hidden space? + PUSH BC + CALL LCnt ;compare HL to BefCu + POP BC + JR NC,CCLp ;get another, if more exist +CC2: INC B + LD A,B ;that is curcol. + RET +; +; +;Do wordwrap if needed +; +WdWrap: LD A,(RtMarg) ;WW off if RM=1 + DEC A + RET Z + LD IY,CurCol + INC (IY) ;count the char you just put in + CALL ChkRM + RET NC + LD B,0 ;past margin... +WWLp: INC B ;count moves + PUSH BC + CALL Left + DEC (IY) + POP BC + CALL FetchB + CP CR ;oh no Uncle Bill + JP Z,Error9 + CP '-' ;hyphenation + JR NZ,WW1 + LD A,(HypFlg) + OR A + JR Z,WW1 + CALL Fetch + CP ' ' + JR Z,WW1a + INC B + PUSH BC + CALL InsSpc ;tuck in a space if there isn't one + JR WW2 +WW1: CALL Fetch + CP ' ' + JR NZ,WWLp +WW1a: PUSH BC + CALL Right ;leave it if there is + INC (IY) +WW2: CALL ChkLM + JR Z,WWerr + JR C,WWerr + CALL ICRB ;break line + CALL QuikLf + CALL DoLM + POP BC + LD A,(NumTab) + ADD A,B + JP C,WWerr + DEC A ;one spc gone +GoRtA: OR A ;Go right A chars - used by wordwrap etc + RET Z + PUSH AF + CALL Right + POP AF + DEC A + JR GoRtA +; +WWerr: POP BC + JP Error9 +; +;Reform a paragraph +; +Reform: LD A,(RtMarg) ;is RM set? + DEC A + RET Z + CALL QuikLf + CALL NdCnt + JP C,RfmE10 + CALL Fetch ;empty line? + JP Z,Down + CALL XQuiet + LD A,(AIFlg) + OR A + JR NZ,RfmBg + CALL RfmNL ;figure out indentation + JR C,RfmBg + CALL CntSpc + PUSH AF + CALL RfmPL + POP AF + CALL EatSpc ;remove spaces acc. to NEXT line indent + CALL DoLM ;and add current margin +RfmBg: CALL QuikLf + CALL KyPeek ;peek for a keypress + CP ESC ;check for abort + JR NZ,RfmBg1 ;no... keep going + CALL Keybd ;eat the ESC + JP RfmEnd ;and quit +RfmBg1: CALL ColCnt ;only once per line (slow) + LD IY,CurCol + LD A,63 + LD (PScnt),A +; +RfmLp: CALL NdCnt + JP C,RfmE10 ;check for EOF + CALL Fetch + JP Z,Rfm7 ;and EOL + CP TAB ;tabs are special + JR NZ,RfmTab + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A + JR Rfm3 +RfmTab: LD HL,PSFlg + DEC (HL) + INC (HL) + JR Z,Rfm3 + LD HL,PSTbl-32 + ADD A,L + LD L,A + LD A,0 + ADC A,H + LD H,A + LD A,(PScnt) + ADD A,(HL) + CP 63+30 + JR NC,RfmTb1 + CP 63-30+1 + JR NC,Rfm3 + ADD A,30 + JR Rfm3a +RfmTb1: ADD A,-30 + INC (IY) +Rfm3: INC (IY) ;Keep CurCol updated +Rfm3a: LD (PScnt),A + CALL Right + CALL ChkRM + JR NC,RfmLp +; +Rfm4: CALL FetchB ;just the right length? + CP ' ' + JR NZ,Rfm4a + CALL Fetch + JR Z,Rfm7 +Rfm4a: CALL Left ;oops, too long. + CALL FetchB + CP CR + JP Z,RfmErr + CALL Fetch + CP '-' + JR NZ,Rfm4b + LD A,(HypFlg) + OR A + JR Z,Rfm4b + CALL Right + CALL ColCnt ;## + CALL ChkRM ;## + JR NC,Rfm4a2 ;## + CALL Left ;## + JR Rfm4 ;## +; +Rfm4a2: CALL InsSpc + JR Rfm4c +Rfm4b: CALL IsBlnk ;break after blank + JR NZ,Rfm4 + CALL Right +Rfm4c: CALL ColCnt + CALL ChkLM ;watch out for left mgn + JP Z,RfmErr + JP C,RfmErr + CALL ICRB +Rfm5: CALL Fetch ;avoid spurious para + JR Z,Rfm6a ;(stop after CR) + CP ' ' + JR NZ,Rfm6b + CALL EChar + JR Rfm5 +Rfm6a: CALL EChar + JR RfmBg2 +Rfm6b: CALL DoLM + JR RfmBg2 +; +Rfm7: CALL FetchB ;is the CR soft or hard? + CP ' ' + JR NZ,Rfm9 ;hard, quit + CALL Left ;soft, delete any other spaces +Rfm7a: CALL FetchB + CP ' ' + JR NZ,Rfm7b + CALL Delete + JR Rfm7a +Rfm7b: CP '-' ;unhyphenate? + JR Z,Rfm20 +Rfm8: CALL Right ;and now the CR itself + CALL EChar + CALL RfmSD ;and any soft CR following + LD A,255 + CALL EatSpc ;and any leading spaces + CALL Fetch + JR NZ,Rfm8a ;hit bald CR? + CALL Delete ;yep, kill space and quit + JR Rfm9 +Rfm8a: CALL Left + CALL Left + CALL IsEndS ;(extra spc for punc) + JR NZ,RfmBg2 + CALL Right + CALL InsSpc +RfmBg2: JP RfmBg +Rfm9: CALL Right ;hard CR (check following soft?) + CALL RfmSD ;delete, if there + CALL ICRB0 ;may need to separate paras +RfmEnd: CALL XLoud + JP SetAl +RfmErr: CALL XLoud + JP Error9 +RfmE10: CALL XLoud + JP Eror10 +; +Rfm20: LD A,(HypFlg) ;unhyphenation + OR A + JR Z,Rfm8 ;not allowed, continue +Rfm21: CALL Loud + CALL ShoAll + CALL YesNo1 + PUSH AF + CALL XQuiet + POP AF + JR NC,Rfm22 + JR Z,Rfm21 ;C,Z means "*": unacceptable + JR Rfm8 ;C,NZ means ESC: don't join at all +Rfm22: CALL Z,Delete ;kill hyphen if it was "Yes" + CALL Join ;join lines (whether "Yes or No") + JR RfmBg2 +; +RfmNL: CALL QuikRt ;go to next line of text + CALL NdCnt + JR NC,RfmNL0 + CALL QuikLf ;oops, none + SCF + RET +RfmNL0: CALL Right + CALL Fetch ;(may be blank) + JR NZ,RfmNL1 ;bald CR next? also give up + CALL Up + SCF + RET +RfmNL1: CP ' ' + JR Z,RfmNL2 + CALL QuikLf ;no, fine, we're here + OR A + RET +RfmNL2: CALL Right + CALL Fetch + JR NZ,RfmNL1 ;just spaces and CR? doublespacing, + CALL Right ; go on to next line + JR RfmNL1 +RfmPL: CALL QuikLf ;return to previous line of text +RfmPL0: CALL Left + CALL FetchB ;(may be blank) + CP CR + JP Z,RfmPLx ;yes, take next + CP ' ' + JR Z,RfmPL0 + JP QuikLf ;no, fine +RfmPLx: CALL Left + JP QuikLf +; +RfmSD: CALL Fetch ;delete a soft CR if present + CP ' ' + RET NZ + CALL Right + CALL Fetch + PUSH AF + CALL Left + POP AF + RET NZ + CALL EChar + JP EChar +; +; +;Center or flush a line +; +Center: LD E,1FH ;(RRA) if Center + CP 'F'-40H + JR NZ,Ctr0 + LD E,0C9H ;(RET) if Flush +Ctr0: LD A,E + LD (Flush),A + LD A,(RtMarg) + CP 1 + RET Z ;not if no margin + CALL QuikLf ;start of line +CtrL1: CALL Fetch + JR Z,CtrXit ;end? done + CALL IsBlnk + JR NZ,CtrL1F + CALL EChar ;delete spaces + JP C,Error9 + JR CtrL1 +CtrL1F: CALL QuikRt ;end of line +CtrL2: CALL Left + CALL IsBlnk + JR NZ,CtrL2F + CALL EChar ;delete spaces + JR CtrL2 +CtrL2F: CALL ColCnt ;where are we? + CALL IgnCtl ;ignore ctlchars + LD HL,CurCol + LD A,(LfMarg) + DEC A + LD B,A + LD A,(RtMarg) + ADD A,E ;(ctlchars) + SUB B + SUB (HL) + JP C,Error9 ;error + CALL Flush + JR Z,CtrXit + PUSH AF + CALL QuikLf ;start again + CALL DoLM + POP BC +CtrL3: PUSH BC ;insert spaces to center + CALL InsSpc + POP BC + DJNZ CtrL3 +CtrXit: CALL QuikLf + CALL ShoCu + CALL QuikRt ;to next line(?) + JP Right +; +Flush: RRA ;<--- goes to RET if Flush + AND 7FH ;take half the difference for Center + RET +; +; +;Fetch character at (or before) cursor +; +Fetch: LD HL,(AftCu) + LD A,(HL) + AND 7FH ;ignore any hidden space + CP CR + RET +FetchB: LD HL,(BefCu) + LD A,(HL) + BIT 7,A + RET Z ;ordinary byte + LD A,' ' + RET ;hidden space +; +;Tests on char at cursor (use only A,HL) +; +IsBlnk: LD HL,BlkTbl ;point to tbl + JR IsTest +IsPara: LD HL,ParTbl + JR IsTest +IsParB: LD HL,ParTbl + JR IsTstB +IsPunc: LD HL,PunTbl + JR IsTest +IsPunB: LD HL,PunTbl + JR IsTstB +IsEndS: LD HL,EndTbl +; +IsTest: PUSH HL + CALL Fetch + POP HL + JR IsTLp +IsTstB: PUSH HL + CALL FetchB + POP HL +IsTLp: BIT 7,(HL) + JR NZ,IsTst1 ;at end of tbl? + CP (HL) + RET Z ;Z set if match + INC HL + JR IsTLp +IsTst1: OR A ;clear Z if none + RET ;ret char in A +; +PunTbl: DB ',;:-' ;fall thru... +EndTbl: DB '.?!',0FFh ;end with 0FFh +ParTbl: DB CR ;fall thru... +BadTbl: DB 0,EOF ;characters not "part" of file text +BadLen EQU $-BadTbl ;(<--BlkChr patches in here) +BlkTbl: DB ' ',TAB,0FFh ;end with 0FFh +; +;DISK I/O +; +IOon: LD DE,DspEsc ;show Wait.... + CALL GoTo + CALL MakAlt + LD HL,IOmsg + LD B,4 + CALL BHLMsg + CALL UnAlt + RET +; +BDOSfc: LD DE,FCB +; +;Enter BDOS, but latch onto warm start for +;recovery purposes. (CP/M 2 ONLY) +; +BDOS: CALL DOSVer + JP NC,BDOSep ; just do the BDOS call for CP/M 3.0 + LD A,(DE) ; grab drive # + LD (FcbDrv+1),A ; and stuff it into code + PUSH DE + LD HL,(0001H) + INC HL ;trap warm boot vector in BIOS JP table + LD E,(HL) + INC HL + LD D,(HL) + LD (BIOSws+1),DE + LD DE,BIOSws + LD (HL),D + DEC HL + LD (HL),E + POP DE + CALL BDOSep ;DO IT + PUSH HL + LD DE,(BIOSws+1) ;Restore real warm boot + LD HL,(0001H) + INC HL + LD (HL),E + INC HL + LD (HL),D + POP HL + RET +BIOSws: LD DE,0 ;<--- Warm boot vector + LD HL,(0001H) + INC HL + LD (HL),E ;restore it + INC HL + LD (HL),D +FcbDrv: LD A,0 ;<----- + LD (FCB),A ;restore drive + LD SP,Stack ;restore stack + CALL RDlog ;and disks + CALL Error3 ;Give I/O message + JP Sk1Ed ;Continue editing +; +DOSVer: LD A,0 ;<---- Version + CP 30H ;(Carry set if 2.2, reset if CP/M3, ZxDOS) + RET +; +RstDrv: OR A ;CP/M 2 drive reset (A=1 etc) + JR Z,RDlog + LD HL,FixDsk + RES 6,(HL) ;(have to adjust from ASCII) + CP (HL) ;one of 2 fixed drives? ignore + RET Z + INC HL + RES 6,(HL) + CP (HL) + RET Z + PUSH AF + LD C,GDRV + CALL BDOSep + POP BC + INC A + CP B ;is it logged drive? + JR Z,RDlog + LD HL,1 ;if NOT, can be selective +RDlp: DEC B + JR Z,RDok + ADD HL,HL + JR RDlp +RDok: EX DE,HL + LD C,RSTV ;reset single drive + JR RDxit +RDlog: LD C,RSTD ;sigh, whole system +RDxit: JP BDOSep +; +; +Parse: PUSH AF ;parse FCB w/Duu: and [A/W (NO WILDCARDS) + LD A,(DFMode) + LD (FMode),A + PUSH HL ;Entry: HL=string, A=length + CALL BlkFCB ;Exit: set FCB, FCBU, FMode + POP HL ;...now checks filetypes too + LD D,H + LD E,L + POP AF + OR A + JP Z,PNODRV + LD C,A + LD B,0 ;chars there + LD A,':' + CPIR ;find drivespec? + JR NZ,PNODRV + DEC HL ;yep...NDR? + LD (HL),0 + CALL NdrChk + LD (HL),':' + JR Z,Parse1 ;not an NDR name + INC HL + LD A,B + LD (FCB),A ;store drive + LD A,C + LD (FCBU),A ;store user number + LD E,A + LD C,USRN + PUSH HL + CALL BDOSep ;set user number + POP HL + JR PNAME +Parse1: DEC HL ;yep...User number? + LD A,(HL) + CP '0' + JR C,PDRV + CP '9'+1 + JR NC,PDRV +; +PUSR: SUB '0' + LD E,A ;Got user... figure units + DEC HL + LD A,(HL) + CP '0' + JR C,ZPAR1 ;thats all? + CP '9'+1 + JR NC,ZPAR1 + SUB '0' + LD D,A ;nope, tens too + ADD A,A + ADD A,A + ADD A,A ;*8 + ADD A,D + ADD A,D + ADD A,E ;*(8+2)+units = user + LD E,A + DEC HL + CP 32 + JR NC,ZPBAD ;illegal? +ZPAR1: LD A,E + LD (FCBU),A ;set user + LD C,USRN + PUSH HL + CALL BDOSep + POP HL +; +PDRV: BIT 7,L ;now, parse FCB (start with drive) + JR Z,ZPAR2B ;(Kludge: stay above 0080h) + LD A,(HL) + CP ' ' ;oops, was it there? + JR Z,ZPAR2B +ZPAR2: SUB 'A' + JR C,ZPBAD ;make sure it's legal + LD E,A + LD A,15 + CP E + JR C,ZPBAD + DEC HL + BIT 7,L + JR Z,ZPAR2A ;kludge again (stay about 0080H) + LD A,(HL) + CP ' ' + JR NZ,ZPBAD +ZPAR2A: INC HL + LD A,E + INC A + LD (FCB),A +ZPAR2B: LD BC,4 + LD A,':' + CPIR ;skip over user, to filename + JR PNAME +PNODRV: LD A,' ' ;no du: at all + EX DE,HL + DEC HL ;find filename +PNDL: INC HL + CP (HL) + JR Z,PNDL ;(first nonblank) +; +PNAME: LD B,8 + LD DE,FCB+1 ;do filename at (HL) + EXX + LD DE,FNamBf + LD H,D + LD L,E + LD B,13 + XOR A + CALL Fill + EXX +ZPRL1: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP '.' + JR Z,ZPRL1X + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZRLP1A + CP (HL) + JR NZ,POPT + INC HL +ZRLP1A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL1 + JR ZPRL1F +ZPRL1X: LD A,' ' ;fill with " " + CALL Fill + JR PTYP +ZPBAD: CALL BlkFCB ;bad entry + SCF + RET +ZPRL1F: XOR A + ADD A,(HL) + JR Z,ZPARX + CP '.' + JR NZ,ZPRL2F ;no "."? leave type blank + INC HL +; +PTYP: LD B,3 ;fill type at (HL) + EXX + LD A,'.' + LD (HL),A + INC HL + EXX +ZPRL2: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZPRL2A + CP (HL) + JR NZ,POPT + INC HL +ZPRL2A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL2 +ZPRL2F: LD A,(HL) ;(eat spaces) + CP ' ' + JR NZ,POPT + INC HL + JR ZPRL2F +; +POPT: LD A,(HL) ;process W/A/N option + CP '/' + JR NZ,POPT1 + INC HL + LD A,(HL) ;process W/A/N option +POPT1: OR A + JR Z,ZPARX + CALL VerOpt ;verify legality + JR NZ,ZPBAD + LD (FMode),A + JR ZPARX2 ;any specification overrides defaults +; +ZPARX: LD HL,FCBt1 ;check filetype mode defaults + LD DE,FDflt1 + CALL TypDfl + LD DE,FDflt2 + CALL TypDfl + LD DE,FDflt3 + CALL TypDfl + LD DE,FDflt4 + CALL TypDfl +ZPARX2: LD A,(FCB+1) + CP ' ' + JR Z,ZPBAD + OR A ;DONE. + RET +; +ZPBADC: PUSH HL ;check bad chars + PUSH BC + LD HL,ZPBLST + LD BC,ZPBLEN + CPIR ;Z set if bad + POP BC + POP HL + RET +ZPBLST: DB ' .,;:?*=' ;illegal chars +ZPBLEN EQU $-ZPBLST +; +TypDfl: PUSH HL + LD B,3 ;Set mode from filetype if (HL),(DE) MATCH +TypDLp: LD A,(DE) + CP '?' + JR Z,TypD2 + CP (HL) + JR NZ,TypDex ;no match, quit +TypD2: INC DE + INC HL + DJNZ TypDLp + LD A,(DE) ;match, here's your mode + CALL VerOpt +TypDex: POP HL + RET NZ + LD (FMode),A + RET +; +; +VerOpt: CP 'A' ;verify mode option legal + RET Z + CP 'N' + RET Z + CP 'W' + RET +; +; +;IN: DE=string to match +;OUT: Z=0,B=drive,C=user# (if NDR match found) +; Z=1 if no NDR match +; +NdrChk: PUSH HL + PUSH DE + EX DE,HL ;string addr to HL + LD A,' ' + DEC HL +NdrSpc: INC HL ;skip over spaces + CP (HL) + JR Z,NdrSpc + LD D,H ;addr of 1st non blank to DE + LD E,L + LD B,Z3NdrM+1 ;# chars to allow before + XOR A ;we MUST see a NUL +NdrEos: CP (HL) ;find terminating NUL + JR Z,NdrNul + INC HL + DJNZ NdrEos + JR NoNdr ;more than 8 chars, not an NDR +NdrNul: LD BC,Z3NDR + CALL Z3EAdr + JR Z,NoNdr ;no NDR block + EX DE,HL ;start of string to HL + LD D,B ;NDR addr to DE + LD E,C +NxtNdr: LD A,(DE) ;end of NDRs? + OR A + JR Z,NoNdr ;yep, no match + INC DE + INC DE ;DE points to NDR string + PUSH HL ;save start of string + PUSH DE ;save NDR string addr + LD B,Z3NdrM +NdrNxC: LD A,(DE) + CP ' ' ;end of NDR name string? + JR NZ,NdrChC ;not yet + INC (HL) ;did we hit the NUL + DEC (HL) ;at the end of string + JR NdrMis ;(i.e. was it a full match?) +NdrChC: CP (HL) + JR NZ,NdrMis + INC HL ;next char in string + INC DE ;next char in NDR entry + DJNZ NdrNxC +NdrMis: POP DE ;restore start of NDR string + POP HL ;restore start of string + JR Z,NdrMtc ;all chars match, got an NDR + EX DE,HL ;start of NDR string to HL + LD BC,Z3NdrL + ADD HL,BC ;next NDR entry to HL + EX DE,HL ;and now to DE + JR NxtNdr +NdrMtc: EX DE,HL ;NDR matched + DEC HL + LD C,(HL) ;fetch user number + DEC HL + LD B,(HL) ;fetch drive + OR 0FFh ;Z=0H +NoNdr: POP DE + POP HL + RET +; +;Read in a word from the Z3ENV block. +;IN: offset in BC +;OUT: addr in BC +; Z=1 if addr is invalid +; +Z3EAdr: PUSH HL + LD HL,(Z3Env) + LD A,H + OR L + JR Z,NoZEnv ;no Z3ENV: Z=1 + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + LD A,B + OR C ;Z=1 if no address at offset +NoZEnv: POP HL + RET +; +; +;Read in the file. (HL=prev byte, BC=max size) +;Return with HL=last byte, Z=out of room, C=input error. +; +MSIn: XOR A + LD (FCBex),A ;Initialize FCB + LD (FCBs1),A + LD (FCBcr),A + LD (MSIFlg),A + CPL + LD (SftFlg),A + PUSH HL + PUSH BC + LD C,FOPN + CALL BDOSfc + INC A ;Not found? + JR NZ,MSIfnd +MSIerr: POP BC ;Error... + POP BC + OR 1 ;Clear Z + SCF ;Set C + RET +MSIfnd: LD DE,DMA + LD C,SDMA + CALL BDOS +; +MSIlp1: LD C,RSEQ + CALL BDOSfc + CP 1 ;No more reocrds? + JP Z,MSIefX + JR NC,MSIerr ;Other error? + LD IX,DMA + POP DE ;target count + LD B,128 ;1 record + POP HL ;target address +MSIlp2: LD A,(FMode) + CP 'W' + JR NZ,MSIlp3 + LD A,(IX) ;Wordstar: handle soft hyphens + CP 1Fh + JR NZ,MSIl2x + LD A,'-' + LD (IX),A +MSIl2x: CP 1Eh ;remove dead soft hyphens + JR Z,MSIlf + CP ' '+080H ;remove soft spaces + JR NZ,MSIl2a + LD A,(SftFlg) + OR A ;(unless at beginning of line) + JR Z,MSIlf + JR MSIlp3 +MSIl2a: XOR A + LD (SftFlg),A + LD A,(IX) ;and keep hard/soft CRs straight + CP CR+80H + JR NZ,MSIl2b + LD A,(HL) ;SCR must have space before... + CP ' ' + JR Z,MSIlp3 + SET 7,(HL) + JR NC,MSIlp3 + RES 7,(HL) ;can't set hi bit on ctlcodes + LD A,' ' + INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z + JR MSIlp3 +MSIl2b: CP CR + JR NZ,MSIlp3 +MSIl2c: RES 7,(HL) ;...and HCR must not have space + LD A,(HL) + CP ' ' + JR NZ,MSIlp3 + DEC HL + INC DE + JR MSIl2c +MSIlp3: LD A,(IX) ;take the byte + AND 7Fh ;Mask parity + CP EOF ;EOF? + JR Z,MSIeof + CP LF ;toss line feeds + JR NZ,MSIl3a + LD (SftFlg),A ;but record them + JR MSIlf +MSIl3a: LD IY,BlkChr + CP (IY) ;toss block chars + JR Z,MSIlf + CP ' ' ;take non-spaces + JR NZ,MSIok + LD A,(HL) + CP 20H ;Last one CTL? take space + JR C,MSIsp + BIT 7,(HL) ;Already hidden space? take space + JR NZ,MSIsp + SET 7,(HL) ;Hide space + JR MSIlf +; +MSIsp: LD A,' ' +MSIok: INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z +MSIlf: INC IX ;Bump input + DEC B ;Go through record + JP NZ,MSIlp2 + PUSH HL + PUSH DE + JP MSIlp1 ;Get next block +; +MSIefX: POP DE ;(for last rec bug fix) + POP HL +MSIeof: OR 1 ;clear Z/C + LD (MSIFlg),A ;Show load OK + RET +; +; +;Write out BC characters at HL to file FCB (C=error) +; +MSOut: PUSH BC + PUSH HL + ADD HL,BC ;ending address + PUSH HL + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD HL,FCB+1 ;strip attributes + LD B,11 +MSOlp1: RES 7,(HL) + INC HL + DJNZ MSOlp1 + CALL ZeroS1 + LD DE,tStamp ; set the buffer for the + LD C,SDMA ; file timestamp + CALL BDOSep + LD C,GETS ; get the file timestamp + CALL BDOSfc + LD (tsFlg),A ; A=1 if we got a stamp + LD A,(FilFlg) ; make a backup file? + OR A + JR Z,MSOdel ; no backup needed + LD HL,FCB ; copy original filename and extension + LD DE,DMA + LD BC,16 ;FCB length + LDIR ;copy it + LD BC,8+1 ;copy original filename only + LD HL,FCB + LDIR ;again + LD BC,3 ;extension of BAK + LD HL,Bak + LDIR + LD DE,DMA+16 ;delete BAKfil + LD C,FDEL + CALL BDOS + INC A + JR NZ,MSOren + OR H ;no BAK deleted, h/w error? + JP NZ,MSOer2 ;yep... +MSOren: LD DE,DMA ;rename old file to BAK + LD C,FREN + CALL BDOS + JR MSOmak +; +MSOdel: CALL DOSVer + JR C,MSOdl2 ; skip if plain CP/M + CP 'S' + JR Z,MSOdl2 ; skip if ZSDOS + CP 'D' + JR Z,MSOdl2 ; skip if ZDDOS + LD C,ERRM ; ... we get here, we're CP/M 3.0 + LD E,0FFH ; return error, no print + CALL BDOS + XOR A + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK ;make a new file + CALL BDOSfc + PUSH AF + PUSH HL + LD C,ERRM ; return error, print + LD E,0FEH + CALL BDOS + POP HL + POP AF + PUSH AF + OR A + JR Z,MSOnSt + POP AF + LD A,H + CP 8 + JR NZ,MSOmak + LD C,FTRU ; truncate file to 0 bytes + XOR A + LD (FCBr0),A + LD (FCBr1),A + LD (FCBr2),A + CALL BDOSfc + OR A + JP NZ,MSOer2 + LD C,FOPN + CALL BDOSfc ; open the file + PUSH AF + JR MSOnSt ; --- end of CP/M3 specific open code +; +MSOdl2: LD C,FDEL ; +++ CP/M2.2, ZxDOS specific + CALL BDOSfc ; delete any old BAK file + INC A + JR NZ,MSOmak ; jump if all good + OR H ; hardware error code? + JP NZ,MSOer2 ; ...yep +; +MSOmak: XOR A ;Initialize FCB + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK + CALL BDOSfc + PUSH AF + LD A,(tsFlg) ;+++ timestamp code start + DEC A ;do we have a timestamp? + JR NZ,MSOnSt ;no, don't update the timestamp + LD C,SETS ;set create timestamp of new file + CALL BDOSfc ;to the same as existing file +MSOnSt: LD C,SDMA + LD DE,DMA + CALL BDOSep + POP AF ;restore result of FMAK + POP DE ;end + POP HL ;start + POP BC ;(bytes) + INC A + JP Z,MSOerr ;make file failed + LD A,B + OR C ;any bytes? + JP Z,MSOcls + LD C,0 ;Initialize GetNx + LD B,128 ;1 record + LD IX,DMA +MSOlp2: CALL GetNx + EXX + LD HL,BadTbl ;skip illegal chars + LD BC,BadLen + CPIR + EXX + JR Z,MSOsk1 ;0 or EOF +MSOlp3: LD (IX),A ;put it out + LD A,(FMode) + CP 'W' ;Wordstar mode? + JR NZ,MSOWSx + LD A,(IX) + CP ' ' + JR NZ,MSOWSa + LD A,(IX-1) ;add microjustification bits + CP 21h + JR C,MSOWS2 + SET 7,(IX-1) + JR MSOWS2 +MSOWSa: CP CR + JR Z,MSOWS1 + CP LF + JR Z,MSOWSx +MSOWS0: XOR A + LD (SftFlg),A + JR MSOWSx +MSOWS1: LD A,(IX-1) ;soften CRs after spaces + AND 7FH + CP ' ' + JR NZ,MSOWS0 +MSOW1a: SET 7,(IX) + LD A,0FFH + LD (SftFlg),A + JR MSOWSx +MSOWS2: LD A,(SftFlg) ;and spaces after soft CRs + OR A + JR NZ,MSOW1a +MSOWSx: LD A,(IX) + INC IX ;bump pointer + DJNZ MSOsk1 ;Skip if buffer not full + PUSH BC + PUSH DE + PUSH HL + LD C,WSEQ + CALL BDOSfc + POP HL + POP DE + POP BC + OR A + JR Z,MSOook + CALL MSOcls ;output error + JR MSOerr +MSOook: LD B,128 + LD IX,DMA + LD A,(DMA+127) + LD (IX-1),A +MSOsk1: AND 7FH + CP CR ;Add LF after CR + LD A,LF + JR Z,MSOlp3 + LD A,H + XOR D ;At end yet? + JP NZ,MSOlp2 + LD A,L + XOR E + JP NZ,MSOlp2 + OR C ;Still got hidden space? + JP NZ,MSOlp2 + OR B ;need EOF? + JR Z,MSOsk2 +MSOefL: LD (IX),EOF ;yes + INC IX + DJNZ MSOefL +MSOsk2: LD C,WSEQ + CALL BDOSfc + OR A + JR Z,MSOcls + CALL MSOcls + JR MSOerr +MSOcls: LD C,FCLO ;all done, close up + CALL BDOSfc + INC A + OR A ;bug fix 2.67 + RET NZ +MSOerr: SCF + RET +MSOer2: POP HL ;discard start, + POP HL ;end, + POP HL ;(bytes) + LD C,SDMA + LD DE,DMA + CALL BDOSep ;reset DMA buffer + JR MSOerr +; +ZeroS1: XOR A + LD (FCBs1),A + RET +; +; +; +; DISPLAY FUNCTIONS +; +;(Re)initialize screen to begin editing +; +DoHdr: LD A,(NoHdrF) + OR A + RET NZ + LD DE,0 + CALL GoTo + LD HL,Header + CALL AltDsp + CALL ShoFnm ;Show file name + LD HL,OPoff + LD A,(FMode) + CP 'N' + JR NZ,DoHdr1 ;show "Pg " if document + LD A,(PgLen) + OR A + JR NZ,DoHdrT + LD HL,OPon ;show "OP" if ^OP in nondoc +DoHdr1: LD DE,DspOP + CALL TogSho +DoHdrT: CALL ITshow ;show toggles + CALL VTshow + CALL HYshow + CALL AIshow + CALL DblSho +MRshow: LD A,(RMSav) ;requires header display + DEC A + LD HL,MRon + JP Z,PSDisp + LD DE,DspMrg + JP TogSho +; +TogSho: LD A,(NoHdrF) + OR A + RET NZ + PUSH HL ;toggle show subroutine + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + JP UnAlt +; +; +UpLft: LD DE,0100H ;go to "top of text" + LD A,(RulFlg) + OR A + JR Z,UndrX + INC D + JR UndrX +UndrHd: LD DE,0100H ;go below header regardless +UndrX: JP GoTo +; +; +NoHdr: LD HL,NoHdrF ;toggles on/off + CALL ToggHL + OR A + JR Z,HdrOn +HdrOff: CALL AdjLns ;that's one more line + CALL IncVO + JP SetAl +HdrOn: CALL AdjLns + CALL DecVO + CALL DoHdr ;let's see it again + JP SetAl +; +; +;Show current file data in the heading +; +ShoFnm: CALL MakAlt + LD DE,DspFnm+8 ;blank out old stuff + CALL GoTo + LD B,19 + CALL BBlank + LD DE,DspFnm + CALL GoTo + LD A,(FCB) + ADD A,'A'-1 ;drive letter + CALL PutChA + LD A,(FCBU) ;user number 0-15 + LD C,A + LD B,'3' ;user 30+? + SUB 30 + JR NC,ShoFn1 + LD B,'2' ;user 20+? + LD A,C + SUB 20 + JR NC,ShoFn1 + LD B,'1' ;user 10+? + LD A,C + SUB 10 +ShoFn1: PUSH AF + LD A,B + CALL NC,PutChA + POP AF + JR NC,ShoFn2 + LD A,C +ShoFn2: ADD A,'0' ;show LSD of user number + CALL PutChA + LD BC,Z3NDR + CALL Z3EAdr + JR Z,ShoFnN ;skip if no NDR + LD H,B + LD L,C +ShFnNl: LD B,(HL) ;drive of this NDR entry + INC B + DEC B + JR Z,ShoFnN ;0 means no more entries + LD A,(FCB) + CP B ;drive match? + INC HL + JR NZ,ShFnNx + LD C,(HL) + LD A,(FCBU) + CP C ;user # match? + JR Z,ShFnNn ;yes, display NDR name +ShFnNx: LD DE,Z3NdrL+1 ;skip over NDR + ADD HL,DE + JR ShFnNl ;try next NDR +ShFnNn: LD A,'/' + CALL PutChA + LD B,8 ;show up to first 8 chars of NDR +ShFdLp: INC HL + LD A,(HL) + CP ' ' + CALL NZ,PutChA + DJNZ ShFdLp +ShoFnN: LD A,':' + CALL PutChA ;punctuate + LD HL,FCB+1 + LD B,8 ;Name +ShFnLp: LD A,(HL) + RES 7,A + CP ' ' ;Quit on blank + JR Z,ShFnLF + CALL PutChA + INC HL + DJNZ ShFnLp ;Loop for 8 +ShFnLF: LD A,'.' ;punctuate + CALL PutChA + LD HL,FCBt1 + LD B,3 ;Type +ShFnL2: LD A,(HL) + CALL PutChA + INC HL + DJNZ ShFnL2 + CALL PutSpc + LD A,'/' ;option + CALL PutChA + LD A,(FMode) + CALL PutChA + JP UnAlt +; +; +Ruler: LD HL,RulFlg ;toggle ruler on/off + CALL ToggHL + OR A + JP Z,RulOff +; +RulOn: CALL AdjLns ;readjust screen length + CALL DecVO + CALL Z,SetAl ;maybe on line 1? + JR RuShow +; +RulFix: LD A,(RulFlg) ;update ruler if on + OR A + RET Z +RuShow: LD IY,RulBuf ;build ruler here + LD A,(NSkip) ;starting column + INC A + LD C,A + LD A,(View) ;length + LD B,A +RuLp: LD E,'-' ;default char is "-" + LD A,(VTFlg) ;which tab mode? + OR A + JR Z,RuLpH + PUSH BC ;"T" if varitab stop + LD A,C + LD HL,VTList + LD BC,VTNum + CPIR + POP BC + JR Z,RuVtab + JR RuNtab +RuLpH: LD HL,TabCnt ;"I" if hardtab stop + LD A,C + DEC A + AND (HL) + JR Z,RuHtab +RuNtab: LD A,(RtMarg) ;"R" if right margin + CP C + JR Z,RuRM + JR C,RuDot ;or dot if outside + LD A,(LfMarg) + CP C + JR Z,RuLM ;or "L" if left margin + DEC A + CP C + JR NC,RuDot +RuLpF: LD (IY),E ;okay, show it + INC IY + INC C + DJNZ RuLp + LD (IY),0 + CALL UndrHd + LD HL,RulBuf + JP AltDsp +RuLM: LD E,'L' + JR RuLpF +RuRM: LD E,'R' + JR RuLpF +RuDot: LD E,'.' + JR RuLpF +RuVtab: LD E,'!' + JR RuLpF +RuHtab: LD E,'I' + JR RuLpF +; +RulOff: CALL AdjLns ;adjust screen size + CALL IncVO + LD E,A + CALL CrLft ;oops, may be near top + XOR A + ADD A,E + JP Z,ShoLn1 + JP SetAl +; +; +;Display one byte on the screen for messages rather than text. +;Hi bit set = following space. +; +DsByt: CP CR ;Is it a CR + JR Z,Sk1DB ;Yes, skip + CP X ;compressed space? + JR NC,Sk3DB +DsBy1: LD E,A ;normal character + LD HL,HPos ;room? + DEC (HL) + JP NZ,PutCh ;put it out + INC (HL) ;EOL + RET +Sk1DB: LD A,(HPos) ;Fill out spaces for CR + LD E,A ;(needed for attributes, etc) + CALL SpEOL + LD A,(AuWrap) ;does autowrap occur? + OR A + JR NZ,Sk1aDB + LD E,CR ;NO, put out a CRLF + CALL PutCh + LD E,LF + CALL PutCh +Sk1aDB: LD A,(View) + INC A + LD (HPos),A ;new line + RET +Sk3DB: AND 7FH ;compressed space + CALL DsByt +DsSpc: LD A,' ' + JR DsBy1 +; +; +;Display message pointed to by HL. 00h is end. +;80H,nn = skip count. +; +Dspla: LD A,(View) ;initialize + INC A + LD (HPos),A +DspLp: LD A,(HPos) ;or continue, here + LD E,A + LD A,(HL) ;get byte + INC HL + OR A ;All done? + RET Z + CP X ;hidden spaces? + JR NZ,Dsp10 + LD A,(HL) ;get space count + INC HL + LD B,A +Dsp01: PUSH BC + PUSH HL + CALL DsSpc + POP HL + POP BC + DJNZ Dsp01 + JR DspLp +Dsp10: PUSH HL + CALL DsByt ;Put it out + POP HL + JR DspLp ;Do next one +; +;Display message which immediatly follows the CALL +; +Dspl: POP HL + CALL Dspla + JP (HL) +DsplC: POP HL ;same, but continued + CALL DspLp + JP (HL) +; +; +;Make a text "window" at screen bottom +; +Window: LD A,(PhysLn) ;requires 16 lines or more + CP 16 + JP C,Error7 + LD HL,WinFlg ;toggles on/off + CALL ToggHL + OR A + JR Z,WinOff +; +WinOn: CALL AdjLns ;adjust counts + LD A,(PhysLn) + AND 1 + CALL NZ,ClLast ;clear odd line? + CALL TopV ;put chosen text on top + LD A,0FFh + LD (BelowF),A ;go below + CALL ShoSc ;show text + LD A,(NoHdrF) + OR A + JR NZ,WinOn2 + LD DE,0000h ;separator needed? + CALL GoTo + CALL SepLin + CALL ShoFnm ;with name +WinOn2: XOR A + LD (BelowF),A + JP SetAl +; +WinOff: CALL AdjLns + JP SetAl +; +; +AdjLns: LD A,(PhysLn) ;KEEP screen counts consistent + LD HL,WinFlg + BIT 0,(HL) + JR Z,AdjL1 + SRL A +AdjL1: LD (Lines),A ;physical window size + LD HL,NoHdrF + BIT 0,(HL) + JR NZ,AdjL2 + DEC A ;adjust for header if present +AdjL2: LD HL,RulFlg + ADD A,(HL) ;adjust for ruler if present + LD (TxtLns),A + RET +; +; +; SCREEN I/O ROUTINES +; +;Do screen control code strings (return Carry if none) +; +CtlStr: XOR A + ADD A,(HL) ;HL points to #,bytes (# may be 0) + SCF + RET Z + LD B,A + INC HL ;set up count +BHLMsg: +CtlSLp: LD E,(HL) + INC HL + PUSH BC + PUSH HL + CALL ShutUp ;do NOT filter + POP HL + POP BC + DJNZ CtlSLp + OR A + RET +; +BlkFCB: LD B,11 ;blank out FCB name,typ + LD DE,FCB+1 +BlkFil: LD A,' ' ;blank out B bytes at DE + LD (DE),A + INC DE + DJNZ BlkFil + RET +BBlank: PUSH BC ;blank out B spaces + LD E,' ' + CALL ShutUp + POP BC + DJNZ BBlank + RET +; +;Show messages and prompts +; +MsgDsp: PUSH HL ;must start at "top" + CALL UpLft + POP HL +AltDsp: PUSH HL ;display message in alt video + CALL MakAlt + POP HL + CALL Dspla + JR UnAlt +; +Prompt: PUSH HL ;Prompt: blank first line + CALL UpLft ;(with attribute) + CALL MakAlt + LD A,(View) + INC A + LD E,A + CALL SpEOL + CALL UnAlt + POP HL + JR MsgDsp ;then show prompt message +; +;Handle alternate video +; +MakAlt: LD A,(AltHdr) ;optional for messages and prompts + OR A + RET Z +AltY: LD HL,AltOn ;mandatory for ctl-chars + LD A,(AltBit) ;ram always uses hi bit + OR A + JP Z,CtlStr + LD A,X + LD (AltMsk),A + RET +UnAlt: LD A,(AltHdr) + OR A + RET Z +UnAltY: LD HL,AltOff + LD A,(AltBit) + OR A + JP Z,CtlStr + XOR A + LD (AltMsk),A + RET +; +;Character output +; +XPutCh: LD A,(Horiz) ;show character in E + LD HL,View ;UNLESS in lower rt corner + CP (HL) + JR NZ,PutCh + LD A,(Vert) + LD HL,TxtLns + CP (HL) + RET Z +PutCh: PUSH HL ;show char in E + PUSH DE + PUSH BC + LD A,(Filter) ;filtered + CP E + JR C,PutChQ ;'?' if char >= Filter (07FH) +PutCh1: LD A,(AltMsk) + OR E + CALL CONOut + POP BC + POP DE + POP HL + RET +PutChQ: LD E,'?' + JR PutCh1 +; +PutSpc: LD A,' ' +Echo: CP 20H ;echo typed char, IF nice + RET C ; (used for one-char input) +PutChA: PUSH DE ;show char in A + PUSH AF ; save it too (for Echo) + LD E,A + CALL PutCh + POP AF + POP DE + RET +; +CONOut: LD E,A +ShutUp: NOP ;<--- goes to RET for Quiet + LD C,UCON ;put byte to console (mostly ctls) + JP BDOSep +; +PosCur: LD A,(Horiz) + LD E,A + DEC E + LD A,(RulFlg) + AND 1 + LD HL,Vert + ADD A,(HL) + LD D,A +; +;Position cursor to row D column E +; +GoTo: LD A,(NoHdrF) ;lie for lack of header + AND D ;(decrement row if >0) + JR Z,GoTo01 + DEC D +GoTo01: LD A,(BelowF) ;implement window below + OR A + JR Z,GoToIt + LD A,(Lines) + ADD A,D + LD D,A +GoToIt: LD A,D + LD (CurRow),A + LD A,(PosMod) + CP 'N' + JR NZ,GoYPos + LD HL,PCu ;use Down,Right method (gaak) + CALL Go2Byt ;home first + LD A,D + OR A + JR Z,Go2RwF +Go2Row: PUSH DE ;move down to desired row + LD E,LF + CALL ShutUp + POP DE + DEC D + JR NZ,Go2Row +Go2RwF: LD A,E + OR A + RET Z +Go2Col: LD HL,PCu+2 + CALL Go2Byt ;now across to desired col + DEC E + JR NZ,Go2Col + RET +GoYPos: CP 'A' ;Okay, can be more sophisticated... + JR Z,GoANSI + LD HL,PCu ;use ESC = sequence + CALL Go2Byt ;leadin byte(s) + LD HL,PCu+2 + PUSH DE ;now coordinates + PUSH HL + LD A,(PosMod) ;which order? + CP 'R' + JR Z,GoToX ;(backwards) + LD A,D + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,E + ADD A,(HL) + CALL CONOut + JR GoToDl +GoToX: LD A,E + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,D + ADD A,(HL) + CALL CONOut +GoToDl: LD A,(PosDly) ;optional delay for some terminals + OR A + RET Z + LD B,A + LD C,0 + JP BDlyLp +GoANSI: LD HL,ANSIms+3 ;use ANSI sequence + LD A,D + INC A ;origin 1,1 + CALL GoASub + LD HL,ANSIms+6 + LD A,E + INC A + CALL GoASub + LD HL,ANSIms + CALL CtlStr + JR GoToDl +GoASub: LD (HL),'0' ;tens digit +GASl1: CP 10 + JR C,GAS2 + INC (HL) + SUB 10 + JR GASl1 +GAS2: INC HL + ADD A,'0' ;units + LD (HL),A + RET +Go2Byt: CALL Go1Byt ;show one or two bytes at HL + LD A,(HL) + OR A + RET Z +Go1Byt: PUSH DE + LD B,1 ;just do one byte + CALL CtlSLp + POP DE + RET +ANSIms: DB 8,ESC,'[00;00H' ;for use with CtlStr +; +; +IfSpLn: LD A,(AltHdr) ;draw sep line IF headers not alt + OR A + RET NZ +SepLin: CALL MakAlt ;draw separator line + LD A,(View) + LD D,A + LD E,'-' +SLDlp: PUSH DE + CALL PutCh + POP DE + DEC D + JR NZ,SLDlp + JP UnAlt +; +; +;SHOW SCREEN ROUTINES +; +; | +------------------------ +; |HELLO! | ^ +; |This is your |text file, which is seen Vert +; |on the screen| just like this._ v +; | | \ +; |<---NSkip---> <-----Horiz-----> \ +; |<-----------CurCol------------> \Cursor at (H,V) +; +;Recheck current position on screen +; +Orient: LD A,(Vert) ;Adjust Horiz and Vert + LD E,A + CALL CrLft ;Start of first screen line + JR NC,Ornt1 + CALL TopV ;At top, set Vert to 1 + JR Ornt2 +Ornt1: LD A,(Vert) ;Decrement Vert if needed + SUB E ; to avoid whitespace at top + LD (Vert),A +Ornt2: CALL ColCnt ;Update columen (in A,B,CurCol) + INC A + JR NZ,Ornt3 + LD B,0FEH +Ornt3: LD A,(Horiz) ;Compute cursor offset in line + LD C,A + LD A,B + SUB C ;CurCol-Horiz is minimum offset + JR NC,Ornt4a + XOR A ;set 0 if negative +Ornt4a: LD E,A + LD A,(NSkip) ;present offset < min? + CP E + JR C,Ornt4b ;if so, change + CP B ;bigger than CurCol-1? + JR C,Ornt4c ;if not, OK + LD A,B ;round down to small enough + DEC A + AND 0C0H ;multiple of 32 + JR Ornt4c +Ornt4b: LD A,E ;round up to big enough + OR 1FH + JR Z,Ornt4c + INC A +Ornt4c: LD (NSkip),A ;set (new?) offset + SUB B + NEG + LD (Horiz),A + LD HL,(CurLin) ;Figure line, page + LD (CurPgL),HL + LD A,(FMode) + CP 'N' + LD A,(PgLen) + JR NZ,Ornt5 + XOR A ;don't SHOW pagination for nondocs +Ornt5: LD E,A + LD D,0 + DEC HL + LD B,D + LD C,D + OR A ;not paginating? + JR Z,OrnLpF + INC BC +OrntLp: SBC HL,DE + JR C,OrnLpF + INC BC + JR OrntLp +OrnLpF: ADD HL,DE + INC HL + LD (CurPgL),HL + LD (CurPg),BC + RET +; +;Show (just) as much of the text as necessary +; +ShoTx: CALL KyStat ;check keybd + JR NZ,ShoTx1 + CALL TestSc ;check postponed screen disp + JP NZ,ShoAll ;do it! + CALL ShoPos ;quiet? update header + CALL TestCu ;check postponed line disp + JR NZ,DoPost ;do it (or more, if requested) +ShoTx1: LD A,(ShoFlg) ;busy... + OR A ;nothing (0) + RET Z + DEC A + JP Z,ShoRCu ;just one line (1,2) - can be postponed + DEC A + JP Z,ShoCu + DEC A + JP Z,ShoDn ;bottom part (3) + JP ShoSc ;or whole screen +DoPost: LD A,(ShoFlg) + CP 3 + JP C,ShoCu ;at LEAST this + JP Z,ShoDn + JP ShoSc +; +;Show position in file, no matter what +; +ShoPos: LD A,(NoHdrF) + OR A + RET NZ + CALL Force ;must see this + LD DE,DspPg ;Update header + CALL GoTo + CALL MakAlt ;C128 bug fix requires GoTo first + LD HL,(CurPg) + LD A,(FMode) + CP 'N' + CALL NZ,ShPSb1 + LD DE,DspLin + LD HL,(CurPgL) + CALL ShPoSb + LD DE,DspCol + LD A,(CurCol) + LD L,A + LD H,0 + CALL ShPoSb + CALL UnAlt + JP UForce +ShPoSb: PUSH HL ;show a number + CALL GoTo + POP HL +ShPSb1: LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + JP BHLMsg +; +;Show current line only (fast) +; +ShoCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu +ShoCu1: LD A,(Vert) + LD B,A + JP ShoLn +; +ShoRCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu + CALL FetchB + CP TAB ;can't do this with tab at left + JP Z,ShoCu + LD A,(Vert) ;special routine: only RIGHT of cursor + LD D,A ;...modeled on ShoLCu + LD A,(RulFlg) + AND 1 + ADD A,D + LD D,A ;current row + LD A,(Horiz) + DEC A + LD E,A + JP Z,ShoCu ;can't do this at left of screen + DEC E + CALL GoTo ;position to start + LD E,1 ;find start of line + CALL CrLft + PUSH HL + LD HL,Horiz + LD A,(NSkip) + ADD A,(HL) + DEC A + LD D,A + DEC A + LD B,A ;skip till just before cursor + LD A,(View) + INC A + SUB (HL) + LD E,A + INC E + POP HL + CALL ShoLSb ;do part (char!) left of cursor + INC E ;(DON'T ask me why this INC is needed) + LD D,E + DEC D + LD A,(Vert) + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShRCu3 + DEC D +ShRCu3: LD HL,(AftCu) + JP ShoLSb +; +;Display from Cursor line-1 down +; +ShoDn: CALL ConChk ;(postpone if busy!) + JP NZ,HoldSc + LD HL,CsrOff + CALL CtlStr + LD A,(DSFlg) ;(or line-2 if DS) + LD HL,Vert + ADD A,(HL) + JR Z,ShoSc0 + LD B,A + DJNZ ShScLp + JR ShoSc0 +; +;Show everything on emerging from macros etc +; +ShoAll: CALL Orient + CALL DoHdr + CALL ShoPos + JR ShoScX +; +;Display whole text screen (sigh) +; +ShoSc: CALL ConChk ;(Postpone if busy!) + JP NZ,HoldSc +ShoScX: LD HL,CsrOff + CALL CtlStr +ShoSc0: CALL RulFix + CALL SetNo ;kill any pending redisps + XOR A + LD (CuFlg),A + CPL + LD (HorFlg),A + LD B,1 ;Simple method if not memory mapped +ShScLp: PUSH BC + CALL ShoLn + POP BC + INC B + LD A,(TxtLns) + INC A + SUB B + JR NZ,ShScLp + LD HL,CurOn + CALL CtlStr + RET +; +IOoff1: LD DE,DspEsc ;header: blank prompt + CALL GoTo + CALL MakAlt + LD B,4+1 ;(cursor) + CALL BBlank + JP UnAlt +; +IOoff: LD A,(NoHdrF) ;headerless? redo top line + OR A + JR Z,IOoff1 + LD A,(RulFlg) + OR A + JP NZ,RuShow +; +;Show line 1 (to wipe out msgs) +; +ShoLn1: LD B,1 ;fall thru... +; +;Show line number B (=1...TxtLns) +; +ShoLn: LD A,(ShutUp) + OR A + RET NZ + PUSH BC + CALL KyStat ;(helps buffering for slow keyboards) + POP BC + LD A,(RulFlg) + AND 1 + ADD A,B + LD D,A ;position cursor on screen + LD E,0 + PUSH BC + CALL GoTo + POP BC + LD A,(Vert) ;is line before or after cursor? + SUB B + JR Z,ShoLCu ;ouch, it's cursor line + JR C,ShoLAf +ShoLBf: LD E,A ;okay, before + INC E + CALL CrLft + LD A,(View) + INC A + LD E,A + LD A,(NSkip) + LD B,A + LD D,255 + JR ShoLSb +ShoLAf: NEG ;okay, after + PUSH BC ;save line# + LD E,A + CALL CrRit + POP BC + PUSH AF + LD A,(View) + LD D,A + INC A + LD E,A + LD A,(TxtLns) + CP B ;last line? avoid last column + JR NZ,ShLAf0 + DEC D +ShLAf0: POP AF + JR C,ShLAf1 + JR Z,ShLAf2 +ShLAf1: JP ClEOL ;no line! +ShLAf2: LD A,(NSkip) + LD B,A + ADD A,D + LD D,A + JR ShoLSb +ShoLCu: LD E,1 ;hmm, right on cursor + PUSH BC ;save line# + CALL CrLft + LD A,(NSkip) + LD B,A + LD A,(CurCol) ;do part to left + DEC A + LD D,A + LD A,(View) + INC A + LD E,A + CALL ShoLSb + LD D,E + DEC D + POP AF ;line# + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShLCu1 + DEC D +ShLCu1: LD HL,(AftCu) +; +ShoLSb: LD A,D ;Show up to column D of text starting at HL + OR A ;E=room+1, B=Cols to skip (if any) + RET Z + XOR A + EXX + LD B,A ;B',C' keep track of previous chars + LD C,A + LD E,A ;E' is count skipped + EXX + LD C,A ;initialize GetNx + ADD A,B + JR Z,ShLSL2 +ShLSL1: CALL GetNx ;eat skipped columns + JP Z,ClEOL ;end of line? + CP TAB + JR Z,ShLS1T + EXX + INC E ;E' + EXX + DEC D + DJNZ ShLSL1 + CALL ShSvCh + INC D + DEC D + RET Z + JR ShLSL2 +ShLS1T: EXX ;count for tabs + LD A,E + LD HL,TabCnt + AND (HL) + XOR (HL) ;extra spaces + INC A ;plus usual one + PUSH AF + ADD A,E + LD E,A + POP AF + EXX + PUSH AF + SUB D + NEG + LD D,A + POP AF + SUB B + NEG + LD B,A + JR NZ,ShLSL1 + LD A,TAB + CALL ShSvCh + INC D + DEC D + RET Z +ShLSL2: CALL GetNx ;show the rest + EXX + LD C,B + LD B,A + EXX + JR Z,ShLSCr ;take care of CR,TAB + CP ' ' + JR C,ShCtl + PUSH DE + LD E,A + CALL PutCh + POP DE +ShLSL3: DEC E + DEC D + RET Z + LD A,E + DEC A + RET Z + JR ShLSL2 +ShCtl: PUSH HL + PUSH BC + PUSH DE + CP TAB + JR Z,ShLSTb + ADD A,40H ;other ctls are hili letters + EX AF,AF' + CALL AltY ;(mandatory) + EX AF,AF' + CALL PutChA + CALL UnAltY + JR ShLRet +ShLSCr: PUSH HL + PUSH BC + PUSH DE + EXX + LD A,C ;last char + EXX + CP ' ' + JR Z,ShLCrF ;SCR doesn't show + LD A,(HCRFlg) + OR A + JR Z,ShLCrF ;HCRs also MAY not... + LD E,'<' + CALL PutCh + POP DE + DEC D + DEC E + PUSH DE + LD A,E ;don't ClEOL if now in last col + CP 2 +ShLCrF: CALL NC,ClEOL + POP DE ;end of line + POP BC + POP HL + RET +ShLSTb: LD A,(View) ;hit a tab... + INC A + SUB E ;column + LD HL,TabCnt + AND (HL) + XOR (HL) ;figure extra spaces + LD B,A + JR Z,ShLTLF +ShLTbL: CALL PutSpc ;do them + POP DE + DEC E + DEC D + PUSH DE + JR Z,ShLRet + DJNZ ShLTbL ;then one last +ShLTLF: CALL PutSpc +ShLRet: POP DE + POP BC + POP HL + JR ShLSL3 +ShSvCh: EXX ;keep track of prev chars + LD C,B + LD B,A + EXX + RET +; +; +ClEOL: LD HL,CIL ;clear to EOL (quickly if possible) + CALL CtlStr + RET NC +SpEOL: DEC E ;this always SPACES (for attributes) + RET Z +ClELp: LD A,(CurRow) + INC A + LD HL,PhysLn + CP (HL) + JR NZ,ClEL3 + DEC E ;avoid last char on last line + RET Z +ClEL3: CALL PutSpc + DEC E + JR NZ,ClEL3 + RET +; +ClLast: LD A,(PhysLn) ;clear last line on screen + DEC A + LD D,A + LD E,0 + CALL GoToIt + LD A,(View) + LD E,A ;do NOT INC this, it's last line + JR ClEOL +; +; +;Set level of display required +; +SetAl: LD A,0FFH ;routines to set it + JR Set1 ;(must preserve ALL REGS and FLAGS) +SetDn: LD A,3 + JR Set1 +SetCu: LD A,2 + JR Set1 +SetRCu: LD A,1 + JR Set1 +SetNo: XOR A ;this one WILL shut it up... + JR Set2 +Set1: PUSH AF ;...otherwise, do not DEcrease previous requests + EX (SP),HL + LD A,(ShoFlg) + CP H + EX (SP),HL + JR NC,Set3 + POP AF +Set2: LD (ShoFlg),A + RET +Set3: POP AF + RET +; +SmlDly: LD A,(Timer) + LD B,A + LD C,1 + JP BDlyLp +; +ScrUDx: LD A,0C9H ;(RET) + LD (UpLft),A + CALL ScrlUD + CALL NC,SmlDly ; delay if scrolled + LD A,11H ;(LD DE,nnnn) + LD (UpLft),A + RET +; +ScrlU2: LD HL,DelL + CALL ScrlUD + JR C,SetAl ; no scroll + JR SetCu +; +ScrlU: LD HL,DelL + JR ScrlX +; +EdgeU: LD A,(Vert) + DEC A ;first line: scroll + RET NZ +ScrlD: LD HL,InsL +ScrlX: CALL ScrlUD + JR C,SetAl ; no scroll + CALL SmlDly + JR SetCu +ScrlUD: PUSH HL ;[common sbr, used in one-liners too] + CALL TestCu + CALL NZ,ShoCu1 + LD A,(NoHdrF) ;canNOT do this if header is suppressed + LD HL,OddDel ; and ins/del specific to ln 1. + AND (HL) + LD HL,WinFlg ; or if Windowing (in any event) + OR (HL) + POP HL + JR NZ,NoScrl + PUSH HL + CALL UpLft + POP HL + CALL CtlStr ;do it + RET C ;(maybe couldn't) + LD A,(OddDel) + OR A + CALL NZ,RulFix + RET +NoScrl: SCF ; didn't scroll + RET +; +; Set flag for redisplay due to arrow keys +; +EdgeL: LD A,(Vert) + DEC A + RET NZ + LD A,(CurCol) + DEC A + RET NZ + JR ScrlD ;scroll if at top left +EdgeR: CALL Fetch + JR Z,ER01 + LD A,(Horiz) ;not CR: if off right edge, scroll + LD HL,View + CP (HL) + JR Z,HorScl + RET +ER01: LD A,(Vert) ;CR: if at bot right, scroll + LD HL,TxtLns + CP (HL) + JP Z,ScrlU +EdgeD: LD A,(Vert) + LD HL,TxtLns + CP (HL) + JP Z,ScrlU ;last line: scroll + RET +; +;Watch for horizontal scroll +; +IfScl: LD A,(NSkip) ;request scroll if already scrolled + OR A + RET Z +HorScl: CALL SetCu ;request scroll + XOR A + LD (HorFlg),A + RET +; +;Postpone display for speed +; +HoldCu: LD A,0FFH ;save if busy + LD (CuFlg),A + RET +HoldSc: LD A,0FFH + LD (ScFlg),A + RET +TestSc: LD HL,ScFlg ;test & reset postponement + JR TestX +TestCu: LD HL,CuFlg +TestX: XOR A ;(ret with Z if none) + ADD A,(HL) + LD (HL),0 + RET +; +; Position cursor for input +; +Cursr: CALL PosCur ;turn on cursor + CALL Fetch + RET NZ + LD A,(HCRFlg) ;oops, on a CR + OR A ;HCRs showing? + RET Z + CALL FetchB ;got to fix HCR flag + LD E,' ' ;kludge to " " or "<" + CP E + JR Z,Csr01 + CALL NdCnt + JR C,Csr01 + LD E,'<' +Csr01: CALL XPutCh + LD E,BS + JP PutCh +; +; +; MESSAGES +; +ErrTab: DW 0,MSG1,MSG2,MSG3,MSG4,MSG4,MSG7,MSG7,MSG8,MSG9 +; +MSG1: DB 'Ou','t'+X,'o','f'+X,'Memory',0 +MSG2: DB 'Invali','d'+X,'Key',0 +MSG3: DB 'I/','O'+X ;(fall through to 7) +MSG7: DB 'Error',0 +MSG4: DB 'No','t'+X,'Found',0 +MSG8: DB 'Synta','x'+X,'Error',0 ;(note 5,6 not used) +MSG9: DB 'Canno','t'+X,'Reformat',0 ;(note error 10 has no MSG) +; +NameQ: DB 'Name',':'+X,0 +ReadQ: DB 'Read',':'+X,0 +WritQ: DB 'Write',':'+X,0 +EraQ: DB 'Erase',':'+X,0 +LoadQ: DB 'Load',':'+X,0 +FindQ: DB 'Find',':'+X,0 +ChgQ: DB 'Chang','e'+X,'to',':'+X,0 +DirQ: DB 'Dir',':'+X,0 +PrtQ: DB 'Options',':'+X,0 +PgLnQ: DB 'Length',':'+X,0 +ColQ: DB 'Column',':'+X,0 +PageQ: DB 'Page',':'+X,0 +LineQ: DB 'Line',':'+X,0 +MacroQ: DB 'Macro',':'+X,0 +RptcQ: DB 'Repea','t'+X,'coun','t'+X,'([Q],0-9/*)',':'+X,0 +KeyQ: DB 'Ke','y'+X,'numbe','r'+X,'([N/Q],0-9)',':'+X,0 +QuitQ: DB 'Abando','n'+X,'changes','?'+X,'(Y/N)',':'+X,0 +UnchgQ: DB 'Unchanged',';'+X,'save','?'+X,'(Y/N)',':'+X,0 +; +; Changed: Q File size: NNNNN Memory used: NNNNN Free: NNNNN +InfMsg: DB CR + DB ' '+X,'Changed',':'+X +ModQQQ: DB 'Q',X,7,'Fil','e'+X,'size',':'+X +SizNNN: DB 'NNNNN',X,5,'Memor','y'+X,'used',':'+X +UsdNNN: DB 'NNNNN',X,5,'Free',':'+X +FreNNN: DB 'NNNNN',CR,0 +; +; [Menus disabled; see VDE.DOC or .QRF] +; [See VDE.DOC and .QRF for help] +; +HlpMsg: DB X,26,'[Menu','s'+X,'disabled',';'+X,'se','e'+X + DB 'Manual]',CR,0 +; +;A4/DOC:FILENAME.TYP /A Pg 1 Ln 1 Cl 51 INS vt by AO DS scr top ^QY del to EOL ^QF Find +; ^QP to Place mk ^Q scr bot ^QDel " to BOL ^QA replAce +; ^QR goto TOF ^Q ln start ^QT del to char ^QP to last cursor +; ^QC goto EOF ^Q ln end ^QU UNdel line ^QI goto pg/ln +; ^QQ goto ZCPR queue line +; +QMenu: DB X,4,'^Q','B'+X,'got','o'+X,'Block',X,4,'^Q'+X,'sc','r'+X,'top' + DB X,5,'^Q','Y'+X,'de','l'+X,'t','o'+X,'EOL',X,4,'^Q','F'+X,'Find',CR + DB X,4,'^Q','Z'+X,'t','o'+X,'plac','e'+X,'mk',X,3,'^Q'+X,'sc' + DB 'r'+X,'bot',X,5,'^QDe','l'+X,'"'+X,'t','o'+X,'BOL',X,4,'^Q','A'+X + DB 'replAce',CR + DB X,4,'^Q','R'+X,'got','o'+X,'TOF',X,6,'^Q'+X,'l','n'+X,'start' + DB X,4,'^Q','T'+X,'de','l'+X,'t','o'+X,'char',X,3,'^Q','P'+X,'t','o'+X + DB 'las','t'+X,'cursor',CR + DB X,4,'^Q','C'+X,'got','o'+X,'EOF',X,6,'^Q'+X,'l','n'+X,'end' + DB X,6,'^Q','U'+X,'UNde','l'+X,'line',X,4,'^Q','I'+X,'got','o'+X + DB 'Pg/Ln',CR + DB X,'(^Q','Q'+X,'got','o'+X,'ZCP','R'+X,'queu','e'+X,'line',CR,0 +; +;^OL,R marg set ^OI tab set ^OP Page length ^O make top ln ^OA Auto-in +; ^OX marg rel ^ON tab clr ^OS dbl Spacing ^OW Window ^OQ Quiet +; ^OC Center ^OV Vari tabs ^OH Hyphenation ^OJ proportional +; ^OF Flush rt ^OT ruler ^OD Display CRs ^OZ Zap screen +; +OMenu: DB '^OL,','R'+X,'mar','g'+X,'set',X,2,'^O','I'+X,'ta','b'+X,'set' + DB X,4,'^O','P'+X,'Pag','e'+X,'length',X,2 + DB '^O'+X,'mak','e'+X,'to','p'+X,'ln',X,2,'^O','A'+X,'Auto-in',CR + DB X,2,'^O','X'+X,'mar','g'+X,'rel',X,2,'^O','N'+X,'ta','b'+X,'clr' + DB X,4,'^O','S'+X,'db','l'+X,'Spacing',X,4,'^O','W'+X,'Window',X,7 + DB '^O','Q'+X,'Quiet',CR + DB X,2,'^O','C'+X,'Center',X,4,'^O','V'+X,'Var','i'+X,'tabs' + DB X,2,'^O','H'+X,'Hyphenation',X,4,'^O','J'+X,'proportional',CR + DB X,2,'^O','F'+X,'Flus','h'+X,'rt',X,2,'^O','T'+X,'ruler' + DB X,6,'^O','D'+X,'Displa','y'+X,'CRs' + DB X,4,'^O','Z'+X,'Za','p'+X,'screen',CR,' ',CR,0 +; + DS 4 +MnuEnd: ;menus end here, text can begin + END + \ No newline at end of file diff --git a/Source/Apps/ZDE/zde16a.pat b/Source/Apps/ZDE/zde16a.pat new file mode 100644 index 00000000..e4520856 --- /dev/null +++ b/Source/Apps/ZDE/zde16a.pat @@ -0,0 +1,102 @@ +; This patch file modifies the officially-distributed .COM file +; for ZDE Ver 1.6 (copyright by Carson Wilson) to: +; - Correct a bug which did not preserve create times when +; editing files > 1 extent. +; - Use an apparently 'dead' byte in the configuration area as +; a configuration flag to allow disabling the 'Auto-Indent' +; feature which was always 'on' in ZDE1.6. +; +; With the second change, you may configure the 'Auto-Indent' +; feature to be active (as distributed) or disabled (as this patch +; is configured) by altering the DB at label 'AIDflt' in the +; second part of this patch file below. +; +; Assemble this file to a .HEX file (example uses ZMAC) as: +; +; ZMAC ZDE16A.PAT /H +; +; then overlay the resulting ZDE16.HEX onto ZDE16.COM with MYLOAD +; (or equivalent) as: +; +; MYLOAD ZDE.COM=ZDE.COM,ZDE16.HEX +; +; The resulting ZDE.COM will be identified as 'ZDE 1.6a' in the +; text identification string near the beginning of the .COM file. +; +; Harold F. Bower, 18 July 2001. +; +; CP/M Standard Equates +; +BDOS EQU 0005H +FCB EQU 005CH +DMA EQU 0080H +TPA EQU 0100H +; +SDMA EQU 26 ; CP/M Function to set DMA Address +; +; Needed locations within ZDE 1.6 +; +Fill EQU TPA+0F8BH ; For Date Patch +TimBuf EQU TPA+3B3FH ; " " " +; +VTFlg EQU TPA+3ADAH ; For Auto-Ins Patch +HCRFlg EQU TPA+3AE3H ; " " " " +LfMarg EQU TPA+3AFDH ; " " " " +; +; ----------- Begin Patch File ----------- +; +; --- Fix Create Time Stamp Preservation Error --- + + ORG TPA+0029H + ; was: + DB 'a, (C)' ; DB ', Copr.' + ORG TPA+2461H + ; was: + LD (FCB+13),A ; CALL ClUsrF +; + ORG TPA+2F10H + ; was: + LD B,4 ; CALL ClUsrF + CALL ClUsrF ; LD DE,TimBuf + LD DE,TimBuf ; LD C,SDMA + CALL SetDMA ; CALL BDOS +; + ORG TPA+30AAH + ; was: + LD DE,DMA ; LD C,SDMA +SetDMA: LD C,SDMA ; LD DE,DMA +; + ORG TPA+30B4H + ; was: +ClUsrF: XOR A ; XOR A + EX DE,HL ; LD (FCB+13),A + JP Fill ; RET +; +; --- Usurp Config Flag for Auto-Insert use, sense on startup --- +; + ORG TPA+0057H + ; was: 0FFH +AIDflt: DB 00H ; Set Desired default (0=Off, FF=On) +; + ORG TPA+262AH + ; was: + LD (LfMarg),HL ; LD HL,0101H + XOR A ; LD (LfMarg),HL + LD (VTFlg),A ; XOR A + LD (HCRFlg),A ; LD (VTFlg),A + NOP ; LD (HCRFlg),A + LD A,(AIDflt) ; DEC A +; + ORG TPA+2711H + ; was: + NOP ; LD A,(0157H) {Unknown Use} + NOP ; OR A + NOP ; JP Z,Error2 + NOP + NOP + NOP + NOP +; +;------------ End of Patch File ------------ + END + \ No newline at end of file diff --git a/Source/Apps/ZDE/zde17.z80 b/Source/Apps/ZDE/zde17.z80 new file mode 100644 index 00000000..7872fbf0 --- /dev/null +++ b/Source/Apps/ZDE/zde17.z80 @@ -0,0 +1,8111 @@ + ;Assembles with Al Hawley's ZMAC as is + ;Rename to ZDE17.Z80 for ZASM (Cromemco ASMB) +; .Z80 ;Uncomment these two lines and rename +; ASEG ;to ZDE17.MAC for M80 + ;(use RELHEX to convert ZDE17.REL to ZDE17.HEX) +; +;*** ZDE assembly sequence +; +CR EQU 0DH ;ASCII stuff +LF EQU 0AH +FF EQU 0CH +BS EQU 08H +TAB EQU 09H +ESC EQU 1BH +DEL EQU 7FH +BEL EQU 07H +EOF EQU 1AH +X EQU 80H ;hibit +; +BDOSep EQU 0005h ;BDOS stuff +FCB EQU 005Ch +FCBt1 EQU FCB+9 +FCBex EQU FCB+12 +FCBs1 EQU FCB+13 +FCBd0 EQU FCB+16 +FCBcr EQU FCB+32 +FCBr0 EQU FCB+33 +FCBr1 EQU FCB+34 +FCBr2 EQU FCB+35 +DMA EQU 0080h +; +LSTO EQU 5 +UCON EQU 6 +CPMV EQU 12 +RSTD EQU 13 +SELD EQU 14 +FOPN EQU 15 +FCLO EQU 16 +SRCH EQU 17 +SRCN EQU 18 +FDEL EQU 19 +RSEQ EQU 20 +WSEQ EQU 21 +FMAK EQU 22 +FREN EQU 23 +GDRV EQU 25 +SDMA EQU 26 +USRN EQU 32 +RSTV EQU 37 +ERRM EQU 45 +DOSV EQU 48 +FTRU EQU 99 +GETF EQU 100 +SETF EQU 101 +GETS EQU 102 +SETS EQU 103 +; +Z3NdrL EQU 16 ; length of NDR dir/pwdstring +Z3NdrM EQU 8 ; length of NDR name to match +Z3NDR EQU 0015H ; offset to NDR address in Z3ENV +Z3MSG EQU 0022H +MsgUsr EQU 64 ; User area offset in message buffer +MsgNmU EQU 16 ; # of user registers +TPAful EQU 12 ; Z33 TPA full error code +ErrBit EQU 00000010B +EcpBit EQU 00000100B +ExtBit EQU 00001000B +; +;ErrSta is the value to be returned in the Z33 Message Buffer command +;status to inform the command processor that an error has occurred in +;an external program and that the error handler should be invoked. +; +ErrSta EQU ErrBit+EcpBit+ExtBit +; +;*** ZDE.ASM - Z-System Display Editor +;*** Universal Version - (c)1988 Eric Meyer +;*** Z-System Version - (c)1989 Carson Wilson +; ------------------- +; VDE,VDE-2 - 9-12/84 - Enhanced VDO, added functions +; VDE-OS,OX - 7/85-1/86 - Small additions and fixes +; VDE-PX - 7-9/85 - Epson Geneva terminal version +; VDE 1.2-3 - 9/85-1/86 - Generic terminal version +; VDE/M 2.0 - 4/86 - Generic memory map version; CP/M+ support; additions +; 2.1 - 6/86 - New Keys 0-9; window; undo; directory; new pagination, +; compression, block marker, scroll; etc. +; 2.2 - 8/86 - WS-like commands; left mrgn, hyphenation; macros +; 2.3 - 9/86 - VINSTALL; Print options; word fns; real ^QA; RstDrv +; 2.4 - 1/87 - vidRAM/window redone; "W" mode; ^OZ,^QP; block print +; 2.5 - 3/87 - User#s; "N" mode; ^OS, ^OV/+/-; new block fns; hard-CRs +; 2.6 - 7/87 - Allow blank filename; ^U abort; new toggles; ruler; +; ^O; AltBit fixes; works w/o curpos; key buffer; faster +; scrolling; case insensitive searches; no fake "VIDRAM" +; 2.61 - 8/87 - Bug fixes (incl FastFi), improved hyphenation +; 2.62 - 11/87 - ^JKL synonyms; ^W prefix; ^OH; several small fixes +; 2.63 - 1/88 - ^KV; WS style ^W/^Z; chgs to ^OP, ^OI/N, word fns +; 2.64 - 3/88 - ^OQ,^QT,^QI; ^KD; ^QA fixes; dbl spc; top margin; +; backward find; ShoRCu +; 2.65 - 4/88 - ^OI/N args; Esc-TAB; ^OA; menu removal; minor fixes +; 2.66 - 6/24/88 - Printer margins; Minor fixes. LAST RELEASE! +; 2.67b - 10/14/88 - Minor fixes +; ZDE 1.0 - 3/10/89 - Z-System Display Editor +; 1.3 - 8/26/89 +; 1.6 - 6/2/90 +; 1.6 - 11/19/20 - ZDE 1.6 source reconstituted using VDE 2.67 +; source as a guide +; 1.7 - 11/21/20 - Incorporated Al Hawley's timestamp fixes +; ------------------- +; + ORG 0100H +; + JP Start ;Entry and exit vectors + DB 'Z3ENV' + DB 1 +Z3Env: DW 0 +Boot: JP 0 + DW 0 +; +;Following VINSTALL data MUST be at 0110-0121 +; + DW 1006H ;Version compatibility + DW UsrPat + DB UPatL + DW PSTbl + DB PsL + DW MnuSt + DW KMnuSt + DW EMnuSt + DW OMnuSt + DW QMnuSt + ;version message (28 chars, used in menu) +; [----5----10---15---20---25--] +VersID: DB 'ZDE 1.7, Copr. 1990 C.Wilson',0 +; +; +;USER PATCHABLE VALUES +; + ORG 0140H +BAKFlg: DB 0FFH ;0140H - create BAK files (y/n) +DFMode: DB 'A' ;default file modem W/A/N +FDflt1: DB 'Z80N' ;1st default override +FDflt2: DB 'WS W' ;2nd +FDflt3: DB 'CMDN' ;3rd +FDflt4: DB 'LIBN' ;4th +InsFlg: DB 0FFH ;defulat insert on (y/n) +RulFlg: DB 0FFH ;default rules on (y/n) +HCDflt: DB 0FFH ;default HCR disp on (y/n) +HypFlg: DB 0FFH ;enable hyphenation (y/n) +PSFlg: DB 0 ;default proportional flag (y/n) +PSokFl: DB 0FFH ;default allow proportional flag (y/n) +DfltLM: DB 1 ;left margin column (1=OFF) +DfltRM: DB 65 ;right margin column (1=OFF) +Ovlap: DB 2 ;scroll overlap (0=none) +DirSys: DB 0 ;include SYS files (y/n) +FixDsk: DB '@@' ;fixed drives +Ring: DB 0FFH ;error ring bell (y/n) +Help: DB 0FFH ;use help menus (y/n) +AltHdr: DB 0FFH ;use alt video in header (y/n) +NoHdrF: DB 0 ;suppress header +MHz: DB 40H ;clock speed (40h=4MHz) +Timer: DB 38H ;horiz scroll delay (01..FF) +TabCnt: DB 7 ;hard tab cols -1 (1/3/7/15) +VTList: DB 6,11,16,21 ;variable tab columns (8) + DB 0,0,0,0 +VTNum EQU $-VTList +WildCd: DB EOF ;wildcard character +BlkChr: DB 0 ;block characters (^@) +TogTbl: DB 02H,04H,13H,19H ;toggles ^B,^D[^T],^S,^Y +NTgTbl: DB 11H,17H,5,12H ;switches ^Q,^W,^E,^R (last 015C) +; +;INSTALLATION +; + ORG 180H +Z3tcap: DB 'Generic CRT ' ;ID + ORG 190H +View: DB 80 ;viewable columns (max 128) +AuWrap: DB 0FFH ;does autowrap cursor +Lines: DB 24 ;lines +UsrKys: DB 0FFH ;DEL key + DB 0FFH ;arrow up + DB 0FFH ;arrow down + DB 0FFH ;arrow right + DB 0FFH ;arrow left + DB 0 +CIL: DB 0,0,0,0,0,0,0 ;clear to end of line, 6 bytes +TInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal init, 7 bytes +TUInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal uninit +AltOn: DB 0,0,0,0,0,0,0 ;alt video on, 6 bytes +AltOff: DB 0,0,0,0,0,0,0 ;alt video off +AltBit: DB 0 ;high bit gives alt video? +Filter: DB 7FH ;highest ASCII to send to screen +PosMod: DB 'N' ;curpos mode (Std/Rev/ANSI/None) +PCu: DB 1EH,0,0CH,0 ;position cursor to (0,0) +PosDly: DB 0 ;delay after curpos (00-FF) +InsL: DB 0,0,0,0,0,0,0 ;insert line [1], 6 bytes +DelL: DB 0,0,0,0,0,0,0 ;delete line [1], 6 byts +OddDel: DB 0 ;ins/del line specific? +CsrOff: DB 0,0,0,0,0,0,0 ;cursor off +CurOn: DB 0,0,0,0,0,0,0 ;cursor on +; + ORG 01F0H ;Printer codes + DB 'Teletype ' ;ID + ORG 0200H +UseLF: DB 0FFH ;use LF after CR in print? +FormL: DB 54 ;form length (0=no pag) +PTMarg: DB 0 ;top margin skip +DotPO: DB 0 ;left margin skip +PInit: ;printer init, 19 bytes + ORG 0218H +PUInit: ;printer uninit, 7 bytes + ORG 0220H +PCodes: DB 0,0,0,0,0,0,0,0 ;^B toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^T [^D] toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^S toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^Y toggle on + DB 0,0,0,0,0,0,0,0 ;...and off +UCodes: DB 0,0,0,0,0,0,0,0 ;sw 1 (^Q) + DB 0,0,0,0,0,0,0,0 ;sw 2 (^W) + DB 0,0,0,0,0,0,0,0 ;sw 3 (^E) + DB 0,0,0,0,0,0,0,0 ;sw 4 (^R) +; + ORG 0280H +UsrPat: ;0280-02AFH - User Patch Area +;(Can extend back into UCodes section if fewer switches used) +; + ORG 02B0H ;02B0-030EH - Proportinal table +UPatL EQU $-UsrPat +PSTbl: DB 0,-12, 0, 0, 0, 6, 6,-12 ;" "-";" + DB -6, -6, 0, 0,-12, 0,-12, 0 ;"("-"/" + DB 0, 0, 0, 0, 0, 0, 0, 0 ;"0"-"7" + DB 0, 0,-12,-12, 0, 0, 0, 0 ;"8"-"?" + DB 6, 6, 6, 6, 6, 6, 6, 6 ;"@"-"G" + DB 6, -6, 0, 6, 6, 12, 6, 6 ;"H"-"O" + DB 6, 6, 6, 6, 6, 12, 6, 12 ;"P"-"W" + DB 6, 6, 0, -6, 0, -6, 0, 0 ;"X"-"_" + DB -12, 0, 6, 0, 6, 0, -6, 6 ;"'"-"g" + DB 6,-12, -6, 6,-12, 12, 6, 0 ;"h"-"o" + DB 6, 6, 0, 0, -6, 6, 6, 12 ;"p"-"w" + DB 0, 6, 0, -6,-12, -6, 0 ;"x"-"~" +PsL EQU $-PSTbl +; + ORG 0310H ;0310-04AFH - Macro keys +Keys: DS 2 ;free count (VDE does this) + DS 510 +KT: +; +; +;----- EXECUTION BEGINS HERE ------- +; + ORG 0510H +; +Start: SUB A ;check for Z80 + RET PE + LD SP,Stack + LD HL,Data ;zero out data area + LD DE,Data+1 + LD BC,DataLn-1 + LD (HL),0 + LDIR + LD C,CPMV + CALL BDOSep + LD (DOSVer+1),A ;CP/M version + CP 30H + JR NC,ItsCP3 + LD C,DOSV + CALL BDOSep ; what kind of enhanced BDOS + LD A,H + CP 'S' + JR Z,ZxDOS + CP 'D' + JR NZ,ItsCP3 +ZxDOS: LD (DOSVer+1),A ; store ZS/ZDDOS version + LD C,GETF ; get ZSDOS flags + CALL BDOSep + LD (ZDflgs+1),HL + EX DE,HL + RES 1,E ; public files are R/O + LD C,SETF + CALL BDOSep ; set ZSDOS flags +ItsCP3: CALL DOSVer + LD C,ERRM ; set action on hardware error + LD E,0FEH ; return error code to program + CALL NC,BDOSep ; for anything other than CP/M 2.2 + LD C,GDRV + CALL BDOSep ;save logged drive + LD (CurDsk),A + INC A + LD (FCB),A ; store A=1..P=16 in FCB->drive + LD C,USRN ;and user + LD E,0FFH + CALL BDOSep + LD (CurUsr),A + LD (FCBU),A + LD A,(Lines) + LD (PhysLn),A + CALL AdjLns + LD A,(FormL) + LD (PgLen),A + LD HL,(DfltLM) + LD (LfMarg),HL + LD A,(BlkChr) + LD (BadTbl),A + LD A,(UseLF) + CPL + OR LF + LD (LFChr),A + LD HL,MacStr + DEC (HL) ;make a FF terminator + XOR A ;a bad load will exit and invoke Z33's + LD (BadLdX+1),A ;error handler +; + LD HL,DMA + LD A,(HL) + INC HL + CALL Parse ;parse command line +; + CALL VerKey ;verify keys + LD HL,TInit + CALL CtlStr ;Clear and home cursor + JR Edit ;start editing. +; +;Clear it all out and start over. +; +Restrt: LD A,1 ;a bad load will not exit and invoke + LD (BadLdX+1),A ;Z33's error handler + LD HL,LoadQ + CALL NewNam + LD A,(EdErr) ;bad name? + OR A + JR NZ,BadLdX +; +;Start editing a File +; +Edit: CALL IniRAM ;initialize memory + CALL DfltM ;adjust defaults + CALL DoHdr ;show header + CALL Top ;Start at TOF + CALL Error0 ;No errors + LD A,(FCB+1) + CP ' ' ;Filename blank? + JR Z,Edit1 + CALL SavNam ;save it for LoadIt kludge + CALL LoadIt ;Get input file + LD A,(EdErr) + CP 1 ;is it too big? + JR NZ,Edit1 +BadLdX: LD A,0 ;a non-zero value will set up Z33's message + OR A ;buffer to have the Z33 error handler handle + JR NZ,BadLd ;the 'TPA full' condition when we exit + LD BC,Z3MSG + CALL Z3EAdr + JR Z,BadLd + LD H,B + LD L,C + LD (HL),TPAful ; Z3MSG error byte: file too big + INC HL + INC HL + INC HL ; point HL at Z3MSG command status byte + LD (HL),ErrSta ; error, ECP running, external invocation + JP QuitY +BadLd: CALL DoErr ;Too big, or bad name + CALL BlkFCB ;(Other error means new file) + JR Edit +Edit1: LD A,(MSIFlg) ;set up BAKflag + LD HL,BAKFlg + AND (HL) + LD (FilFlg),A + XOR A + LD (Modify),A +; +Reset: LD SP,Stack ;recover from ^U prompt abort + CALL ShoLn1 +; +; +;MAIN LOOP: SHOW TEXT, GET KEY +; +Ready: CALL Orient ;Get bearings + LD HL,(OldLin) ; ### + LD (SavLin),HL ; ### + LD A,(OldCol) ; ### + LD (SavCol),A ; ### + LD A,(MacFlg) ; ### + OR A ; ### + JR NZ,RdyMac ; ### + LD HL,(CurLin) ; ### + LD (OldLin),HL ; ### + LD A,(CurCol) ; ### + LD (OldCol),A ; ### +RdyMac: CALL ShoTx ; then show text as needed + CALL Cursr ;position cursor + CALL TRptKy ;Get input + PUSH AF + CALL Error0 ;Clear error indicator + CALL SetNo ;default NO redisp + POP AF + CALL AdjKey ;translate arrows/DEL +; +DoKey: CALL Case ;try to match control code? + DB MnuLn/3 + DW IChar ;Default : Insert character +MnuSt EQU $ + DB 0 ;(internal use: null key) + DW CKCan + DB 80H ;DEL + DW Delete + DB 81H ;Up arrow + DW Up + DB 82H ;Down + DW Down + DB 83H ;Right + DW Right + DB 84H ;Left + DW Left + DB ESC + DW Escape + DB '^'-40H + DW UpLow + DB '\'-40H + DW Repeat ;Synonym for ^L + DB 'A'-40H + DW WordLf + DB 'B'-40H + DW Reform + DB 'C'-40H + DW PageF + DB 'F'-40H + DW WordRt + DB 'G'-40H + DW EChar + DB 'I'-40H + DW TabKey + DB 'J'-40H + DW DoMnu + DB 'K'-40H + DW CKKey + DB 'L'-40H + DW Repeat + DB 'M'-40H + DW ICR + DB 'N'-40H + DW ICRA + DB 'O'-40H + DW Onscrn + DB 'P'-40H + DW CtlP + DB 'Q'-40H + DW Quick + DB 'R'-40H + DW PageB + DB 'T'-40H + DW WordDl + DB 'U'-40H + DW Undel + DB 'V'-40H + DW IToggl + DB 'W'-40H + DW Scr1LU + DB 'Y'-40H + DW Eline + DB 'Z'-40H + DW Scr1LD +MnuLn EQU $-MnuSt +; +Sk1Ed: LD A,(EdErr) ;Check for error, repeat main loop + OR A + CALL NZ,DoErr + JP Ready +; +;Block commands: ^K toggle is on +; +CKKey: LD HL,CKTog + CALL Prefix +CKSyn: CALL XCase ;Entry for ESC synonyms + CALL Case + DB KMnuLn/3 + DW Error2 ;complain if unknown +KMnuSt EQU $ + DB 'B'-40h + DW Block + DB 'C'-40h + DW Copy + DB 'D'-40h + DW Done + DB 'E'-40h + DW Era + DB 'F'-40h + DW Dir + DB 'H'-40h + DW DoMnu + DB 'I'-40h + DW Info + DB 'K'-40h + DW Termin + DB 'L'-40h + DW Load + DB 'N'-40h + DW ChgNam + DB 'P'-40h + DW Print + DB 'Q'-40h + DW Quit + DB 'R'-40h + DW Read + DB 'S'-40h + DW Save + DB 'U'-40h + DW Unmark + DB 'V'-40h + DW MovBlk + DB 'W'-40h + DW Write + DB 'X'-40h + DW Exit + DB 'Y'-40h + DW EBlock + DB ESC + DW CKCan + DB ' ' + DW CKCan +KMnuLn EQU $-KMnuSt +CKCan: RET +; +;ESC commands: ESC toggle is on. +; +Escape: LD HL,ESCTog + CALL Prefix + CALL AdjKey + CALL UCase + CP '0' + JR C,Esc01 ;macro Keys: special case + CP '9'+1 + JP C,UseKey +Esc01: CALL Case + DB EMnuLn/3 + DW CKSyn ;default: ^K synonym +EMnuSt EQU $ + DB 81H ;Up arrow + DW ShftU + DB 82H ;Down + DW ShftD + DB 83H ;Right + DW ShftR + DB 84H ;Left + DW ShftL + DB '[' ;ANSI cursor sequences + DW ANSIcu + DB TAB + DW TaBack + DB 'M' + DW DoMac + DB '#' + DW MacKey + DB '!' ;macro prog stmts + DW MacJmp + DB '=' + DW MacTst + DB '~' + DW MacTsX + DB '+' + DW ChainK + DB ';' + DW Wait +EMnuLn EQU $-EMnuSt + RET +; +;Onscreen commands. ^O toggle is on. +; +Onscrn: LD HL,COTog + CALL Prefix + CALL XCase ;force to ctl + CALL AdjKUp ;adjust UP ARROW ONLY + CALL Case ;What function? + DB OMnuLn/3 + DW Error2 ;complain if unknown +OMnuSt EQU $ + DB 81H ;up + DW MakTop + DB 'A'-40h + DW AITog + DB 'C'-40h + DW Center + DB 'D'-40h + DW HCRTog + DB 'F'-40h + DW Center ;same fn as 'C' + DB 'H'-40h + DW HypTog + DB 'I'-40h + DW VTSet + DB 'J'-40h + DW PSTog + DB 'L'-40h + DW SetLM + DB 'N'-40h + DW VTClr + DB 'P'-40h + DW PgSet + DB 'Q'-40h + DW NoHdr + DB 'R'-40h + DW SetRM + DB 'S'-40h + DW DblTog + DB 'T'-40h + DW Ruler + DB 'V'-40h + DW VTTog + DB 'W'-40h + DW Window + DB 'X'-40h + DW RelM + DB 'Z'-40h + DW Blank + DB ESC + DW COCan + DB ' ' + DW COCan +OMnuLn EQU $-OMnuSt +COCan: RET +; +;Quick commands. ^Q toggle is on. +; +Quick: LD HL,CQTog + CALL Prefix + CALL XCase + CALL AdjKey ;translate arrow/DEL + CALL Case ;What function? + DB QMnuLn/3 + DW Error2 ;complain if unknown +QMnuSt EQU $ + DB 80H ;DEL + DW EBLine + DB 81H ;Up arrow + DW QuikUp + DB 82H ;Down + DW QuikDn + DB 83H ;Right + DW QuikRt + DB 84H ;Left + DW QuikLf + DB 'A'-40h + DW Rplace + DB 'B'-40h + DW QikBlk + DB 'C'-40h + DW Bottom + DB 'F'-40h + DW Find + DB 'Q'-40h + DW Queue + DB 'I'-40h + DW ZipTo + DB 'P'-40h + DW QuikLc + DB 'R'-40h + DW Top + DB 'T'-40h + DW E2Char + DB 'U'-40h + DW UndlLn + DB 'Y'-40h + DW EOLine + DB 'Z'-40h + DW QuikMk + DB ESC + DW CQCan + DB ' ' + DW CQCan +QMnuLn EQU $-QMnuSt +CQCan: RET +; +; +; +Prefix: PUSH HL ;show prefix, get suffix + LD DE,DspEsc + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + LD B,1 + CALL BBlank + LD DE,DspEsQ ;position cursor + CALL GoTo + CALL RptKey ;get suffix + PUSH AF + LD A,(NoHdrF) + OR A + JR NZ,PrefNH + LD DE,DspEsc + CALL GoTo + LD B,4 ;clean up + CALL BBlank + CALL UnAlt + POP AF + RET +PrefNH: CALL UnAlt ;(if no header) + CALL ShoLn1 + CALL RulFix + POP AF + RET +; +; +;Return to CP/M ... With or without saving +; +Exit: CALL Save ;Save the file + LD A,(EdErr) ;Was it ok? + OR A + RET NZ ;No, do not quit + JR QuitY1 +; +Done: CALL Save ;Save, and load new + LD A,(EdErr) + OR A + RET NZ + JP Restrt +; +Quit: LD A,(Modify) ;Quit to CP/M + OR A + JR Z,QuitY1 + LD HL,QuitQ + CALL Prompt + CALL Confrm ;warn if file changed... + JP NZ,ShoLn1 +QuitY1: XOR A ;### + LD (WinFlg),A ;### + CALL AdjLns ;### + LD BC,Z3MSG ;### + CALL Z3EAdr ;### + JR Z,QuitY ;### + LD HL,MsgUsr ;### offset to user area in message buffers + ADD HL,BC ;### + LD DE,CurLin ;### store the current line# in the Z3 + EX DE,HL ;### + LD BC,2 ;### + LDIR ;### +QuitY: LD HL,TUInit ;Clear screen + CALL CtlStr + LD A,(CurDsk) ;restore logged disk + LD E,A + LD C,SELD + CALL BDOS + LD A,(CurUsr) ;and user + LD E,A + LD C,USRN + CALL BDOSep + CALL DOSVer + JP C,Boot ;### restart if CP/M 2.2 + CP 'S' ;### + JR Z,ZSErrR ;### + CP 'D' ;### + JR NZ,CPM3xt ;### +ZSErrR: LD C,SETF ;### restore ZxDOS flags +ZDflgs: LD DE,0 ;### + CALL BDOSep ;### +CPM3xt: LD C,ERRM ;### reset ZxDOS, CP/M 3 error mode + LD E,0 ;### + CALL BDOSep ;### + JP Boot ;### and restart +; +;Error handler +; +DoErr: CALL Loud ;Show error message, wait for ESC + CALL SetNo + LD A,(MacFlg) + OR A ;### + CALL NZ,RstI1x ;### + XOR A ;### + LD (MacFlg),A ;### kill any running macro + LD A,(EdErr) + CP 10 + JP NC,SetAl ;error 10 does NOT show + LD A,(Ring) + OR A + LD E,BEL + CALL NZ,ShutUp ; ring bell + CALL MakAlt + CALL UpLft + CALL Dspl + DB X,31,'[[','['+X,0 + LD A,(EdErr) + ADD A,A ;Double the code + LD L,A + LD H,0 + LD DE,ErrTab + ADD HL,DE + LD E,(HL) ;Get msg addr from table + INC HL + LD D,(HL) + EX DE,HL + CALL DspLp ;show it + CALL DsplC + DB ' ]]]',CR,0 + CALL UnAlt + CALL ESCLp + LD A,(EdErr) + CP 1 + JR Z,DoErr2 + CP 5 + JR Z,DoErr2 + CP 9 + JP C,ShoLn1 ;(errors 2-8 need no redisp) +DoErr2: JP SetAl +ESCLp: CALL RptKey ;await ESC from console + CP ESC + RET Z + CP ' ' + JR NZ,ESCLp + RET +; +Error0: LD A,0 ;clear error (don't change flags) + JR ErrSet +Error1: LD A,1 ;error set fns + JR ErrSet +Error2: LD A,2 + JR ErrSet +Error3: LD A,3 + JR ErrSet +Error4: LD A,4 + JR ErrSet +Error5: LD A,5 ;6 currently not used + JR ErrSet +Error7: LD A,7 + JR ErrSet +Error8: LD A,8 + JR ErrSet +Error9: LD A,9 + JR ErrSet +Eror10: LD A,10 +ErrSet: LD (EdErr),A + RET +; +; +;INPUT ROUTINES +; +KeyIn: LD HL,(Timer) ;Get key, regardless + LD H,0 + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL + INC HL +KyIn1: PUSH HL + CALL KyStat + POP HL + DEC HL + JR NZ,Keybd ;read key if got one + LD A,(HorFlg) + LD E,A + LD A,(KeyFlg) + OR E + OR H + OR L ;allow redisp for horizontal scroll? + JR NZ,KyIn1 + CPL + LD (HorFlg),A ;yep (just once) + CALL ShoAll + CALL Cursr + JR KyIn1 +; +Keybd: CALL KyStat ;Get key, or 0 if none + RET Z + LD HL,ConBuf + DEC (HL) ;uncount it + INC HL + LD A,(HL) ;here it is + LD D,H + LD E,L + INC HL + LD BC,ConBufL-1 + LDIR ;remove it + AND 7FH ;strip parity + RET +; +KyStat: CALL CONSt ;Console status with buffering + JR Z,ConChk ;all quiet + LD HL,ConBuf ;got key + INC (HL) ;ok, count it + LD E,(HL) + LD D,0 + ADD HL,DE ;point there + LD (HL),A ;put it in + LD A,E + CP ConBufL ;buffer full? + JR C,ConChk +ConBsy: LD A,0C9H ;(RET) + LD (Plug),A ;plug up the console until buffer empty +ConChk: LD A,(ConBuf) ;check buffer (FAST) + OR A + RET NZ + LD (Plug),A ;buffer empty, unplug console + RET +; +CONSt: XOR A +Plug: NOP ;<--- RET plugs up console + LD E,0FFH ;console status/input + LD C,UCON + CALL BDOSep + OR A ;test for null + RET +; +KyPeek: CALL KyStat ;key available? + RET Z ;no + LD A,(ConBuf+1) ;return 1st char in buffer + AND 7FH ;strip parity + RET +; +; +Confrm: CALL RptKey ;get a Y/N answer + CALL UCase + CP 'Y' ;return Z if confirmed + RET Z + CP 'U'-40h + JR Z,IsCtlU + CP ESC ;allow this too +IsCtlU: JP Z,Reset + CP 'N' + JR NZ,Confrm +CnfNo: OR A + RET +; +;Translate four arrow keys and BS,DEL +; +AdjKey: CP BS ;First handle ^H (special case) + JR NZ,AdjK0 + LD C,80h ;make it DEL + LD HL,UsrKys + CP (HL) ;Is it installed as DEL? + JR Z,AKret + LD C,84h ;no, then it's Left arrow + CP A + JR AKret +AdjK0: LD B,5 ;Not ^H, try the rest + JR AdjK1 +AdjKUp: LD B,2 ;only do (DEL and) UP arrow +AdjK1: LD HL,UsrKys + LD DE,WSKys + LD C,7FH ;encode 80h=DEL, 81h=up, etc. +AKlp: INC C + CP (HL) + JR Z,AKret + EX DE,HL + INC DE + CP (HL) + JR Z,AKret + INC HL + DJNZ AKlp + CP C + LD C,A ;NO match: return NZ, char in A and C +AKret: LD B,A ;MATCH: return Z, code in A, char in C + LD A,C + LD C,B + RET +WSKys: DB DEL,'E'-40H,'X'-40H,'D'-40H,'S'-40H +; +; +ANSIcu: CALL RptKey ;Handle ANSI cursor keys ESC-[... + SUB 'A' + JP Z,Up + DEC A + JP Z,Down + DEC A + JP Z,Right + DEC A + JP Z,Left + JP Error2 +; +;Get string input +; +GetStr: LD A,LinLen+1 ;string length +1 +GSEnt: LD (GSlen+1),A ;(entry for GetNum and NewNam) + LD HL,DMA ;*** MUST be 0080h *** +Lp1GSx: EXX + POP HL ;word after call + PUSH HL + LD E,(HL) ;storage/recall buffer address + INC HL + LD D,(HL) + LD (GSbufA),DE + EXX +Lp1GSy: XOR A + LD (RclFlg),A +Lp1GS: LD A,L + SUB DMA ;length +GSlen: CP 0 ;<---- max length pastes in here + JR NC,GSBS ;full? + LD A,(RclFlg) + OR A + JR NZ,GSrcl + PUSH HL + CALL RptKey ;Get next input + CALL AdjKey ;translate key + POP HL + CP 80H ;corrections? DEL, + JR Z,GSBS + CP 84H ;left + JR Z,GSBS + CP 83H ;right + JR Z,GSrcl ;recall a char + CP CR ;CR ends + JR Z,GSCR + CP 'U'-40H ;^U aborts operation + JP Z,Reset + CP 'P'-40H ;^P for ctlcode + JR Z,GSctl + LD A,C ;restore orig char + CP 'X'-40H ;wipeout + JR Z,GSwipe + CP 'R'-40H + JR Z,GSrcl ;recall the last string +; +Sk1GS: LD (HL),A ;Store byte + INC HL ;Move along + CP 20H ; ctl char? + PUSH HL + JR NC,Sk2GS ;no, just a normal char + ADD A,40H ;ctls are hili letters + PUSH AF + CALL AltY + POP AF + CALL PutChA + CALL UnAltY + JR Sk3GS +Sk2GS: CALL PutChA ;show byte +Sk3GS: POP HL + JR Lp1GS +; +GSBS: CALL GSBSsb + JR Lp1GSy +GSwipe: CALL GSBSsb + JR NZ,GSwipe + JR Lp1GSx +GSBSsb: LD A,DMA ;Are we at start + CP L + RET Z ;return Z if so + DEC HL ;back up pointer + LD E,BS ;wipe out char + CALL PutCh + LD E,' ' + CALL PutCh + LD E,BS + CALL PutCh + OR 1 ;clear flags + RET +; +GSrcl: EX AF,AF' ;save original char + EXX ;save HL + LD HL,(GSbufA) ;recall buffer ptr + LD A,H + OR L + EXX ;restore HL + JP Z,Lp1GS ;no recall buffer + EXX ;recall buffer ptr in HL + LD A,(HL) ;fetch char from recall buffer + EXX ;restore HL + OR A ;any char? + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + CP 0FFH + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + EXX ;recall buffer pre in HL + INC HL ;point to next char + LD (GSbufA),HL ;update recall buffer ptr + EXX ;restore HL + EX AF,AF' ;restore original char + CP 'R'-40h ;^R? (whole string) + JR NZ,GSrclX ;no, just a single char + LD (RclFlg),A +GSrclX: EX AF,AF' ;restore char from recall buffer + JR Sk1GS ;store char +; +GSCR: LD (HL),0 ;terminator + LD A,L + SUB DMA ;Compute input length (Z=zero) + POP DE ;skip over buffer address + INC DE + INC DE + PUSH DE + RET ;HL points past end of string +; +GSctl: PUSH HL + CALL RptKey + CALL XCase + POP HL + JP Sk1GS +; +;Get numeric input (0-65535 decimal), return C if bad +; +GetNbr: PUSH BC ;BC = default if no input + LD A,5+1 + CALL GSEnt ;get up to 3 digits + DW 0 + POP DE + JR NZ,GNyes + LD B,D + LD C,E + LD A,B ;no entry, use default + OR C + RET +GNyes: LD DE,DMA ;fall thru to GetNNN +; +GetNNN: PUSH HL ;gets decimal # pointed by DE + LD H,D + LD L,E + LD B,0 +GNL: LD A,(HL) + CP '0' + JR C,GotN ;terminated by any nondigit. + CP '9'+1 + JR NC,GotN + INC HL + INC B + LD A,B + CP 5+1 + JR NC,GNErr ;5 digits max. + JR GNL +GotN: LD A,B ;okay, do them + LD BC,0 + OR A ;digits? + JR Z,GNErr + CP 2 + JR Z,Got2 + JR C,Got1 + CP 4 + JR Z,Got4 + JR C,Got3 + CP 5 + JR NZ,GNErr +Got5: LD HL,10000 + CALL GNNdig + JR C,GNErr +Got4: LD HL,1000 + CALL GNNdig + JR C,GNErr +Got3: LD HL,100 + CALL GNNdig + JR C,GNErr +Got2: LD HL,10 + CALL GNNdig + JR C,GNErr +Got1: LD HL,1 + CALL GNNdig + JR C,GNErr + POP HL + LD A,B + OR C + RET +GNErr: POP HL + SCF ;error + RET +; +GNNdig: LD A,(DE) ;do a digit: HL=power of 10 + INC DE +GNNLp: CP '0' + RET Z + DEC A + PUSH HL + ADD HL,BC + LD B,H + LD C,L + POP HL + RET C ;overflow + JR GNNLp +; +;Versions of above for 0...255 only: GetNum, GetNN take # in A +; +GetNum: LD C,A + LD B,0 + CALL GetNbr + JR GetNN1 +GetNN: CALL GetNNN +GetNN1: RET C + XOR A + OR B + JR NZ,GetNNX + OR C ;result in A, OK + RET +GetNNX: SCF ;oops, too big + RET +; +; +;Convert 16-bit number in HL to a one to five +;digit decimal number in the area pointed to by DE +; +BCDCon: LD IX,P10Tab ;Point at table + PUSH DE ;Save output pointer +BCDlp1: LD B,(IX+1) + LD C,(IX) + LD A,C ;low byte + CP 1 ;Clear carry flag + JR Z,BCDend + SBC HL,BC ;Subtract from input + JR NC,BCDok ;Got one in range + ADD HL,BC ;Restore it + INC IX + INC IX + JR BCDlp1 ;Try next one +; +BCDok: LD A,'1' + LD (DE),A ;Set initial digit +BCDlp2: SBC HL,BC ;Subtract again + JR C,BCDsk1 ;Went negative + EX DE,HL + INC (HL) ;Increment digit + EX DE,HL + JR BCDlp2 +; +BCDsk1: ADD HL,BC ;Restore it + INC DE ;Bump output + INC IX + INC IX + LD C,(IX) + LD B,(IX+1) + LD A,C + CP 1 ;Is this last entry + JR Z,BCDend + LD A,'0' + LD (DE),A + JR BCDlp2 +; +BCDend: LD A,L + OR '0' + LD (DE),A + INC DE + EX DE,HL + POP BC + SBC HL,BC ;Number filled + LD A,5 ; needed + SUB L ; to do + RET Z + ADD HL,BC ;Restore pointer +BCDlp3: LD (HL),' ' ;Clear field + INC HL + DEC A + JR NZ,BCDlp3 + RET +; +P10Tab: DW 10000,1000,100,10,1 +; +; +; +;PRINT text from memory +; +Print: LD HL,PgLen ;set defaults + XOR A + CP (HL) + JR NZ,Pr00 + INC A ;bit 0 set if no pagn +Pr00: LD (POByt),A + XOR A + LD (HdrLen),A + LD (POff),A + CPL + LD (PNum),A + LD (PrFlg),A + LD A,1 + LD (Copies),A + LD (PBeg),A + LD A,(DotPO) + LD (PrLMrg),A + LD A,(PTMarg) + LD (PrTMrg),A + LD HL,PrtQ ;options? + CALL Prompt + CALL GetStr ;get string into 80 + DW 0 +PO1st: LD DE,DMA ;point to option string +PrOlp: LD A,(DE) + INC DE + LD HL,POByt ;set up bit flags + LD BC,PrOlp + PUSH BC ;(return) + CALL UCase + CP ' ' ;eat spaces + RET Z + CP 'B' + JR Z,POBlk + CP 'D' + JR Z,PODblS + CP 'P' + JR Z,POPau + CP 'L' + JR Z,POLMrg + CP 'T' + JR Z,POTMrg + CP '*' + JR Z,POCpy + CP '^' + JR Z,POCtl + CP '@' + JR Z,POBeg + CP '#' + JR Z,PONum + CP '=' + JP Z,POPgS + CP '"' + JP Z,POHdrT + POP BC ;kill return + OR A + JP NZ,Error7 ;unexpected char + LD A,(PrFlg) + LD B,A + XOR A ;zero PrFlg + LD (PrFlg),A + OR B + JR NZ,PO1st + JP PORdy +; +PrFlg: DB 0 +; +POCpy: CALL GetNN ;"*" sets copy count + JP C,POBad + LD (Copies),A + RET +POLMrg: CALL GetNN ;"Lnn" sets left margin + JP C,POBad + LD (PrLMrg),A + RET +POTMrg: CALL GetNN ;"Tnn" sets top margin + JR C,POBad + LD (PrTMrg),A + RET +POPau: SET 4,(HL) ;bit 4 is for "P" + RET +PODblS: SET 3,(HL) ;bit 3 is for "D" + RET +POCtl: SET 2,(HL) ;bit 2 is for "^" + RET +POBlk: LD A,(HL) + AND 11000010B ;bits 1,6,7 must be clear + JR NZ,POBad + SET 5,(HL) ;set bit 5 (BLOCK) + RET +POBeg: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"@" page beginning + JR C,POBad + OR A + JR Z,POBad + LD (PBeg),A + SET 6,(HL) ;bit 6 is for "@" (suppresses output) + SET 7,(HL) ;so is bit 7 (multicopy) + INC A + NEG ;255-@ is most # can be + LD B,A + LD A,(PNum) + CP B + RET C ;okay, less + LD A,B + LD (PNum),A + RET +PONum: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"#" page count + JR C,POBad + OR A + JR Z,POBad + LD B,A + LD A,(PBeg) + ADD A,B ;@ + # cannot exceed 255 + JR C,POBad + LD A,B + LD (PNum),A + RET +POPgS: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"=" starting pagination + JR C,POBad + OR A + JR Z,POBad + LD (POff),A ;offset beginning page + RET +POHdrT: BIT 0,(HL) ;must be paginating + JR NZ,POBad + SET 1,(HL) ;bit 1 requests header + LD (HdrPtr),DE ;point to header text + LD B,50 ;and figure its length +POHlp: LD A,(DE) + INC DE + CP '"' + JR Z,POHlpF + DJNZ POHlp + JR POBad ;too long +POHlpF: LD A,50 + SUB B ;length + LD (HdrLen),A + RET +POBad: POP HL ;eat return + JP Error7 +; +PORdy: CALL IOon ;say Wait + LD HL,PInit ;init string? + LD B,(HL) + INC HL + CALL LSTStr + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;move to top of file + LD A,(POff) + OR A + JR NZ,PORdy0 + LD A,(PBeg) +PORdy0: LD HL,PBeg + SUB (HL) ;adjust starting page offset + LD (POff),A + LD HL,POByt + BIT 5,(HL) + JR Z,PORdy1 + CALL IsBlk ;block print requested + BIT 1,A ; must be marked + JP Z,PrOops + INC DE + PUSH HL + SBC HL,DE + POP HL + RET Z ;block empty + DEC HL + EX DE,HL + JR PORdy2 +PORdy1: CALL NdCnt ;print whole file + JP C,PrDone ;file empty + LD HL,(AftCu) + LD DE,(EndTx) +PORdy2: LD (StPrt),HL + LD (EndPr),DE + CALL PCR ;### +; +RePrt: LD HL,POByt ;[reprint reentry] + BIT 7,(HL) + JR Z,PRP0 + SET 6,(HL) ;remember if "@" was used +PRP0: XOR A + LD (PageN),A + INC A + LD (IgnFlg),A ;TOF is start of line (DotChk) + LD A,(PgLen) ;start first page + LD B,A + OR A + PUSH AF ;### + CALL Z,DoPOf ;### + POP AF ;### + CALL NZ,PgBrk + JR C,Sk4Pr + LD HL,(StPrt) ;Point at first one + LD C,0 ;Initialize GetNx +Lp1Pr: CALL GetNx ;Get a character + CALL DotChk ;(maybe ignore dot command lines) + CP CR + JR NZ,Sk2Pr + CALL PrOut ;It's a CR + PUSH BC + PUSH HL + CALL Keybd + CP ESC ;Abort request? + POP HL + POP BC + JR Z,Sk1Pr + LD A,(POByt) + BIT 3,A ;doublespacing? do extra CR(LFCR)LF + JR Z,Sk0Pr + CALL PLF + CALL PCR + LD A,B ;count it (if paginating) + OR A + JR Z,Sk0Pr + DEC B + JR Z,Sk01Pr +Sk0Pr: LD A,B + OR A ;Not paginating? B is and stays 0 + LD A,(LFChr) ;Add usual line feed + JR Z,Sk2Pr + DJNZ Sk2Pr +Sk01Pr: CALL PgBrk ;time for NEW PAGE + JR C,Sk4Pr ;done? + JR Sk2aPr +Sk1Pr: LD A,1 ;abort + LD (Copies),A + JR Sk3Pr +Sk2Pr: CALL ChekC ;Check for masking + CALL PrOut ;Output char + XOR A + CP C ;Hidden space waiting? + JR NZ,Lp1Pr +Sk2aPr: LD DE,(EndPr) ;At end? + LD A,E + SUB L + LD A,D + SBC A,H + JR NC,Lp1Pr ;Loop if more to go +Sk3Pr: CALL PCR ;last CRLF for some matrix printers + LD A,(LFChr) + LD C,A + LD A,(PgLen) + OR A ;Finish page? + JR Z,Sk3aPr + LD C,FF +Sk3aPr: LD A,C + CALL PrOut +Sk4Pr: LD HL,PCodes ;undo toggles if on + LD DE,16 + LD B,4 +Lp2Pr: BIT 7,(HL) + JR Z,Lp2PrF + RES 7,(HL) + PUSH BC + PUSH DE + PUSH HL + LD DE,8 + ADD HL,DE + LD B,(HL) + INC HL + CALL LSTStr + POP HL + POP DE + POP BC +Lp2PrF: ADD HL,DE + DJNZ Lp2Pr + LD HL,Copies ;more copies? + DEC (HL) + JP NZ,RePrt + LD HL,PUInit ;uninit string? + LD B,(HL) + INC HL + CALL LSTStr + JR PrDone +PrOops: CALL Error7 +PrDone: LD HL,(LastCu) ;all finished + DEC HL + CALL MoveR ;go back to position + CALL IOoff + JP ShoLn1 +; +PgBrk: PUSH BC ;call this for new page (returns C for EOP) + PUSH HL + LD A,(PageN) + OR A + LD A,FF ;start new sheet IF not 1 + CALL NZ,PrOut + LD A,(POByt) + BIT 4,A ;pause requested? + JR Z,NP00 + CALL IOoff ;do it + LD HL,RdyQ + CALL Prefix + CP ESC + JP Z,NPquit + CALL IOon +NP00: LD HL,PageN + INC (HL) + JP Z,NPquit ;255 page limit. + LD C,(HL) ;check "#" limit? + LD A,(PBeg) + LD E,A + LD A,(PNum) ;Pnum+Pbeg-1 = Lastpage# + DEC A + ADD A,E + JP C,NPquit ;255 page limit + CP C + JP C,NPquit ;"#" pages printed... quit. + LD A,(PBeg) + LD C,A + LD A,(PageN) + CP C + LD HL,POByt + JR C,NP10 ;are we "@" yet? + RES 6,(HL) ;yes (start) printing + LD A,0C9H ;begin with margin offset + LD (DoPOf),A +NP10: LD A,(PrTMrg) + OR A + JR Z,NP20 + LD B,A +NP11Lp: CALL PCRLF ;top margin? + DJNZ NP11Lp +NP20: LD HL,POByt + BIT 1,(HL) + JR Z,NPnoh ;want header? + LD A,(HdrLen) + ADD A,6 + LD B,A + LD A,(RtMarg) ;column for page no. + SUB B + JR NC,NPlp + LD A,70 ;default if margin unusable + SUB B +NPlp: PUSH AF ;space over to right justify header + CALL PrSpc + POP AF + DEC A + JR NZ,NPlp + LD HL,(HdrPtr) ;put out header + LD A,(HdrLen) + LD B,A + CALL POStr + CALL PrSpc + LD A,(PageN) ;put out page + LD HL,POff + ADD A,(HL) ;adjust for "=" option + LD L,A + LD H,0 + LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + CALL POStr + CALL PCRLF + CALL PCRLF ;two blank lines + CALL PCRLF +NPnoh: XOR A + LD (DoPOf),A + CALL DoPOf + POP HL + POP BC + LD A,(PgLen) ;reset TOP + LD B,A + OR A + RET +NPquit: POP HL + POP BC + SCF + RET +PNBuf: DB 'nnnnn',0 ;(also used elsewhere) +; +DotChk: CP CR ;may ignore dot commands + JR Z,DotCCR + CP '.' + JR Z,DotCDt +DtC01: EX AF,AF' ;ordinary char + LD A,(IgnFlg) + CP 0FFh ;ignoring chars? + RET Z ;(returns 0FFh, nonprinting) + XOR A + LD (IgnFlg),A ;nope, clear dot search +DtCRet: EX AF,AF' ;no action, accept char + RET ;leave it 0FFh (ignore) +DotCCR: CALL DtC01 + EX AF,AF' + LD A,1 ;1 = ready to ignore if next char dot + LD (IgnFlg),A + EX AF,AF' + RET +DotCDt: EX AF,AF' + LD A,(FMode) ;Only ignore dotcmds in "W" mode + CP 'W' + JR NZ,DtCRet + LD A,(IgnFlg) + OR A + JR Z,DtCRet + LD A,0FFh ;FF = dot seen, ignore + LD (IgnFlg),A + RET +; +ChekC: CP ' ' ;may mask ctl chars + RET NC + CP CR ;exceptions: CR,LF,BadTbl + RET Z + CP LF + RET Z + PUSH HL + PUSH BC + LD HL,BadTbl + LD BC,BadLen + CPIR + POP BC + POP HL + RET Z + PUSH AF + LD A,(POByt) + BIT 2,A + JR NZ,CMask + POP AF + RET +CMask: LD A,'^' ;mask: print "^", + CALL PrOut + POP AF + OR 40H ;turn ^A into A, etc. + RET +; +PCR: LD A,CR + JR PrOut +PrSpc: LD A,' ' +PrOut: CP 0FFH ;(FF=dummy code, ignore) + RET Z + PUSH BC ;Print byte + PUSH DE + PUSH HL + LD HL,POByt ;printing yet? + BIT 6,(HL) + JR NZ,Sk2PO + CP ' ' + JR NC,Sk1PO ;non-ctl + LD HL,BadTbl + LD BC,BadLen + CPIR + JR Z,Sk2PO ;ILLEGAL + LD HL,TogTbl + LD BC,4 + CPIR ;toggle? + JR Z,Sk3PO + LD BC,4 + CPIR ;switch? + JR NZ,Sk1PO ;arbitrary ctl-code + LD A,4-1 + SUB C ;nontog# (0..n) + ADD A,A + ADD A,A + ADD A,A ;*8 + LD E,A + LD D,0 + LD HL,UCodes + ADD HL,DE +Sk00PO: LD B,(HL) + INC HL ;string to send +Sk0PO: CALL LSTStr + JR Sk2PO +Sk3PO: LD A,4-1 + SUB C ;tog# (0..n) + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;*16 + LD E,A + LD D,0 + LD HL,PCodes + ADD HL,DE + BIT 7,(HL) ;toggle status? + JR NZ,Sk3aPO + LD B,(HL) ;off, turn on + SET 7,(HL) + INC HL + JR Sk0PO +Sk3aPO: RES 7,(HL) ;on, turn off + LD DE,8 + ADD HL,DE + JR Sk00PO +Sk1PO: LD E,A ;byte to send + PUSH AF + CALL LSTOut + POP AF + LD HL,LFChr + CP (HL) + CALL Z,DoPOf ;LF? need margin skip +Sk2PO: POP HL + POP DE + POP BC + RET +; +DoPOf: NOP + LD A,(PrLMrg) ;do printer margin offset + OR A + RET Z + LD B,A +DoPOfL: CALL PrSpc + DJNZ DoPOfL + RET +; +PCRLF: CALL PCR ;do CR(LF?) +PLF: LD A,(LFChr) + JP PrOut +; +POStr: LD A,B ;send B chars at (HL) to PrOut + OR A + RET Z + LD A,(HL) + CALL PrOut + INC HL + DJNZ POStr + RET +; +LSTStr: LD A,B ;send B chars at (HL) to LST directly + OR A + RET Z + LD E,(HL) + PUSH BC + PUSH HL + CALL LSTOut + POP HL + POP BC + INC HL + DJNZ LSTStr + RET +; +LSTOut: LD C,LSTO ;print char in E + JP BDOSep +; +; +; +; ASSORTED SUPPORT ROUTINES +; +;RAM initialization functions +; +IniRAM: LD HL,MnuEnd ;Figure what used to be TxtOrg + LD A,(Help) ;help menus disabled? + OR A + JR NZ,IniR02 + LD HL,HelpY ;yes, use that memory for editing +IniR02: LD (BegTx),HL + LD HL,(BDOSep+1) ;BDOS origin (xx06) + LD L,-4 ;a few bytes room + DEC H ;back a page + LD (EndTx),HL + XOR A ;initialize screen + LD (NSkip),A + INC A + LD (Horiz),A + LD (Vert),A + LD (CurCol),A + LD (OldCol),A ;### + LD HL,1 + LD (CurPg),HL + LD (CurPgL),HL + LD (CurLin),HL + LD (OldLin),HL ;### + LD HL,(BegTx) ;set up cursor gap, mark CRs at ends + DEC HL + LD (BefCu),HL + LD (HL),CR + LD HL,(EndTx) + INC HL + LD (AftCu),HL + LD (HL),CR + RET +; +;Case selection subroutine +; CALL Case +; DB # of entries in list +; DW Default subroutine if no match +; DB value1 +; DW subroutine1.... +; +; +Case: POP HL + LD B,(HL) ;entries + INC HL + LD E,(HL) ;DE=default sbr + INC HL + LD D,(HL) + INC HL +Lp1Ca: CP (HL) ;Value matches? + INC HL + JR NZ,Sk2Ca + LD E,(HL) ;yes, get address + INC HL + LD D,(HL) + JR Sk3Ca ;finish up +; +Sk2Ca: INC HL ;No match, skip ahead +Sk3Ca: INC HL + DJNZ Lp1Ca ;Try again + EX DE,HL ;Swap sbr and return + PUSH DE ;Store return (end of list) + JP (HL) ;Go do sbr (LAST match) +; +; +XCase: CALL UCase ;force A to ctl-codes + CP '@' + RET C + CP '_'+1 + RET NC + AND 1FH + RET +UXCase: CP ESC ;uppercase A if letter OR ctl-code + JR NC,UCase + ADD A,40H + RET +UCase: CP 'a' + RET C ;uppercase A if letter + CP 'z'+1 + RET NC + AND 5FH + RET +; +; +Wait: LD A,(MacFlg) ;Macro Pause function + OR A + JP Z,Error2 + LD A,3 ;Wait about 3/2 sec + JR Dly0 +; +Delay: LD B,A ;Delay about A/2 sec + LD A,(MacFlg) ;but NOT if Macro going + OR A + RET NZ + LD A,B +Dly0: ADD A,A + ADD A,A +Dly1: PUSH AF + CALL BDly + POP AF + DEC A + JR NZ,Dly1 + RET +BDly: LD A,(MHz) + LD B,A + LD C,0 +BDlyLp: DEC BC + LD A,B + OR C + JR NZ,BDlyLp + RET +; +; +; UR-ROUTINES +; +Fill: LD (DE),A ;fill B bytes at DE with A + INC DE + DJNZ Fill + RET +; +GpCnt: LD BC,(BefCu) ;Count cursor gap size + LD HL,(AftCu) + DEC HL + DEC HL +SubDP: PUSH HL ;Double precision subtract + OR A ;BC = HL - BC + 1 + SBC HL,BC + LD B,H + LD C,L + INC BC + POP HL + RET +; +BgCnt: LD HL,(BegTx) ;Count bytes before cursor +LCnt: LD B,H + LD C,L + PUSH HL + LD HL,(BefCu) + CALL SubDP + POP HL + RET +NdCnt: LD HL,(EndTx) ;Count bytes after cursor +RCnt: LD BC,(AftCu) + JR SubDP +; +;Move bytes across cursor gap so the gap moves left. +;HL points to what will become BefCu. +; +MoveL: CALL LCnt ;bytes to move + RET C + LD DE,(AftCu) + DEC DE + LD HL,(BefCu) + LDDR + LD (BefCu),HL + INC DE + LD (AftCu),DE + RET +; +;MoveR - Moves gap right. HL will become BefCu. +; +MoveR: CALL RCnt + RET C + LD DE,(BefCu) + INC DE + LD HL,(AftCu) + LDIR + LD (AftCu),HL + DEC DE + LD (BefCu),DE + RET +; +;CrLft - Find CRs to left of cursor (up to E) +; +CrLft: CALL BgCnt + JR NC,Sk1Lf + XOR A ;no bytes, return with C and no Z + SUB 1 + RET +Sk1Lf: CALL FetchB + CP CR ;Is cursor on a CR + JR NZ,Sk2Lf + LD A,1 + CP E + JR NZ,Sk2Lf + SCF ;Asked for 1, and already there: ret C and Z + RET +Sk2Lf: LD A,CR +Lp3Lf: CPDR ;find a CR + JP PO,Sk4Lf ;count exhausted? + DEC E + JR NZ,Lp3Lf ;Do more? + INC HL ;Back up to before CR + INC HL + XOR A ;Found AOK, ret Z and no C + RET +Sk4Lf: INC HL ;Back to first byte + SCF + CCF ;Clear C + JR Z,Sk5Lf ;Was first byte CR + DEC E ;No, reduce count + RET +Sk5Lf: INC HL ;Back after CR + DEC E ;the one we wanted? + RET Z + DEC HL ;No, back in front of it + DEC E + RET +; +;CrRit - same, to right. +; +CrRit: CALL NdCnt + JR NC,Sk1Ri + XOR A + SUB 1 ;no bytes, return C and no Z + RET +Sk1Ri: LD D,E + LD A,CR + LD HL,(AftCu) +Lp2Ri: CPIR + JP PO,Sk3Ri + DEC E + JR NZ,Lp2Ri + SCF + CCF ;found AOK, ret Z and no C + RET +Sk3Ri: LD A,D + CP E + JR NZ,Sk4Ri + SCF ;none found, return C and Z + RET +Sk4Ri: LD HL,(EndTx) + DEC HL + LD A,CR + LD BC,0FFFFh + CPDR + INC HL + INC HL + OR 1 ;some but not enough, ret no C and no Z + RET +; +;cursor positioning subroutines +; +TopV: LD A,1 + JR LoadV +MidV: LD A,(TxtLns) + SRL A + JR LoadV +DecV: EXX + LD HL,(CurLin) + DEC HL + LD (CurLin),HL + EXX +DecVO: LD A,(Vert) ;returns Z if cannot Dec + CP 1 + JR Z,LoadV + DEC A + JR LoadV +IncV: EXX + LD HL,(CurLin) + INC HL + LD (CurLin),HL + EXX +IncVO: LD A,(Vert) ;returns Z if cannot Inc + EXX + LD HL,TxtLns + CP (HL) + EXX + JR Z,LoadV + INC A + JR LoadV +BotV: LD A,(TxtLns) +LoadV: LD (Vert),A + RET +LftH: LD A,1 + JR LoadH +LTabH: LD A,(Horiz) + DEC A + JR Z,RitH + CALL WhatC ;ouch, got to calculate + LD HL,NSkip ;Horiz = CurCol-NSkip + SUB (HL) + JR C,RitH + JR LoadH +DecH: LD A,(Horiz) + DEC A + RET Z + JR LoadH +TabH: LD A,(Horiz) + DEC A + EXX + LD HL,TabCnt + OR (HL) + EXX + INC A + JR IncT +IncH: LD A,(Horiz) +IncT: EXX + LD HL,View + CP (HL) + EXX + RET NC + INC A + JR LoadH +RitH: LD A,(View) +LoadH: EX AF,AF' ;### + LD A,(CurCol) ;### + INC A ;### + JR NZ,LoadH2 ;### + EX AF,AF' ;### + RET ;### +LoadH2: EX AF,AF' ;### + LD (Horiz),A + RET +; +; +;Get next text character from memory +;(HL and C keep track across repeated calls) +; +GetNx: XOR A + CP C ;Have we a hidden space? + JR NZ,Sk1Gt + LD A,(HL) ;No, get next byte + INC HL + CP 80H ;Does it have hidden space? + JR NC,Sk2Gt ;Yes, note and remove + CP CR + RET +Sk1Gt: DEC C ;Fetch hidden space + LD A,' ' + CP CR ;Set Z flag if CR + RET +Sk2Gt: AND 7FH + INC C + CP CR ;Set Z flag if CR + RET +; +;Hide any hideable spaces. (NEW ALGORITHM) +; +Cmprs: CALL BgCnt ;bytes to left + JR C,Sk2Cm ;none? + LD D,H + LD E,L + DEC DE +Lp1Cm: LD A,(HL) ;Get a byte + CP ' ' ;Nonspace? fine + JR NZ,Sk1Cm + LD A,(DE) ;Last byte CTL? fine + CP 20H + LD A,' ' + JR C,Sk1Cm + LD A,(DE) ;Hidden space already? fine + BIT 7,A + LD A,' ' + JR NZ,Sk1Cm + LD A,(DE) + OR 80h ;Got to hide the space. + DEC DE +Sk1Cm: INC DE ;Store byte + LD (DE),A + INC HL ;Bump input + DEC BC + LD A,B + OR C ;more to do? + JR NZ,Lp1Cm + LD (BefCu),DE ;This is now BefCu +; +Sk2Cm: CALL NdCnt ;How many after cursor? + RET C + LD HL,(EndTx) ;work back from end + LD D,H + LD E,L + INC DE +Lp3Cm: LD A,(DE) + CP ' ' ;Last byte space? + JR NZ,Sk3Cm + LD A,1FH ;This byte CTL? + CP (HL) + JR NC,Sk3Cm + BIT 7,(HL) ;This byte already hiding? + JR NZ,Sk3Cm + SET 7,(HL) ;Got to hide that space + INC DE +Sk3Cm: DEC DE + LDD ;Store byte, Bump input + INC DE + JP PE,Lp3Cm ;more to do? + LD (AftCu),DE ;This is now AftCu + RET +; +;Set BC to gap size (make room if needed, or set EdErr) +; +Space: LD L,A ;Save A + PUSH HL + CALL GpCnt ;Count gap size + CALL C,Cmprs ;No room? Hide spaces + CALL GpCnt ;Room now? + CALL C,Error1 ;out of memory + POP HL + LD A,L + RET +; +InsSpc: LD A,' ' +; +;Put ordinary byte in A into text at cursor. +; +Insrt: CALL Space ;Insert Before cursor + RET C + CP EOF + JR Z,Insrt1 + LD HL,BlkChr + CP (HL) + JR Z,Insrt1 + LD HL,Modify + LD (HL),0FFh +Insrt1: LD HL,(BefCu) ;Bump pointer + INC HL + LD (HL),A ;Store byte + LD (BefCu),HL + OR A ;Clear flags + RET +InsrtA: CALL Space ;same, but After cursor + RET C + LD HL,Modify + LD (HL),0FFh +InsrA1: LD HL,(AftCu) + DEC HL + LD (HL),A + LD (AftCu),HL + OR A + RET +; +;Compute absolute line number +; +CountS: LD HL,1 ;Hard way: from start + LD (CurLin),HL + CALL BgCnt + JR Sk0CL +CountL: LD HL,(LastCu) ;same but faster, using LastCu + INC HL + CALL LCnt +Sk0CL: RET C ;(At start, or have not moved) + LD DE,0 + LD A,CR + LD HL,(BefCu) +Lp1CL: CPDR + JR NZ,Sk1CL + INC DE + JP PE,Lp1CL +Sk1CL: LD HL,(CurLin) + ADD HL,DE + LD (CurLin),HL + RET +CountR: LD HL,(LastCu) ;same, but for backward move + DEC HL + CALL RCnt + RET C ;(have not moved) + LD DE,0 + LD A,CR + LD HL,(AftCu) +Lp1CR: CPIR + JR NZ,Sk1CR ;(have not moved) + INC DE + JP PE,Lp1CR +Sk1CR: LD HL,(CurLin) + OR A + SBC HL,DE + LD (CurLin),HL + RET +; +; +;MACRO functions +; +MacKey: LD HL,KeyQ + CALL Prompt + CALL RptKey ;which key? + CALL UCase + LD (MKsav),A + CP 'N' ;no-rpt request? + JR Z,MK0 + CP 'Q' ;no-rpt & macro request? + JR NZ,MK00 +MK0: CALL Echo ;show N or Q, get next + CALL RptKey +MK00: SUB '0' + JP C,Error7 + CP 10 + JP NC,Error7 + LD D,A ;save key + LD A,0FFH + LD HL,MacStr + LD BC,StrSiz+1 ;find end + CPIR + LD A,StrSiz + SUB C ;figure length + LD E,A ;save it + LD HL,Keys+2 + LD A,D + OR A + JR Z,MKlp1F +MKlp1: LD C,(HL) + LD B,0 ;find key in list + ADD HL,BC + INC HL + DEC A + JR NZ,MKlp1 +MKlp1F: LD A,(HL) ;old length + OR A + JR Z,MK1 + PUSH DE + PUSH HL ;delete old one + LD E,(HL) + LD D,0 + LD (HL),0 + INC HL + EX DE,HL + ADD HL,DE + LD B,H + LD C,L + PUSH HL + LD HL,Keys+200H + OR A + SBC HL,BC ;bytes to move + LD B,H + LD C,L + POP HL + LDIR + CALL VerKey + POP HL + POP DE +MK1: LD A,E ;anything to add? + OR A + JR Z,MKDone + LD A,(Keys+1) ;will it fit + OR A + JR NZ,MK1a + LD A,(Keys) + SUB E + JP C,Error1 ;out of memory +MK1a: LD (HL),E ;yes + INC HL + LD C,E + LD B,0 + PUSH HL + LD HL,Keys+200H-1 + LD D,H + LD E,L + OR A + SBC HL,BC ;from here + POP BC + PUSH HL + SBC HL,BC ;bytes to move + LD B,H + LD C,L + INC BC ;inclusive + POP HL + LDDR ;make room + LD C,(HL) + LD B,0 + INC HL + EX DE,HL + LD HL,MacStr + PUSH DE + LDIR ;insert new one + POP HL + LD A,(MKsav) + CP 'N' ;take care of N/Q request + JR Z,MK2 + CP 'Q' + JR NZ,MKDone + DEC HL + LD A,(HL) ;Q only works if length >1 + CP 2 + INC HL + JR C,MK2 + INC HL + SET 7,(HL) ;indicate quiet + DEC HL +MK2: SET 7,(HL) ;indicate no-rpt +MKDone: CALL VerKey + JP ShoLn1 +; +; +VerKey: LD B,10 ;verify key area + LD HL,200H-12 + LD D,0 + LD IX,Keys+2 +VKlp: LD A,StrSiz ;check size + CP (IX) + JR C,VKwipe + LD E,(IX) + SBC HL,DE ;decrement + JR C,VKwipe + ADD IX,DE ;move to next + INC IX + DJNZ VKlp + LD (Keys),HL ;free bytes + LD A,H + OR L + RET Z ;full? +VKlp2: LD (IX),0 + INC IX ;zero fill + DEC HL + LD A,H + OR L + JR NZ,VKlp2 + RET +VKwipe: LD HL,200H-12 ;oops, bad + LD (Keys),HL + LD IX,Keys+2 + LD HL,200H-2 + JR VKlp2 +; +ChainK: LD HL,MacFlg ;chain to new macro + BIT 0,(HL) ;(used only if macro going) + RET Z + CALL RstI1x ;reset INS to saved state + CALL RptKey ;get key # + CP '0' + JP C,Error8 + CP '9'+1 + JP NC,Error8 + PUSH AF + CALL Loud + XOR A + LD (MacFlg),A + POP AF + JR UK0 +; +UseKey: LD HL,MacFlg ;macro going already? + BIT 0,(HL) + RET NZ ;YES, this is just a label +UK0: SUB '0' ;NO, retrieve key 0-9 + LD B,A + LD HL,Keys+2 + JR Z,UKlp1F +UKlp1: LD E,(HL) + LD D,0 ;find it + ADD HL,DE + INC HL + DJNZ UKlp1 +UKlp1F: LD A,(HL) ;length + INC HL + OR A + JP Z,Error7 ;none? + LD C,A + LD B,0 + PUSH BC ;on stack for Mac00 entry + LD DE,DMA + PUSH DE + LDIR ;fetch it in + POP HL ;point to it + BIT 7,(HL) + RES 7,(HL) + JR Z,Mac00 ;not no-rpt? go ask, etc. + INC HL + BIT 7,(HL) + RES 7,(HL) + CALL NZ,Quiet ;quiet? + LD A,'1' + JR Mac0 ;go do just once +; +DoMac: LD HL,MacroQ ;get Macro defn + CALL Prompt + CALL GetStr + DW MacStr ;### + OR A + JR Z,MacDel ;none? delete + LD C,A ;save count + LD B,0 + PUSH BC +Mac00: LD HL,RptcQ ;(entry for normal Key) + CALL Prompt + CALL RptKey + CALL UCase + CP 'Q' + JR NZ,Mac0 + CALL Echo + CALL Quiet ;Q? do quiet, get rpt cnt + CALL RptKey +Mac0: POP BC ;string cnt (entry for no-rpt Key) + PUSH AF ;save rpt cnt + LD A,C + OR A ;null string? + JR Z,Mac1 + LD HL,DMA ;move in string + LD DE,MacStr + LDIR + EX DE,HL + LD (HL),0FFh ;terminator +Mac1: CALL ShoLn1 + POP AF + LD B,255 + CP '*' ;figure rpt cnt + JR Z,Mac2 ;(* is maximal) + LD B,0 ;(0 is default) + SUB '0' + JR C,Mac2 + CP 9+1 + JR NC,Mac2 + LD B,A +Mac2: LD A,B ;set rpt cnt + LD (RptCnt),A + OR A + JP Z,Loud ;oops, rpt=0 +Mac3: LD HL,MacStr ;Point to it + LD (CmdPtr),HL + LD A,0FFH ;Okay, here goes + LD (MacFlg),A + LD HL,InsFlg ;save INSERT toggle + LD A,(HL) + LD (SavIns),A ;turn INSERT off if on + BIT 7,(HL) + CALL NZ,ToggHL + RET +MacDel: LD A,0FFH + LD (MacStr),A + JP ShoLn1 +; +;"Macro Programming Language" +; +MacJmp: LD A,(MacFlg) ;jump to a label + OR A + JP Z,Error8 ;macro must be going + LD (JmpFlg),A ;say Jump in progress + CALL RptKey + LD HL,JmpFlg + LD (HL),0 + CP '[' ;TOF/EOF? + JR Z,MJtop + CP ']' + JR Z,MJend + CP '>' ;move/loops? + JR Z,MJRt + CP '<' + JR Z,MJLf + LD E,A ;key to find + LD HL,MacStr + LD B,StrSiz +MJlp: LD A,(HL) ;search along + INC HL + CP 0FFH + JP Z,Error8 + CP ESC + JR Z,MJlp01 + DJNZ MJlp + JP Error8 +MJlp01: LD A,E ;found ESC... right one? + CP (HL) + JR NZ,MJlp + INC HL ;yep + LD (CmdPtr),HL + RET +; +MJtop: LD HL,MacStr ;redo it from the top + LD (CmdPtr),HL + RET +MJend: XOR A ;quit + LD (MacFlg),A + LD E,A + CALL RstI1x + JP Loud +MJRt: CALL NdCnt ;right/left jump loops + JP C,Error7 ;stop at EOF + CALL Right + JR MJredo +MJLf: CALL BgCnt + JP C,Error7 + CALL Left +MJredo: LD HL,(CmdPtr) + DEC HL ;back up to the ESC to repeat + DEC HL + DEC HL + DEC HL + LD (CmdPtr),HL + RET +; +MacTst: LD A,0CAH ;(JP Z) + JR MacT1 +MacTsX: LD A,0C2H ;(JP NZ) +MacT1: LD (MacT),A + LD A,(MacFlg) + OR A ;macro must be going + JP Z,Error8 + CALL RptKey ;get char to match + LD E,A + CALL Fetch ;char at cursor + CP E +MacT: JP Z,MacJmp ;yes? jump <--- can be JP NZ too + JP RptKey ;no, just eat label +; +;Get the next key stroke (check Macro first.) +; +TRptKy: XOR A ;enable redisp Timer + JR RK0 +RptKey: LD A,0FFH +RK0: LD (KeyFlg),A + LD A,(MacFlg) + OR A ;macro waiting? + JP Z,KeyIn ;no. +MacIn: CALL Keybd ;YES, check keyboard for abort + CP ESC + JR NZ,MacIn1 + LD HL,(CmdPtr) ;abort, make this last char + LD E,(HL) + LD HL,MacFF+1 ;### + LD (CmdPtr),HL ;### + JR MacIn3 +MacIn1: LD HL,(CmdPtr) ;OK, take waiting char + LD A,(HL) + INC HL ;bump pointer + LD (CmdPtr),HL +MacFF: CP 0FFH ;### + JR Z,MacFFx ;### + LD E,A ;### + LD A,(HL) ;end of macro now? (FF) + INC A + JR NZ,MacIn2 ;NO, return char + LD A,(JmpFlg) ;jump in progress? + OR A + JR NZ,MacIn2 + LD HL,RptCnt ;need to repeat? + LD A,(HL) + INC A + JR Z,McIn1a + DEC (HL) + JR Z,MacIn3 +McIn1a: LD HL,MacStr ;repeat: reset pointer + LD (CmdPtr),HL + JR MacIn2 +MacIn3: CALL Loud +MacIn2: LD A,E + AND 7FH ;strip parity, return char + RET +MacFFx: XOR A ;NO, stop macro execution + LD (MacFlg),A + CALL RstI1x ;restore saved INS state + JP KeyIn +; +; +;Unconditional Q/L for Macros +; +Quiet: LD HL,ShutUp + LD (HL),0C9H ;(RET) + RET +Loud: LD HL,ShutUp + XOR A ;(NOP) + CP (HL) + RET Z + LD (HL),A + JP HoldSc ;gotta see... +; +RstI1x: LD A,(SavIns) + LD HL,InsFlg + CP (HL) + CALL NZ,ToggHL ;switch INS to match the saved state + RET +; +;Conditional Q/L for formatting etc. +; +; +XQuiet: LD HL,ShutUp + LD A,(HL) + LD (HL),0C9H ;(RET) + LD (SavQ),A + RET +XLoud: LD A,(SavQ) + OR A ;(NOP) + RET NZ + LD (ShutUp),A + RET ;do NOT need redisp here +; +;Force loud for header display +; +Force: LD HL,ShutUp + LD A,(HL) + LD (HL),00H ;(NOP) + LD (SavQ2),A + RET +UForce: LD A,(SavQ2) + CP 0C9H ;(RET) + RET NZ + LD (ShutUp),A + RET +; +; +; VDE EDITING FUNCTIONS +; +; +;Show information +; +Info: CALL MakAlt ;show this first for entertainment + CALL UndrHd + CALL Dspl + DB X,26,0 + LD HL,VersID + CALL DspLp + CALL Cmprs ;pack spaces + CALL GpCnt ;count gap size + PUSH BC + LD H,B + LD L,C + LD DE,FreNNN ;show it as "free space" + CALL BCDCon + LD HL,(EndTx) + INC HL + LD DE,(BegTx) + OR A + SBC HL,DE + POP BC + SBC HL,BC ;memory used + LD DE,UsdNNN + CALL BCDCon ;show it as "used" + LD HL,(BegTx) + LD DE,(BefCu) + CALL FSzSbr ;figure actual disk file size + PUSH BC + LD HL,(AftCu) + LD DE,(EndTx) + CALL FSzSbr + POP HL + ADD HL,BC + LD DE,SizNNN ;show it as "file size" + CALL BCDCon + LD A,(Modify) + OR A ;file changed? + LD A,'Y' + JR NZ,Info2 + LD A,'N' +Info2: LD (ModQQQ),A + LD HL,InfMsg ;now display the data + CALL DspLp + CALL UnAlt + CALL ESCLp + JP SetAl +; +FSzSbr: LD BC,0 ;count a block +FSzLp: LD A,E ;done? + SUB L + LD A,D + SBC A,H + RET C + LD A,(HL) + INC HL + INC BC ;count character + CP CR + JR Z,FSz1 ;and (missing) LF? + CP X + JR C,FSzLp ;and (hidden) space? +FSz1: INC BC + JR FSzLp +; +; +; Blank the screen +; +Blank: LD A,(WinFlg) ;window off first (will lose text) + OR A + CALL NZ,Window + LD HL,CsrOff ;### + CALL CtlStr ;### + LD HL,TInit + CALL CtlStr + CALL ESCLp + CALL DoHdr + JP SetAl +; +; +;Move cursor to the beginning of text +; +Top: LD HL,(BegTx) + CALL MoveL ;Move + CALL TopV ;Adjust cursor + CALL LftH + LD HL,1 + LD (CurLin),HL + JP SetAl +; +; +;Move cursor to the last character of text +; +Bottom: LD HL,(BefCu) ;for CountL + LD (LastCu),HL + LD HL,(EndTx) + CALL MoveR ;Move + CALL BotV ;Adjust cursor + CALL RitH + CALL CountL + JP SetAl +; +; +; Queue: move to next line in ZCPR queue +; +Queue: LD BC,Z3MSG + CALL Z3EAdr + JP Z,Error7 ; no Z3 message buffers + LD D,B ; addr of Z3MSG to DE + LD E,C + LD HL,RegNum+1 ; current register addr + LD A,(HL) + CP MsgUsr-2+MsgNmU ; time to wrap around? + JR NZ,QueNxt +QueWrp: LD A,MsgUsr-2 ; yes + LD (HL),A ; update it +QueNxt: INC (HL) ; next register + INC (HL) +RegNum: LD HL,MsgUsr-2 + ADD HL,DE ; point to next line # + LD C,(HL) + INC HL + LD B,(HL) ; line # to BC + LD A,B + OR C + JP NZ,ZipTo2 ; go to it + LD HL,RegNum+1 ; is first register empty? + LD A,(HL) + CP MsgUsr + JP Z,Error7 ; yes, error + JR QueWrp ; no, wrap around +; +; +;QUICK cursor movements +; +QuikMk: CALL NdCnt ;look for next place marker + JR C,QkMk1 + LD HL,(AftCu) + LD A,EOF ;marker + CPIR + JP Z,QikB1 ;found? rest same as ^QB +QkMk1: CALL BgCnt ;not? try from top + JR C,QkMk2 + LD HL,(BegTx) + LD A,EOF + CPIR + JP Z,QikB0 ;found? rest same as ^QB +QkMk2: JP Error7 ;not? error. +; +QuikLf: LD E,1 ;move left to start of line + CALL CrLft + RET C + LD A,1 + LD (CurCol),A ;(useful for format subroutines) + CALL MoveL + CALL LftH + JP IfScl +; +QuikRt: CALL NdCnt ;move right to end of line + JP C,ColCnt + CALL Fetch + JP Z,ColCnt + CALL Right + RET C + JR QuikRt +; +QuikUp: LD A,(Vert) ;move up to top of screen + DEC A + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QUlp: PUSH BC + CALL Up + POP BC + DJNZ QUlp + CALL SetNo + POP AF ;restore col + JP SkQUD +; +QuikDn: LD A,(TxtLns) ;move down to end of screen + LD HL,Vert + SUB (HL) + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QDlp: PUSH BC + CALL Down + POP BC + DJNZ QDlp + CALL SetNo + POP AF + JP SkQUD +; +ZipTo: LD HL,PageQ ;zip to given page + LD A,(PgLen) + OR A + JR Z,ZipTo0 + LD A,(FMode) + CP 'N' + JR NZ,ZipTo1 +ZipTo0: LD HL,LineQ ;or line, in N mode +ZipTo1: CALL Prompt + LD BC,1 + CALL GetNbr + JP C,Error7 + JP Z,Error7 + LD A,(FMode) + CP 'N' + JR Z,ZipTo2 + LD A,(PgLen) ;(calculate line) + OR A + JR Z,ZipTo2 + LD D,0 + LD E,A + LD L,D + LD H,D + DEC BC +ZipMul: LD A,B + OR C + JR Z,ZipMF + ADD HL,DE + DEC BC + JR ZipMul +ZipMF: INC HL +ZipMF2: LD B,H + LD C,L +ZipTo2: PUSH BC + CALL Top + POP DE ;desired line + LD A,D + OR E + JR Z,ZipXit + DEC DE ;lines to move down + XOR A + OR D + JR Z,ZipLpF +ZipLp: PUSH DE ;do multiples of 256 + LD E,0 ;(256) + CALL CrRit + DEC HL + CALL MoveR + POP DE + DEC D + JR NZ,ZipLp +ZipLpF: XOR A + OR E + JR Z,ZipTo3 + CALL CrRit ;do remainder + DEC HL + CALL MoveR +ZipTo3: CALL MidV + CALL RitH + CALL CountS +ZipXit: JP SetAl +; +; +;Move cursor up. +; +Up: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,2 ;start of last line + CALL CrLft + RET NZ ;TOF? quit + PUSH HL + CALL EdgeU + CALL DecV + POP HL + CALL MoveL +SkUpDn: LD A,(CurCol) ;where we were +SkQUD: CALL GoCol + RET Z ;exact? + JP IfScl ;may need to scroll +; +; +;Move cursor down. +; +Down: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,1 ;start of next line + CALL CrRit + DEC HL + JR NC,Sk1Dn ;was there one? + RET NZ ;EOF? quit + LD HL,(EndTx) + LD A,(HL) ;Get that last byte + CP CR + RET NZ ;no next line +Sk1Dn: PUSH HL + CALL EdgeD + CALL IncV + POP HL + CALL MoveR + JR SkUpDn +; +QuikLc: LD HL,(SavLin) + CALL ZipMF2 + LD A,(SavCol) +; +; +GoCol: DEC A ;restore cursor to column A + RET Z + LD HL,(HorFlg) ;don't change show status + PUSH HL + PUSH AF + CALL ColCnt ;where are we? + LD IY,CurCol + JR GRCent +GRCLp: CALL NdCnt + JR C,GRCF ;stop at EOF + CALL Fetch + JR Z,GRCF ;stop at CR + CP TAB ;tabs are special + JR NZ,GRC1 + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A +GRC1: INC (IY) ;Keep CurCol updated + CALL Right +GRCent: POP AF + PUSH AF + CP (IY) ;there yet? + JR NC,GRCLp +GRCF: POP AF + POP HL + LD (HorFlg),HL + INC A + SUB (IY) ;set Z if exact + RET +; +; +;Move cursor one to the left (C=cannot) +; +Left: CALL Space ;Any space left? + RET C + CALL BgCnt ;Are we at front? + RET C + CALL EdgeL + LD HL,(BefCu) ;Look back + LD A,(HL) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1Lt ;No, just move + RES 7,(HL) ;Yes, unhide it + LD A,' ' + INC HL +Sk1Lt: DEC HL ;Back up + LD (BefCu),HL + CALL InsrA1 ;store byte ahead + CP TAB ;Was a TAB moved + JR Z,LftTab + CP CR ;Was a CR moved? + JR Z,LftCR + CALL DecH ;no + OR A + RET NZ + JP IfScl ;at left mgn...scroll? +; +LftCR: CALL RitH ;special cases - scrolling + CALL DecV + CALL ColCnt + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl + OR A + RET +LftTab: LD A,(Horiz) + DEC A + CALL Z,HorScl ;need to scroll if at left + CALL LTabH + OR A + RET +; +; +;Move cursor one to the right +;(return C if can't, char passed in A) +; +Right: CALL Space ;Any room left? + RET C + CALL NdCnt ;Already at end? + RET C + CALL EdgeR + CALL Fetch + JR NZ,Sk0Rt + PUSH HL + CALL TestCu ;change of line: no delays + CALL NZ,ShoCu1 + POP HL +Sk0Rt: LD A,(HL) + BIT 7,A ;Hidden space? + JR Z,Sk1Rt ;No, just move + LD (HL),' ' ;Yes, unhide it + AND 7FH + DEC HL +Sk1Rt: INC HL ;Bump pointer + LD (AftCu),HL + CALL Insrt1 ;put byte in behind + OR A ;and return it + PUSH AF + CP TAB ;TAB and CR are special + JR Z,RtTab + CP CR + JR Z,RtCR + CALL IncH ;no, just move + POP AF + RET +; +RtCR: CALL IfScl ;may have to scroll + CALL IncV ;adjust + CALL LftH + LD A,1 + LD (CurCol),A + POP AF + RET +; +RtTab: LD A,(View) + DEC A + LD HL,TabCnt + SUB (HL) + LD HL,Horiz + SUB (HL) + CALL C,HorScl ;at right, need to scroll + CALL TabH + POP AF + RET +; +; +;Word tab, delete +; +WdMxCh EQU 255 ;max chars to loop +; +WordRt: CALL Fetch ;Word tab right + JP Z,Right ;at EOL? special case + CALL IsBlnk ;on break? just find nonbreak + JR Z,WRlpF + LD B,WdMxCh +WRlp: CALL WRfBrk + JR Z,WRlpF + CP CR ;quit at CR + RET Z + DJNZ WRlp +WRlpF: LD B,WdMxCh +WRlp2: CALL WRfBrk + RET NZ + DJNZ WRlp2 + RET +WRfBrk: PUSH BC + CALL Right + JR C,WRfBrX + CALL IsBlnk ;then nonbreak + CALL NZ,IsPunc + PUSH BC +WRfBrX: POP BC + POP BC + RET +; +WordLf: CALL FetchB ;Word tab left + CP CR ;at BOL? Special case + JP Z,Left + LD B,WdMxCh +WLlp: CALL IsParB ;find a nonbreak + CALL NZ,IsPunB + JR NZ,WLlpF + CP CR ;quit at CR + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp +WLlpF: CALL Left + LD B,WdMxCh +WLlp2: CALL IsParB ;then a break + CALL NZ,IsPunB + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp2 + RET +; +WordDl: CALL Fetch ;Word Delete + JP Z,EChar ;at BOL? special case + CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNB ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNB: LD B,WdMxCh +WDlp2: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak + CP CR ;but quit at CR + RET Z + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2 + RET +WDlB: LD B,WdMxCh +WDlp: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET Z ;delete till reak + PUSH BC + CALL EChar + POP BC + DJNZ WDlp + RET +; +Join: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNBx ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNBx: LD B,WdMxCh +WDlp2x: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak (including CRs) + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2x + RET +; +IsPaPu: CALL IsPara + CALL NZ,IsPunc + RET +; +; +;Move cursor ahead one page +; +PageF: CALL SetAl + LD A,(TxtLns) + DEC A + LD E,A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgF1 + INC A + LD E,A +PgF1: CALL CrRit ;Point that many CRs down + DEC HL ;Back off one byte + JP C,Bottom + JP NZ,Bottom + LD DE,(BefCu) ;Prepare Count + LD (LastCu),DE + CALL MoveR ;Move cursor gap + CALL CountL + JR LDaGoC ;relocate cursor +; +; +;Move cursor back one page +; +PageB: CALL SetAl + LD A,(TxtLns) + LD E,A + DEC A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgB1 + ADD A,2 + LD E,A +PgB1: CALL CrLft ;Point that many CRs back + JP C,Top + JP NZ,Top + LD DE,(AftCu) ;Prepare Count + LD (LastCu),DE + CALL MoveL ;Move cursor gap + CALL CountR +LDaGoC: LD A,(CurCol) + JP GoCol ;relocate cursor +; +; +;Scroll screen 1/4 vertically +; +ShftD: LD A,(TxtLns) ;Down + SRL A + SRL A + INC A + LD B,A +LDLp: PUSH BC + CALL DecVO + JR NZ,LDLpF + CALL Down ;oops, cursor already on top + CALL DecVO +LDLpF: POP BC + DJNZ LDLp + JP SetAl +; +ShftU: LD A,(TxtLns) ;same, up + SRL A + SRL A + INC A + LD B,A +LULp: PUSH BC + CALL IncVO + JR NZ,LULpF + CALL Up ;oops, cursr already on bottom + CALL IncVO +LULpF: POP BC + DJNZ LULp + JP SetAl +; +Scr1LD: CALL DecVO ;FAST one-line scrolls + JR NZ,ScLD1 + CALL Down ;oops, already on top + CALL DecVO +ScLD1: LD HL,DelL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + LD A,(TxtLns) + LD B,A + JP ShoLn ;re-show last line +; +Scr1LU: LD HL,(CurLin) + LD DE,(Vert) + LD D,0 + OR A + SBC HL,DE + RET Z ;oops, nowhere to go + CALL IncVO + JR NZ,ScLU1 + CALL Up ;oops, already on bottom + CALL IncVO +ScLU1: LD HL,InsL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + JP ShoLn1 +; +;Scroll screen 32 cols horizontally +; +ShftR: LD HL,Horiz ;INcrease screen scroll (right) + LD A,(HL) + SUB 32+1 + RET C + INC A + LD (HL),A + LD HL,NSkip + LD A,(HL) + ADD A,32 + JR ShftX +; +ShftL: LD A,(Horiz) ;DEcrease scroll (left) + ADD A,32 + LD HL,View + CP (HL) + RET NC + LD (Horiz),A + LD HL,NSkip + LD A,(HL) + SUB 32 + RET C +; +;Make current line top +; +ShftX: LD (HL),A + JP SetAl +; +MakTop: CALL TopV ;gee boss, that was easy, huh? + JP SetAl +; +; +;FIND/REPLACE +; +;Find next occurance of a given string. +; +Find: CALL FndSub + JP C,Error7 + CALL ShoLn1 +; + LD A,(FGlobl) + OR A + JR Z,RpFind + LD A,(FBackw) ;global search: backwards? + OR A + JR Z,FndBck + CALL Bottom ;...yes, goto bottom of file + JR RpFind +FndBck: CALL Top ;...no, goto top of file +RpFind: LD A,(FndStr) ;length + OR A + RET Z ;no string, quit + LD A,(FBackw) + OR A ;backward? + JR NZ,RpF5 + CALL NdCnt ;number to scan + JP C,Err4x + LD HL,(EndTx) + LD DE,(FndStr) ;string length + XOR A + LD D,A ;extend to 16 bits + SBC HL,DE +RpSsLp: INC HL + BIT 7,(HL) ;soft space? + JR Z,RpSsNo ;nope + INC A ;count soft spaces? +RpSsNo: DEC E ;decrement string length + JR NZ,RpSsLp + ADC A,C + LD C,A + LD A,B + ADC A,0 + LD B,A + LD HL,FndStr + LD A,C + SUB (HL) + LD C,A ;less string length + LD A,B + SBC A,0 + LD B,A + JR C,Err4x + INC BC ;in case last + LD HL,(BefCu) + LD (LastCu),HL ;Mark position + LD HL,(AftCu) + LD A,(ChgFlg) ;was last operation change? + OR A + JR NZ,RpF1 + INC HL ;NO, start at next byte + DEC BC ;YES, start at this byte +RpF1: LD A,B + OR C + JR Z,Err4x ;gotta have bytes + LD A,(FUCase) + CP 0C3H ;ucase? (groan) + JR Z,SlowFi + LD A,(FndStr) ;only one char? (groan) + DEC A + JR Z,SlowFi + LD DE,(FndStr+1) ;space in char 1 or 2? (groan) + LD A,' ' + CP D + JR Z,SlowFi + CP E + JR Z,SlowFi + JR FastFi +; +Err4x: LD A,(FGlobl) + OR A + JP Z,Error4 ;not found + LD HL,(OldLin) + CALL ZipMF2 + LD A,(OldCol) + CALL GoCol + JP Error5 +; +RpF5: CALL BgCnt ;backward: number to scan + JR C,Err4x ;EOF? + LD HL,(AftCu) + LD (LastCu),HL ;Mark position + LD HL,(BefCu) + JR BackFi +; +FastFi: LD A,B ;find lead char FAST with CPIR + OR C + JR Z,Err4x + LD A,(FndStr+1) + CPIR + JP PE,FstFi1 ;jump if P/V=1 (BC-1 is not 0) + JR NZ,Err4x ;NOT found +FstFi1: PUSH BC + PUSH HL + LD C,0 ;no hidden spaces involved + CALL FndChk ;rest of string? + POP HL + POP BC + JR NZ,FastFi ;no match, keep going + LD C,0 + JP Found +; +SlowFi: LD A,(FndStr+1) ;find lead char the slow way + LD (LdChar+1),A ;(spaces or upcase involved) + LD D,H + LD E,L + ADD HL,BC + EX DE,HL + LD C,0 +Lp1Fi: LD (FindSv),BC ;save hidden space status + CALL GetNx + CALL FUCase +LdChar: CP 0 ;<---- + JR Z,Lp1Fi1 ;got one +Lp1Fi0: LD A,H + XOR D + JR NZ,Lp1Fi + LD A,L + XOR E + JR NZ,Lp1Fi + JR Err4x +Lp1Fi1: PUSH BC + PUSH DE + PUSH HL + CALL FndChk ;rest of string? + POP HL + POP DE + POP BC + JR NZ,Lp1Fi0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR Found +; +BackFi: LD A,(FndStr+1) ;find lead char backwards + LD (LdChr2+1),A + PUSH HL + OR A + SBC HL,BC + PUSH HL + POP DE + POP HL + INC HL + INC HL ;adjust for kludge below + LD C,0 +Lp1BF: LD A,C + LD (FindSv),A ;clear hidden space status + OR A + JR Z,Lp1BFa + DEC C + LD A,' ' + JR Lp1BFb +Lp1BFa: DEC HL ;back up + DEC HL + LD A,(HL) + INC HL ;simulate GetNx in reverse + BIT 7,A + JR Z,Lp1BFb + INC C +Lp1BFb: AND 7Fh + CALL FUCase +LdChr2: CP 0 ;<----- + JR Z,Lp1BF1 ;got one +Lp1BF0: LD A,H + XOR D + JR NZ,Lp1BF + LD A,L + XOR E + JR NZ,Lp1BF + JP Err4x +Lp1BF1: PUSH HL + PUSH DE + PUSH BC + CALL FndChk ;rest of string? + POP BC + POP DE + POP HL + JR NZ,Lp1BF0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR FoundB +; +FndChk: LD A,(FndStr) ;is (HL) a hit? + DEC A + RET Z ;just one char: already matched + LD B,A + LD DE,FndStr+2 ;start at char2 +Lp1FC: CALL GetNx + CALL FUCase + EX DE,HL + CP (HL) + EX DE,HL + JR Z,Sk1FC + LD A,(DE) ;hmm, no match + PUSH HL + LD HL,WildCd ;consider wildcard + CP (HL) + POP HL + RET NZ ;NOPE. +Sk1FC: INC DE ;match, keep on + DJNZ Lp1FC + RET ;YES. +; +; +Found: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back to char1 + DEC HL ;put cursor BEFORE char1 + CALL MoveR + LD HL,(AftCu) ;Hidden space there? + BIT 7,(HL) + JR Z,Found1 + OR A ;need to be on it? + JR Z,Found1 + LD A,(HL) + AND 7FH ;Yep, unhide it + LD (HL),' ' + CALL Insrt1 +Found1: CALL MidV ;Center on screen +Chged0: CALL CountL ;Adjust line number +Chged: CALL RitH ;Adjust cursor + LD HL,ChgFlg + BIT 0,(HL) + JP Z,SetAl ;find? redisplay + LD HL,FndStr + XOR A + ADD A,(HL) + JR Z,Chgd1 + LD C,A ;change: CR involved? + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl ;yes +Chgd1: LD HL,ChgStr + XOR A + ADD A,(HL) + JP Z,SetCu ;no + LD C,A + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl + JP SetCu +; +FoundB: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back before char1 + CALL MoveL ;Move to found string + LD HL,(AftCu) ;hidden space there? + BIT 7,(HL) + JR Z,FounB1 + OR A ;yes, need to be on it? + JR Z,FounB1 + LD A,(HL) ;Yes, unhide it + AND 7Fh + LD (HL),' ' + CALL Insrt1 +FounB1: CALL MidV ;Center on screen + CALL RitH ;Adjust cursor + CALL CountR ;Adjust line number + JP SetAl +; +FndSub: LD HL,FindQ ;Get Find string + CALL Prompt + CALL GetStr ;Put string in 80 + DW FndStr+1 + LD DE,FndStr + LD (DE),A + RET Z ;no string + INC DE + XOR A + LD (ChgFlg),A ;find, not change + LD (FBackw),A ;not (yet) backwards + LD (FGlobl),A ;not (yet) global + LD A,0C3H ;(JP) + LD (FUCase),A ;ignore case + LD HL,DMA + LD A,(HL) + CP '/' + JR NZ,FndSb2 + INC HL +FndSL1: LD A,(HL) + INC HL + OR A + RET Z + CP '/' ;do /options/ + JR Z,FndSb2 + CALL UCase + CP 'C' + JR Z,FOptC + CP 'B' + JR Z,FOptB + CP 'G' + JR Z,FOptG + SCF + RET +FOptC: LD A,0C9H ;(RET) respect case + LD (FUCase),A + JR FndSL1 +FOptB: LD (FBackw),A ;backward + JR FndSL1 +FOptG: LD A,0FFH + LD (FGlobl),A + JR FndSL1 +FndSb2: LD B,0 +FndSL2: LD A,(HL) ;move string in + INC HL + CALL FUCase + OR A + LD (DE),A + JR Z,FndSLF + INC DE + INC B + JR FndSL2 +FndSLF: LD A,B ;count + LD (FndStr),A + RET +; +FUCase: JP UCase ;<--- becomes RET +; +;Change found string [this entry NOT currently in use] +; +;Change: CALL ChgSub ;get string +; +RepChg: LD HL,(BefCu) ;mark position + LD (LastCu),HL + LD A,(FndStr) + OR A + JR Z,RpCh1F ;no string + LD B,A ;count to erase +RpCh1: PUSH BC + CALL EChar + POP BC + JP C,Error7 + DJNZ RpCh1 +RpCh1F: LD HL,ChgStr ;point to string + LD A,(HL) ;count to replace + OR A + JR Z,RpCh3 ;quit if no new string + LD B,A + PUSH BC +RpCh2: INC HL + PUSH BC + PUSH HL + LD A,(HL) + CALL Insrt + POP HL + POP BC + CALL C,Error1 ;out of memory + DJNZ RpCh2 + POP BC + LD A,(FBackw) + OR A +RpCh3: JP Z,Chged0 +RpCh4l: PUSH BC + CALL Left + POP BC + RET C + DJNZ RpCh4l + CALL CountR + JP Chged +; +ChgSub: LD A,0FFH ;say we've done a change + LD (ChgFlg),A + LD HL,ChgQ + CALL Prompt + CALL GetStr ;Put string in 80 + DW ChgStr+1 + PUSH AF + CALL ShoLn1 ;may need this later + POP AF + LD DE,ChgStr + LD (DE),A + RET Z ;do not LDIR with B=0 + INC DE + LD C,A + LD B,0 + LD HL,DMA + LDIR ;Move string in + XOR A + LD (DE),A ;zero terminate it + RET +; +;Global replace +; +Rplace: LD A,0FFH + LD (YNFlg),A + CALL FndSub + JP C,Error7 + LD A,(FndStr) + OR A + JP Z,ShoLn1 ;no string? + LD A,(FGlobl) ;global replace? + OR A + JR Z,RplcGo + LD A,(FBackw) ;backward? + OR A + JR Z,RplTop + CALL Bottom ;goto end + JR RplcGo +RplTop: CALL Top ;goto start +RplcGo: LD A,(MacFlg) + PUSH AF ;(got to do this before Chg Input) + CALL ChgSub + POP AF + OR A + CALL NZ,Global ;within Macro: force Global + CALL RepFCh ;do first one + JR C,RplLpQ ;none found? +RplLp: CALL Keybd + CP ESC ;abort? + JR Z,RplLpX + XOR A + LD (FGlobl),A ;turn off global + CALL RepFCh + JR NC,RplLp +RplLpX: LD A,(EdErr) + CP 4 ;suppress "not found" error + CALL Z,Error0 +RplLpQ: CALL XLoud ;turn CONOut back on + JP SetAl +; +;Repeat last find/replace +; +Repeat: LD A,0FFH + LD (YNFlg),A + CALL RepFCh + LD A,(YNFlg) + OR A + JR Z,RplLp + RET +; +RepFCh: CALL RpFind ;[entry from Replace] + LD A,(EdErr) ;return Carry if not found or error + OR A + SCF + RET NZ ;not found + LD A,(ChgFlg) + OR A + RET Z ;find only, all done + CALL ShoAll ;replace, gotta show it + CALL YesNo ;..and ask + JR C,RepFC0 + JR Z,RepFC1 + LD A,(FBackw) ;NC,NZ = No + OR A + LD A,(FndStr) + CALL Z,GoRtA ;skip ahead + OR A + RET +RepFC0: RET NZ ;C,NZ means Esc: abort +RepFC1: CALL RepChg ;Z (C or NC) means Yes + LD A,(EdErr) + CP 1 ;error? set carry + CCF + RET +; +YesNo: LD A,(YNFlg) ;return C=abort, Z=yes + OR A + SCF + RET Z ;"*" mode? Z,C = yes,global + CALL Loud ;MUST see this +YesNo1: LD DE,DspEsc ;entry for hyphenation Y/N + CALL GoTo + CALL MakAlt + LD HL,YNMsg ;say "Y/N/*" + LD B,4 + CALL BHLMsg + CALL UnAlt + CALL Cursr + CALL KeyIn ;MUST come from keyboard + PUSH AF + LD DE,DspEsc ;clean up + CALL GoTo + LD A,(NoHdrF) + OR A + CALL Z,MakAlt + LD B,4 + CALL BBlank + CALL UnAlt + POP AF + CP ESC ;abort? + JR NZ,YN1 + OR A + SCF ;C, NZ = yes + RET +YN1: CP '*' + JR NZ,YN2 +Global: CALL XQuiet + XOR A + LD (YNFlg),A ;set global flag + SCF + RET ;Z,C = yes,globally +YN2: AND 5FH ; upper case + CP 'Y' + RET Z ;Z,NC = yes,once + CP 'N' + JR NZ,YesNo1 + OR A + RET ;NZ,NC = no +; +; +;Variable Tabs. +;"VTList" is a list of settings, increasing order, zero fill +; +VTTog: LD HL,VTFlg ;toggle variable on/off + CALL ToggHL + CALL RulFix +VTshow: LD A,(VTFlg) ;requires header display + OR A + LD HL,VTon + JR NZ,VTsho1 + LD HL,TogOff +VTsho1: LD DE,DspTab + JP TogSho +; +; +VarTab: CALL ColCnt ;advance to next VT setting + LD B,VTNum + LD HL,VTList +VTlp1: CP (HL) ;find it + JR C,VTb2 + INC HL + DJNZ VTlp1 + RET ;none, no action. +VTb2: LD A,(HL) + PUSH HL + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl ;may need to scroll + POP HL + LD A,(InsFlg) + OR A ;is insert on? + LD A,(HL) ;column to move to + JP Z,MvCol + JP MvColI ;move by inserting spaces +; +TaBack: CALL ColCnt ;retreat to last tab setting + DEC B + RET Z + LD A,(VTFlg) + OR A + JR Z,BThard + LD C,B + XOR A + LD B,VTNum + LD HL,VTList+VTNum-1 +BTlp1: CP (HL) ;skip 0s + JR NZ,BTb1 + DEC HL + DJNZ BTlp1 + RET ;no tabs at all, no action +BTb1: LD A,C +BTlp2: CP (HL) ;find it + JR NC,BTb2 + DEC HL + DJNZ BTlp2 + JP QuikLf ;no more left, go to col 1 +BTb2: LD A,(HL) ;that's it + JR BTabX +BThard: LD A,(TabCnt) ;back to last multiple + CPL + DEC B + AND B + INC A +BTabX: PUSH AF + CALL QuikLf ;go all the way back + POP AF + JP MvCol ;then go there +; +; +VTSet: LD HL,ColQ ;Set tab(s) + CALL Prompt + CALL GetStr + DW 0 + LD A,(CurCol) ;default is Here + JR Z,VTSt01 ;nothing entered? + LD HL,DMA + LD A,(HL) + CP '@' + JR Z,VTSInt ;interval specified? + CP '#' + JR Z,VTSGrp ;group? + EX DE,HL + CALL GetNN ;nope, single tab set + JR Z,VTErr +VTSt01: CALL VTStCl + JR C,VTErr + JR VTStX +VTStCl: LD E,A ;[sbr: set VT here] + LD A,(VTList+VTNum-1) + OR A + SCF + RET NZ ;must be room in list + LD BC,VTNum + LD HL,VTList +VTSlp1: LD A,(HL) ;find it + OR A + JR Z,VTSt1 + CP E + RET Z ;(quit if already set) + JR NC,VTSt2 + INC HL + DEC C + JR NZ,VTSlp1 + DEC HL ;last place +VTSt1: LD (HL),E ;add at end + OR A + RET +VTSt2: LD A,E + LD HL,VTList+VTNum-2 ;make room here + LD DE,VTList+VTNum-1 + DEC BC + LDDR + LD (DE),A ;put it in + OR A + RET +VTErr: JP Error7 +; +VTSInt: LD DE,VTList ;"@" interval specified + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL + INC DE + CALL GetNN + OR A + JR Z,VTStX + LD C,A + INC A ;"@n" means n+1, 2n+1 etc + LD DE,VTList + LD B,VTNum +VTSlp2: LD (DE),A + INC DE + ADD A,C + JR C,VTStX + DJNZ VTSlp2 + JR VTStX +VTSGrp: LD DE,VTList ;'#' group specivied + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL +VTGlp: INC DE + CALL GetNN ;get one from list + OR A + PUSH DE + CALL NZ,VTStCl ;set it? + POP DE + JR C,VTErr + LD A,(DE) + OR A + JR NZ,VTGlp +VTClX: +VTStX: CALL ShoLn1 ;all done + JP RulFix +; +; +VTClr: LD HL,ColQ ;clear a tab + CALL Prompt + LD A,(CurCol) ;default is Here + CALL GetNum + JR C,VTErr + JR Z,VTErr + LD B,VTNum + LD HL,VTList +VTClp1: CP (HL) ;find it + JR Z,VTCl2 + INC HL + DJNZ VTClp1 + JR VTErr ;wasn't set +VTCl2: LD (HL),0 + DEC B + JR Z,VTClX ;was last, all done + LD D,H + LD E,L + INC HL + LD C,B + LD B,0 + LDIR ;delete it + XOR A + LD (DE),A ;zero fill + JR VTClX +; +; +; INSERTION FUNCTIONS +; +;Store a ctl-code in text +; +CtlP: LD HL,CPTog ;say "^P-_", get key + CALL Prefix + CALL XCase + CP DEL + JR Z,CtlP1 + CP ' ' ;error if not now ctl-char + RET Z ;(space cancels) + JP NC,Error2 ;invalid key +CtlP1: LD HL,BlkChr + CP (HL) ;don't allow block char + JP Z,Error2 ;invalid key + CP TAB ;tabs are special + JR Z,ITab + CP CR ;so are CRs + JP Z,ICRB1 + JR Sk2IC +; +IChar: CP ' ' ;Main menu entry: no control codes allowed + RET C +Sk2IC: PUSH AF + CALL ChkLM ;Check for left margin + JR NC,Sk2aIC + CALL UpToLM + CALL SetCu +Sk2aIC: POP AF + LD E,A + CP 7FH ;redo line if DEL/ctl + CCF + JR C,Sk3IC + CP ' ' +Sk3IC: CALL C,SetRCu + PUSH DE + CALL NC,XPutCh ;just show nice chars + POP DE + PUSH DE + LD A,E + CALL Insrt ;Put byte in + POP DE + RET C ;Full? + PUSH DE + LD A,(Horiz) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if at edge + CALL IncH ;Move cursor + CALL ChkIns ;adjust for insert mode + POP DE + LD A,E + CP ' ' + RET Z ;if not space + CP EOF + RET Z + LD HL,BlkChr + CP (HL) + RET Z + JP WdWrap ;check wordwrap +; +TabKey: LD A,(VTFlg) + OR A + JP NZ,VarTab ;maybe variable tabbing +ITab: LD A,TAB + CALL Insrt + RET C + CALL SetCu + CALL ChkIns + LD A,(Horiz) + LD HL,TabCnt + ADD A,(HL) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if needed + JP TabH +; +;Do a carriage return +; +ICR: LD A,(DSFlg) + OR A + CALL NZ,ICR1 +ICR1: LD A,(InsFlg) + BIT 7,A ;Is insert flag on? + JR NZ,ICRB1 + CALL QuikRt ;noo... + LD A,(FMode) + CP 'N' + JR Z,ICR01 +ICR00: CALL FetchB ; in Document: make HCR + CP ' ' + JR NZ,ICR01 + CALL Delete + JR ICR00 +ICR01: CALL Cursr ;may need to show new HCR + CALL NdCnt ;Are we at end? + JR C,ICRB1 ;Yes, add a new line + CALL IfScl ;no, just move cursor + CALL Right + JP ChkAI +ICRB: CALL ICRB1 +ICRB0: LD A,(DSFlg) + OR A + RET Z + CALL InsSpc ;doublespace? add soft CRLF +ICRB1: XOR A + LD (NumTab),A + CALL IfScl + LD A,CR + CALL Insrt ;Put it in + RET C + LD A,(Vert) + LD HL,TxtLns + CP (HL) + CALL Z,ScrlU2 ;end of screen? scroll + CALL SetDn + CALL IncV ;Move cursor down + CALL LftH ;Move to start of line + JR ChkAI +ICRA: CALL ICRA1 + LD A,(DSFlg) + OR A + RET Z + LD A,' ' ;doublespace? add soft CRLF + CALL InsrtA +ICRA1: LD A,CR ;Used as ^N routine only + CALL InsrtA + RET C + CALL FetchB + CP CR + JR NZ,ICRAx + LD HL,InsL + CALL ScrUDx + RET NC +ICRAx: JP SetDn +; +; +;Check for insert mode +; +ChkIns: LD A,(InsFlg) + OR A ;INSERT on? + JP NZ,SetRCu ;Yes, all done + LD HL,(BefCu) + LD A,(HL) + CP EOF + JP Z,SetRCu + LD HL,BlkChr + CP (HL) + JP Z,SetRCu + LD HL,(AftCu) ;No, Look at the character + LD A,CR + CP (HL) ;Is it a CR? + RET Z ;Yes, leave it + LD A,TAB + CP (HL) ;TAB? redo line + CALL Z,SetCu + LD A,(ShoFlg) + PUSH AF + CALL EChar ;overwrite character + POP AF + LD (ShoFlg),A + RET +; +;Check for auto indent mode +; +ChkAI: LD A,(AIFlg) ;AI on? + OR A + RET Z + LD A,(DSFlg) + OR A + RET NZ ;done if doublespacing + CALL NdCnt ;add text at cmd? + JR C,ChkAll + LD A,(InsFlg) ;insert on? + OR A + JR Z,ChkALp +ChkAll: CALL QuikLf ;#inline version of IndPL + CALL BgCnt ;# / + RET C ;# / + CALL Up ;#/ + CALL CntSpc ;get indentation + PUSH BC ;back to this line + CALL QuikRt ;#inline version of IndNL + CALL Right ;#these are just like RfmNL/PL, + POP BC ;#except they DON'T skip over blank lines + LD A,B + CP TAB + LD A,(NumTab) + JR Z,ChkAtb + INC A + JP MvColI ;do it +ChkALp: CALL Fetch ;NO, just move to first nonspace + CP ' ' + JR Z,ChkAI1 + CP TAB + RET NZ +ChkAI1: CALL Right + JR ChkALp +ChkAtb: OR A + RET Z + DEC A + PUSH AF + CALL ITab + POP AF + JR ChkAtb +; +; +; DELETION FUNCTIONS +; +;UNdelete a character +; +Undel: CALL GpCnt ;Anything to undelete? + RET C + CALL ELret2 + LD HL,(AftCu) + DEC HL ;here goes + LD (AftCu),HL + LD A,(HL) + CP CR ;was it a CR? + JP Z,SetDn + JP SetRCu +; +UndlLn: CALL GpCnt ;Do a whole line + RET C + CALL ELret2 + LD A,B + OR A ;max 256 chars + JR Z,UdLn1 + LD BC,256 +UdLn1: LD HL,(AftCu) + DEC HL + DEC HL + LD A,CR + CPDR ;look for CR + RET NZ + INC HL + INC HL ;start of line + LD (AftCu),HL + JP SetDn +; +; +;Erase character to left of cursor (C=error) +; +Delete: CALL Left + RET C ;Fall through to EChar +; +; +;Erase character to right of cursor (C=error) +; +EChar: CALL NdCnt ;Anything to erase? + RET C + CALL ELret2 + CALL SetRCu + LD HL,(AftCu) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1EC + CALL GpShft ;unhide it + LD HL,(AftCu) + LD A,(HL) + LD (HL),' ' + AND 7FH + DEC HL + LD (HL),A + RET +Sk1EC: LD A,(HL) + INC HL ;Move up, past character + LD (AftCu),HL ;Store updated value + CP CR + CALL Z,SetDn ;ate a CR? + OR A + RET +; +GpShft: CALL GpCnt ;Shift gap contents left (for Undel sake) + RET C + DEC BC + LD A,B + OR C + SCF + RET Z + LD HL,(BefCu) + INC HL + LD A,B + SUB 08H ;Maximum 2k worth + JR C,GpS1 + LD B,08H + ADD A,H + LD H,A +GpS1: LD D,H + LD E,L + INC HL + LDIR + OR A + RET +GpCR: CALL GpShft ;mark BOL for ^QU + RET C + LD A,CR + LD (DE),A + RET +; +; +;Line erase functions +; +Eline: LD HL,(AftCu) ;first left end + PUSH HL + CALL QuikLf + POP HL + LD (AftCu),HL + LD E,1 ;now right end + CALL CrRit + JR NC,Eline1 ;found CR? good + JR NZ,Eline2 ;EOF? return + LD HL,(EndTx) ;Cursor is in last line + INC HL +Eline1: LD (AftCu),HL +Eline2: CALL ELret2 + LD HL,DelL + CALL ScrUDx + JP C,SetDn + LD A,(TxtLns) + LD B,A + JP ShoLn +; +EOLine: LD E,1 ;Erase to EOL + CALL CrRit + JR NC,Sk1EO ;Found CR? good + RET NZ ;EOF? return + LD HL,(EndTx) ;cursor is in last line + LD A,(HL) + CP CR ;Is last byte a CR? + INC HL + JR NZ,Sk2EO ;No +Sk1EO: DEC HL ;Point at trailing CR +Sk2EO: PUSH HL + JR EBLret ;delete to there +; +EBLine: LD HL,(AftCu) ;Erase to BOL + PUSH HL + CALL QuikLf +EBLret: CALL GpCR ;delete to there + POP HL + CALL SetRCu +ELret: LD (AftCu),HL +ELret2: LD A,0FFh + LD (Modify),A + RET +; +E2Char: LD HL,CQTTog ;Erase to character + CALL Prefix + CP ESC + RET Z + CP 'U'-40h ;^U? + RET Z + LD (PrevCh),A +E2CLp: CALL EChar ;always eat first char + CALL NdCnt + RET C + CALL Keybd + CP ESC + RET Z + CALL Fetch + LD HL,PrevCh + CP (HL) + JR Z,E2CLpF + LD (PrvCh2),A + JR E2CLp +E2CLpF: CP CR + RET NZ + LD A,(FMode) + CP 'N' + RET Z + LD HL,PrvCh2 ;CR means HARD CR in Doc modes + LD A,(HL) + CP ' ' + RET NZ + LD (HL),CR + JR E2CLp +; +; +; BLOCK FUNCTIONS +; +;MARK Block start and termination +; +Block: CALL UnBlAb ;Remove any markers above + CALL UnBlB1 ;Remove all but last marker below +Blk01: LD A,(BlkChr) ;mark it now + JP Sk2IC +; +Termin: CALL UnBlA1 ;Remove all but first marker above + CALL UnBlBl ;Remove any markers below + JR Blk01 +; +Unmark: CALL UnBlAb ;Remove all block markers + CALL UnBlBl + RET +; +;Move cursor to block start +; +QikBlk: CALL IsBlk + EX DE,HL + INC HL + BIT 0,A + JP Z,Error7 ;must be marked + BIT 6,A + JR NZ,QikB1 +QikB0: CALL MoveL ;before cursor (entries from QuikMk) + JR QikB2 +QikB1: DEC HL ;after cursor + CALL MoveR +QikB2: CALL CountS ;Adjust count + CALL RitH ;Adjust cursor + CALL MidV + JP SetAl +; +;Basic query returns: +; A= {bit 7=gap in block; 6=start after gap; 1=block marked; 0=start marked} +; DE,HL= start, end (if marked) +; +IsBlk: LD IX,IsBVal + LD (IX),0 ;result byte + CALL BgCnt + JR C,IsB1 + LD A,(BlkChr) ;look before cursor + CPIR + JR NZ,IsB1 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + JP PO,IsB0 + CPIR + JR NZ,IsB0 + SET 1,(IX) ;found end + DEC HL +IsB5: LD A,(IX) ;exit + RET +IsB0: SET 7,(IX) ;straddle + JR IsB1a +IsB1: SET 6,(IX) ;block after cursor +IsB1a: CALL NdCnt ;now look after cursor + JR C,IsB5 + LD HL,(AftCu) +IsB3: LD A,(BlkChr) ;search loop + CPIR + JR NZ,IsB5 + BIT 0,(IX) + JR NZ,IsB2 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + LD A,B + OR C + JR Z,IsB5 + JR IsB3 +IsB2: SET 1,(IX) ;found end + DEC HL + JR IsB5 +; +; +UnBlA1: CALL BgCnt ;undo all but 1st marker above + RET C + LD A,(BlkChr) + CPIR + JP PE,UnBA01 ;one? leave and look for more + RET ;no more, finished +UnBlAb: CALL BgCnt ;undo all markers above + RET C +UnBA01: LD A,(BlkChr) + CPIR + RET NZ ;none, finished + CALL SetAl + PUSH BC + PUSH HL + LD D,H + LD E,L + DEC DE + CALL LCnt + JR C,UnBA02 + LDIR ;remove it +UnBA02: DEC DE + LD (BefCu),DE + POP HL + DEC HL + POP BC + LD A,B + OR C + JR NZ,UnBA01 + RET +; +UnBlB1: CALL NdCnt ;undo all but 1st marker below + RET C + LD HL,(EndTx) + LD A,(BlkChr) + CPDR + JP PE,UnBB01 ;one, leave and continue + RET ;none, finished +UnBlBl: CALL NdCnt ;undo all markers below + RET C + LD HL,(EndTx) +UnBB01: LD A,(BlkChr) + CPDR + RET NZ ;none, finished + CALL SetDn + PUSH BC + PUSH HL + LD D,H + LD E,L + INC DE + CALL RCnt + JR C,UnBB02 + LDDR ;remove it +UnBB02: INC DE + LD (AftCu),DE + POP HL + INC HL + POP BC + LD A,B + OR C + JR NZ,UnBB01 + RET +; +;Erase Block +; +EBlock: CALL IsBlk + BIT 1,A ;must be marked + JP Z,Error7 + BIT 7,A + JR NZ,EPrt3 ;straddles cursor? + BIT 6,A ;is it after cursor? + JR NZ,EPrt2 + LD B,H ;no, before cursor + LD C,L + LD HL,(BefCu) + SBC HL,BC ;bytes to move + PUSH HL + LD H,B + LD L,C + POP BC + JR Z,EPrt1a + INC HL + LDIR +EPrt1a: DEC DE + LD (BefCu),DE + JR EPrtRt +EPrt2: EX DE,HL ;it's after cursor + LD BC,(AftCu) + PUSH HL + SBC HL,BC + LD B,H + LD C,L + POP HL + JR Z,EPrt2a + DEC HL + LDDR +EPrt2a: INC DE + LD (AftCu),DE + JR EPrtRt +EPrt3: DEC DE ;cursor straddles it + LD (BefCu),DE + INC HL + LD (AftCu),HL +EPrtRt: CALL RitH ;Adjust cursor + CALL CountS + CALL ELret2 + JP SetAl +; +;Block Copy +; +Copy: CALL IsBlk + AND 82H ;must be marked, not straddled + CP 2 ;(bit 1 set, 7 clear) + JP NZ,Error7 + CALL CmpLng ;compute length + RET Z ;was empty + CALL CpSafe + JR NC,Copy02 ;okay, go do it + CALL Cmprs ;try to get more room + CALL IsBlk + CALL CmpLng ;compute length now + CALL CpSafe ;well? + JP C,Error1 ;REALLY won't fit +Copy02: LDDR + INC DE + LD (AftCu),DE + CALL RitH ;adjust cursor + CALL CountS + CALL ELret2 + JP SetDn +; +CmpLng: DEC HL + INC DE + PUSH HL + INC HL + SBC HL,DE ;compute length now + LD B,H + LD C,L + POP HL + LD DE,(AftCu) + DEC DE + RET +; +CpSafe: PUSH HL ;Set C if BC bigger than gap + PUSH BC + CALL GpCnt + LD H,B + LD L,C + POP BC + SCF ;(just to be safe) + SBC HL,BC + POP HL + RET +; +;Block Move +; +MovBlk: CALL Copy ;first copy + LD A,(EdErr) + OR A + RET NZ + JP EBlock ;then delete +; +; +; DISK FUNCTIONS +; +;View Directory +; +Dir: LD HL,DirQ + CALL Prompt + LD A,8+1 ;ask for Duu: or NDR name (8 chars max) + CALL GSEnt + DW 0 + PUSH AF + LD A,(FCB) ;defaults + LD B,A + LD A,(FCBU) + LD C,A + POP AF + JR Z,Dir00 + LD B,A + LD HL,DMA +DirULp: LD A,(HL) + CALL UCase ;new D (?) + LD (HL),A + INC HL + DJNZ DirULp + CP ':' + JR NZ,Dir0x ;jump if not a ":" + DEC HL + LD (HL),0 +Dir0x: LD DE,DMA + CALL NdrChk + JR NZ,Dir00 ;is an NDR name + LD A,(DE) ;new D (?) + CP '0' + JP C,Error7 ;<'0', not even a user # + CP '9'+1 + JR C,Dir0 ;jump is just a user # + SUB 'A'-1 + CP 17 ;drive letter > 'P'? + JP NC,Error7 ;yep.. a no no + LD B,A + INC DE +Dir0: PUSH BC + CALL GetNN ;new uu + POP BC + JR NC,Dir0a + LD A,(FCBU) ; fetch user # + JR Dir0y +Dir0a: CP 32 ;0-31 ok + JP NC,Error7 +Dir0y: LD C,A +Dir00: PUSH BC + LD E,C + LD C,USRN + CALL BDOSep ;set user + POP BC + LD HL,FCBBuf + LD (HL),B ;and drive + INC HL + LD (HL),'?' ;set up *.* FCB + LD DE,FCBBuf+2 + LD BC,10+1 + LDIR ; wildcard filename, type and extent + LD (HL),0 + LD BC,19 + LDIR ; zero out S1, S2, RC and alloc. map + CALL MakAlt + LD DE,010Fh ;position to col 2 + LD A,(RulFlg) + OR A + JR Z,Dir1 + INC D ;move down a line to preserve the ruler +Dir1: CALL GoTo + LD A,(View) ;initialize + SUB 14 + LD (HPos),A + LD A,(TxtLns) ;lines free on screen + DEC A + LD (DirLns),A + LD A,(View) ;columns free + LD HL,DirCls + LD (HL),A + XOR A + RRD ;cols=view/16 + LD C,(HL) + DEC C + PUSH BC + LD DE,FCBBuf ;first file? + LD C,SRCH + CALL BDOS ; search for first matching file + POP BC + CP 0FFH + JR NZ,Sk1Dir + CALL DsplC + DB 'N','o'+X,'File',CR,0 + JP Sk3Dir +; +Lp3Dir: PUSH BC + LD DE,FCBBuf ;next one... + LD C,SRCN + CALL BDOS ; search for next matching file + POP BC + CP 0FFH + JP Z,DirEnd ;all done? +Sk1Dir: ADD A,A + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;desired FCB is at 32*A + DMA + LD E,A + LD D,0 + LD HL,DMA + ADD HL,DE + INC HL ;point to filename + EX DE,HL + LD HL,9 + ADD HL,DE ;test SYS attribute + BIT 7,(HL) + JR Z,Sk2Dir + LD A,(DirSys) ;yes, include? + OR A + JR Z,Lp3Dir ;no +Sk2Dir: EX DE,HL + PUSH HL + LD B,11 +Lp4Dir: RES 7,(HL) ;strip flags + INC HL + DJNZ Lp4Dir + LD DE,4 + ADD HL,DE + LD (HL),0 ;terminator + DEC HL + LD A,' ' ;separator + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD D,H + LD E,L + DEC HL + LD A,C ;save DirCls + LD BC,3 ;move TYP + LDDR + EX DE,HL + LD (HL),'.' ;punctuate + POP HL + LD C,A ;save DirCls + PUSH BC + CALL DspLp ;SHOW IT + POP BC + DEC C + JR NZ,Lp3Dir ;finish line? + LD HL,DirLns + DEC (HL) + JR Z,DirFul ;out of room? + LD A,CR + CALL DsByt ;okay, new line + LD A,(DirCls) + LD C,A + JR Lp3Dir +; +DirFul: CALL DsplC ;ran out of lines + DB '...',CR,0 + JR Sk3Dir +DirEnd: LD A,C ;done, need CR? + LD HL,DirCls + CP (HL) + JR Z,Sk3Dir + LD A,CR + CALL DsByt +Sk3Dir: CALL UnAlt + CALL IfSpLn + LD A,(FCBU) + LD E,A + LD C,USRN ;reset user + CALL BDOSep + CALL SetAl + JP ESCLp ;wait for ESC to clear +; +;Load a new file. +; +Load: LD A,(Modify) + OR A + JR Z,LoadY + LD HL,QuitQ ;warn if old file was changed + CALL Prompt + CALL Confrm + JP NZ,ShoLn1 +LoadY: JP Restrt ;go do it +; +;Erase a disk file. +; +Era: CALL SavNam ;save old FCB + LD HL,EraQ + CALL NewNam + LD A,(EdErr) + OR A + JR NZ,EraDon + LD (FCBs1),A ;zero S1 + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD C,FDEL + CALL BDOSfc + INC A + CALL Z,Error7 +EraDon: CALL GetNam ;restore FCB + JP ShoLn1 +; +; +;Read text from disk file to cursor location. +; +Read: CALL SavNam ;save old FCB + LD HL,ReadQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,RdDone +; +LoadIt: CALL IOon ;say wait + CALL Cmprs ;need all our room + CALL GpCnt + JR C,Sk1Rd ;No room? + LD HL,(BefCu) ;Start here + CALL MSIn ;Read it in + JR NZ,Sk2Rd ;Worked? +Sk1Rd: CALL Error1 ;no, out of room + JR RdDone +Sk2Rd: JR NC,Sk3Rd ;Okay? + CALL Error3 ;no, I/O error + JR RdDone +Sk3Rd: LD DE,(BefCu) ;Get old BefCu + LD (BefCu),HL ;Set new one + EX DE,HL + INC HL ;Point at first byte loaded + CALL MoveL ;Move the cursor +RdDone: CALL GetNam ;restore FCB + CALL IOoff + CALL ELret2 + JP SetAl +; +; +;Write the whole file out to disk. +; +Save: LD A,(FCB+1) ;must have filename + CP ' ' + JR NZ,Save00 + CALL ChgNam + LD A,(EdErr) + OR A + RET NZ +Save00: LD A,(Modify) + OR A + JR NZ,Save01 + LD HL,UnchgQ ;hey, no changes! + CALL Prompt + CALL Confrm + PUSH AF + CALL ShoLn1 + POP AF + RET NZ +Save01: CALL IOon ;say wait + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL NdCnt ;count number of bytes + JR NC,Save02 + LD BC,0 +Save02: LD HL,(AftCu) ;point at first byte + CALL MSOut ;write it out + JR NC,Save03 + CALL Error3 ;I/O error + JR Save04 +Save03: XOR A + LD (Modify),A ;clean slate +Save04: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + JP IOoff +; +; +;Write block text to a disk file. +; +Write: CALL SavNam ;save orig FCB + LD HL,WritQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,WrXit + CALL IOon ;say wait + LD HL,(AftCu) ;save position + LD (LastCu),HL + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL IsBlk + BIT 1,A ;must be marked + JR Z,WrOops + INC DE ;point to it + SBC HL,DE ;size of block + EX DE,HL + LD B,D + LD C,E + CALL MSOut + JR NC,WrDone +WrOops: CALL Error7 +WrDone: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + CALL IOoff +WrXit: CALL GetNam ;restore orig FCB + JP ShoLn1 +; +; +SavNam: LD HL,FCB ;Preserve main filename + LD DE,FCBBuf + LD BC,12 + LDIR ; copy drive, file name and type + XOR A + LD (FCBd0),A + LD A,(FCBU) ;and user, W/A, FilFlg + LD (DE),A ; set user number in FCBBuf+13 + INC DE + LD A,(FMode) + LD (DE),A ; set S1 + INC DE + LD A,(FilFlg) + LD (DE),A ; set S2 + RET +GetNam: LD HL,FCBBuf ;And restore them + LD DE,FCB + LD BC,12 + LDIR + XOR A + LD (FCBd0),A + LD A,(HL) + LD (FCBU),A + LD E,A + INC HL + LD A,(HL) + LD (FMode),A + INC HL + LD A,(HL) + LD (FilFlg),A + LD C,USRN + JP BDOSep +; +; +;Accept a new file name to be used for disk i/o. +; +ChgNam: CALL SavNam + LD HL,NameQ + CALL NewNam + LD A,(EdErr) + OR A + CALL NZ,GetNam ;bad? restore + CALL DfltM ;may have changed modes + CALL DoHdr + CALL ELret2 + JP ShoLn1 +; +NewNam: CALL Prompt ;subroutine entry + LD A,24+1 + CALL GSEnt ;Ask for input + DW FNamBf + JP Z,Error7 ;Error if no input + LD B,A + PUSH BC + LD HL,DMA ;uppercase it +NNUlp: LD A,(HL) + CALL UCase + LD (HL),A + INC HL + DJNZ NNUlp + POP BC ;restore length + LD HL,DMA + LD A,(HL) + CP '/' ;watch for mode only + JR NZ,NNMod + INC HL + CP (HL) ;second '/' + DEC HL + JR NZ,NNMod2 +NNMod: LD A,B + CALL Parse ;parse DU:FN.T /O + JP C,Error7 ;check bad entry + XOR A + LD (FilFlg),A ;kill fileflg + RET +NNMod2: INC HL + LD A,(HL) ;do mode only + CP 'W' ;WordStar + JR Z,NNMdOK + CP 'A' ;ASCII + JR Z,NNMdOK + CP 'N' ;non document + JP NZ,Error7 +NNMdOK: LD (FMode),A + RET +; +DfltM: LD HL,0101H + LD (LMSav),HL ;margins set + LD A,(FMode) ;doc or nondoc mode? + SUB 'N' + JR Z,Dflt2 + XOR A + LD (AIFlg),A + DEC A + LD (VTFlg),A + LD A,(HCDflt) + LD (HCRFlg),A ;HCR display? + LD A,(RtMarg) ;If RM set, avoid wierd WW/AI conflict + DEC A + JR NZ,DfltX + LD HL,(DfltLM) ;from NONdoc: reset margins + LD (LfMarg),HL +DfltX: LD A,';' ;punctation chars: , ; : - . ? ! + JR DfltX2 +Dflt2: LD (LfMarg),HL ;NONdocument mode + LD (VTFlg),A ;varitabs off + LD (HCRFlg),A ;HCR display off + DEC A + LD (AIFlg),A ;auto indent ON + LD A,':' ;punctation chars: , : - . ? ! (NOT ;) +DfltX2: LD (PunTbl+1),A + JP RulFix +; +; +;Toggle case of character at cursor +; +UpLow: CALL Fetch ;also points to byte with (HL) + AND 5FH ;strip off both hidden space and case + CP 'A' + JR C,UpLo1 ;leave alone if not letter + CP 'Z'+1 + JR NC,UpLo1 + BIT 5,(HL) ;toggle case + RES 5,(HL) + JR NZ,UpLo0 ;was lower, now up + SET 5,(HL) ;was upper, now low +UpLo0: CALL ELret2 +UpLo1: CALL Right ;move right for next(?) + JP SetRCu +; +; +;Set page length +; +PgSet: LD HL,PgLnQ + CALL Prompt + LD A,(FormL) ;default value + CALL GetNum + JP C,Error7 + LD (PgLen),A + CALL DoHdr + JP ShoLn1 +; +; +;VARIOUS TOGGLES +; +;Simple on/off toggles +; +HCRTog: CALL SetAl ;HCR display + LD HL,HCRFlg +ToggHL: LD A,(HL) + CPL + LD (HL),A + RET +; +;These require header display +; +HypTog: LD HL,HypFlg ;hyphenation + CALL ToggHL +HYshow: LD HL,HYon + LD A,(FMode) + CP 'N' ;irrelevant in N mode + JR Z,HYsho0 + LD A,(HypFlg) + OR A + JR NZ,HYsho1 +HYsho0: LD HL,TogOff +HYsho1: LD DE,DspHyp + JP TogSho +; +IToggl: LD HL,InsFlg ;INSERT + CALL ToggHL +ITshow: LD A,(InsFlg) + LD HL,MacFlg + BIT 7,(HL) + JR Z,ITsho0 + LD A,(SavIns) +ITsho0: OR A + LD HL,INSon + JR NZ,ITsho1 + LD HL,TogOff +ITsho1: LD DE,DspIns + JP TogSho +; +DblTog: LD HL,DSFlg ;double spacing + CALL ToggHL + OR A + CALL NZ,AIoff ;turn off auto ident if double spacing +DblSho: LD A,(DSFlg) + OR A + LD HL,DSon + JR NZ,DSsho1 + LD HL,TogOff +DSsho1: LD DE,DspSpc + JP TogSho +; +AIoff: LD HL,AIFlg + INC (HL) + DEC (HL) + RET Z ;fall thru to turn off auto indent if it's on +; +AITog: LD HL,AIFlg ;auto indentation + CALL ToggHL + OR A + JR Z,AIshow + LD HL,DSFlg ;is double spacing on? + INC (HL) + DEC (HL) + CALL NZ,ToggHL ;turn it off if so + CALL NZ,DblSho ;turn off the old DS display + LD A,1 + CALL SLM1 ;reset left margin to 1 +AIshow: LD A,(AIFlg) + OR A + LD HL,AIon + JR NZ,AIsho1 + LD HL,TogOff +AIsho1: LD DE,DspInd + JP TogSho +; +PSTog: LD A,(PSokFl) + OR A + JP Z,Error2 ;invalid key + LD HL,PSFlg + CALL ToggHL + LD A,(RMSav) + DEC A + RET NZ ;margins released? then we're done +PSDisp: LD A,(FMode) + CP 'N' + JR Z,PSTogU ;no PS in nondocument mode + LD A,(PSFlg) + OR A + LD HL,PSon ;proportional spacing on + JR NZ,PSTogX +PSTogU: LD HL,TogOff ;turn off margin release +PSTogX: LD DE,DspMrg + JP TogSho +; +; +;TEXT FORMAT functions +; +SetRM: CALL StMrCm ;Same for left and right + LD C,A + LD A,(LfMarg) + CP C + JR C,SRM1 ;inside LM? + LD A,1 + LD (LfMarg),A ;if so, reset LM +SRM1: LD A,C + LD (RtMarg),A + JR StMgEn +; +SetLM: CALL StMrCm ;Same for left and right + LD HL,RtMarg + CP (HL) + JR NC,MrgErr +SLM1: LD (LfMarg),A + DEC A + CALL NZ,AIoff +StMgEn: CALL RulFix + JP ShoLn1 +; +StMrCm: LD A,(FMode) ;Set right margin + CP 'N' ;(must be Document mode) + JR Z,MrgErr + LD A,(RMSav) ;okay, do it + DEC A + CALL NZ,RelM ;(undo Margin Release) + LD HL,ColQ + CALL Prompt + LD A,(CurCol) ;default: cursor column + CALL GetNum + JR Z,MrgErr + RET NC +MrgErr: POP HL + JP Error7 +; +RelM: CALL RelLM ;release both margins (Toggle) + LD HL,RtMarg + LD DE,RMSav + CALL RelSb + CALL MRshow + JP RulFix +; +RelLM: LD HL,LfMarg ;SBR: release left only + LD DE,LMSav +RelSb: LD A,(HL) ;common subroutine + CP 1 + JR Z,Rel1 + LD (DE),A ;note: if RMSav>1, margins released + LD (HL),1 + RET +Rel1: LD A,(DE) + LD (HL),A + LD A,1 + LD (DE),A + RET +; +;Check the right margin +; +ChkRM: LD A,(CurCol) ;be sure this is up to date + LD B,A + LD A,(RtMarg) + INC A + LD C,A + SUB B ;set C if over + RET NC + CALL IgnCtl ;yes, ignore ctlchars + LD A,C ;try arithmetic once again + ADD A,E + SUB B + RET ;now C set if really over +; +IgnCtl: CALL Fetch ;count ctlchars to be ignored + LD E,0 ;(up to present cursor) + LD HL,(BefCu) + JR NZ,IgnC1 +IgnCLp: LD A,(HL) ;count em + DEC HL + CP CR ;quit at BOL + RET Z +IgnC1: CP TAB ;tabs don't count + JR Z,IgnCLp + CP 20H + JR NC,IgnCLp + INC E ;others do + JR IgnCLp +; +;Check left margin, space over if needed +; +ChkLM: LD A,(LfMarg) + LD B,A + LD A,(CurCol) + SUB B ;be sure this is uptodate + RET ;ret Z if at, C if over +; +UpToLM: LD A,(LfMarg) ;git on over to the LM column +; +MvCol: PUSH AF ;move to col A saving any existing text + CALL GoCol + POP AF +MvColI: LD HL,CurCol ;move to col A inserting spaces + SUB (HL) + RET C ;we're past already + RET Z ;we're there + LD B,A + CALL SetCu ;this is going to hurt +MvClp: PUSH BC ;insert B spaces + CALL InsSpc + POP BC + RET C ;quit if out of space + CALL IncH + DJNZ MvClp + RET +; +DoLM: LD A,(LfMarg) ;create whole left margin + DEC A + RET Z + LD B,A + JR MvClp +; +;Handle former margin for reformat +; +CntSpc: CALL QuikLf ;count lead spaces/tabs on line + CALL Fetch + LD B,A + EXX + XOR A +CSpLp: LD (NumTab),A + PUSH AF + CALL Fetch + CP ' ' + JR Z,CSpL1 + CP TAB + JR NZ,CSpLpF +CSpL1: EXX + CP B + EXX + JR NZ,CSpLpF + CALL Right ;move 1 char right + POP AF + INC A ;incr # tabs + JR CSpLp +CSpLpF: CALL QuikLf ;back to start + EXX +CntSpX: POP AF + RET +; +EatSpc: OR A ;eat up to A lead spaces on line + RET Z +ESpLp: PUSH AF + CALL Fetch + CP TAB + JR Z,ESpLpF + CP ' ' + JR NZ,CntSpX +ESpLpF: CALL EChar + POP AF + DEC A + JR NZ,ESpLp + RET +; +; +;Update CurCol and return it in A and B +;(NOTE: slow. When possible, LDA CurCol.) +; +ColCnt: CALL WhatC + LD (CurCol),A + RET +; +WhatC: CALL FetchB ;col 1 is spcl case + CP CR + LD A,1 + LD B,A + RET Z + LD E,1 + CALL CrLft ;start of line + LD BC,0 +; +CCLp: CALL GetNx ;get a char + CP TAB + JR NZ,CC1 + LD A,B ;tabs are special + PUSH HL + LD HL,TabCnt + OR (HL) ;round up + POP HL + LD B,A +CC1: INC B ;count char + LD A,B + CP 254 + JR Z,CC2 ;too long? return column 255 forever + XOR A + CP C + JR NZ,CCLp ;get hidden space? + PUSH BC + CALL LCnt ;compare HL to BefCu + POP BC + JR NC,CCLp ;get another, if more exist +CC2: INC B + LD A,B ;that is curcol. + RET +; +; +;Do wordwrap if needed +; +WdWrap: LD A,(RtMarg) ;WW off if RM=1 + DEC A + RET Z + LD IY,CurCol + INC (IY) ;count the char you just put in + CALL ChkRM + RET NC + LD B,0 ;past margin... +WWLp: INC B ;count moves + PUSH BC + CALL Left + DEC (IY) + POP BC + CALL FetchB + CP CR ;oh no Uncle Bill + JP Z,Error9 + CP '-' ;hyphenation + JR NZ,WW1 + LD A,(HypFlg) + OR A + JR Z,WW1 + CALL Fetch + CP ' ' + JR Z,WW1a + INC B + PUSH BC + CALL InsSpc ;tuck in a space if there isn't one + JR WW2 +WW1: CALL Fetch + CP ' ' + JR NZ,WWLp +WW1a: PUSH BC + CALL Right ;leave it if there is + INC (IY) +WW2: CALL ChkLM + JR Z,WWerr + JR C,WWerr + CALL ICRB ;break line + CALL QuikLf + CALL DoLM + POP BC + LD A,(NumTab) + ADD A,B + JP C,WWerr + DEC A ;one spc gone +GoRtA: OR A ;Go right A chars - used by wordwrap etc + RET Z + PUSH AF + CALL Right + POP AF + DEC A + JR GoRtA +; +WWerr: POP BC + JP Error9 +; +;Reform a paragraph +; +Reform: LD A,(RtMarg) ;is RM set? + DEC A + RET Z + CALL QuikLf + CALL NdCnt + JP C,RfmE10 + CALL Fetch ;empty line? + JP Z,Down + CALL XQuiet + LD A,(AIFlg) + OR A + JR NZ,RfmBg + CALL RfmNL ;figure out indentation + JR C,RfmBg + CALL CntSpc + PUSH AF + CALL RfmPL + POP AF + CALL EatSpc ;remove spaces acc. to NEXT line indent + CALL DoLM ;and add current margin +RfmBg: CALL QuikLf + CALL KyPeek ;peek for a keypress + CP ESC ;check for abort + JR NZ,RfmBg1 ;no... keep going + CALL Keybd ;eat the ESC + JP RfmEnd ;and quit +RfmBg1: CALL ColCnt ;only once per line (slow) + LD IY,CurCol + LD A,63 + LD (PScnt),A +; +RfmLp: CALL NdCnt + JP C,RfmE10 ;check for EOF + CALL Fetch + JP Z,Rfm7 ;and EOL + CP TAB ;tabs are special + JR NZ,RfmTab + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A + JR Rfm3 +RfmTab: LD HL,PSFlg + DEC (HL) + INC (HL) + JR Z,Rfm3 + LD HL,PSTbl-32 + ADD A,L + LD L,A + LD A,0 + ADC A,H + LD H,A + LD A,(PScnt) + ADD A,(HL) + CP 63+30 + JR NC,RfmTb1 + CP 63-30+1 + JR NC,Rfm3 + ADD A,30 + JR Rfm3a +RfmTb1: ADD A,-30 + INC (IY) +Rfm3: INC (IY) ;Keep CurCol updated +Rfm3a: LD (PScnt),A + CALL Right + CALL ChkRM + JR NC,RfmLp +; +Rfm4: CALL FetchB ;just the right length? + CP ' ' + JR NZ,Rfm4a + CALL Fetch + JR Z,Rfm7 +Rfm4a: CALL Left ;oops, too long. + CALL FetchB + CP CR + JP Z,RfmErr + CALL Fetch + CP '-' + JR NZ,Rfm4b + LD A,(HypFlg) + OR A + JR Z,Rfm4b + CALL Right + CALL ColCnt ;## + CALL ChkRM ;## + JR NC,Rfm4a2 ;## + CALL Left ;## + JR Rfm4 ;## +; +Rfm4a2: CALL InsSpc + JR Rfm4c +Rfm4b: CALL IsBlnk ;break after blank + JR NZ,Rfm4 + CALL Right +Rfm4c: CALL ColCnt + CALL ChkLM ;watch out for left mgn + JP Z,RfmErr + JP C,RfmErr + CALL ICRB +Rfm5: CALL Fetch ;avoid spurious para + JR Z,Rfm6a ;(stop after CR) + CP ' ' + JR NZ,Rfm6b + CALL EChar + JR Rfm5 +Rfm6a: CALL EChar + JR RfmBg2 +Rfm6b: CALL DoLM + JR RfmBg2 +; +Rfm7: CALL FetchB ;is the CR soft or hard? + CP ' ' + JR NZ,Rfm9 ;hard, quit + CALL Left ;soft, delete any other spaces +Rfm7a: CALL FetchB + CP ' ' + JR NZ,Rfm7b + CALL Delete + JR Rfm7a +Rfm7b: CP '-' ;unhyphenate? + JR Z,Rfm20 +Rfm8: CALL Right ;and now the CR itself + CALL EChar + CALL RfmSD ;and any soft CR following + LD A,255 + CALL EatSpc ;and any leading spaces + CALL Fetch + JR NZ,Rfm8a ;hit bald CR? + CALL Delete ;yep, kill space and quit + JR Rfm9 +Rfm8a: CALL Left + CALL Left + CALL IsEndS ;(extra spc for punc) + JR NZ,RfmBg2 + CALL Right + CALL InsSpc +RfmBg2: JP RfmBg +Rfm9: CALL Right ;hard CR (check following soft?) + CALL RfmSD ;delete, if there + CALL ICRB0 ;may need to separate paras +RfmEnd: CALL XLoud + JP SetAl +RfmErr: CALL XLoud + JP Error9 +RfmE10: CALL XLoud + JP Eror10 +; +Rfm20: LD A,(HypFlg) ;unhyphenation + OR A + JR Z,Rfm8 ;not allowed, continue +Rfm21: CALL Loud + CALL ShoAll + CALL YesNo1 + PUSH AF + CALL XQuiet + POP AF + JR NC,Rfm22 + JR Z,Rfm21 ;C,Z means "*": unacceptable + JR Rfm8 ;C,NZ means ESC: don't join at all +Rfm22: CALL Z,Delete ;kill hyphen if it was "Yes" + CALL Join ;join lines (whether "Yes or No") + JR RfmBg2 +; +RfmNL: CALL QuikRt ;go to next line of text + CALL NdCnt + JR NC,RfmNL0 + CALL QuikLf ;oops, none + SCF + RET +RfmNL0: CALL Right + CALL Fetch ;(may be blank) + JR NZ,RfmNL1 ;bald CR next? also give up + CALL Up + SCF + RET +RfmNL1: CP ' ' + JR Z,RfmNL2 + CALL QuikLf ;no, fine, we're here + OR A + RET +RfmNL2: CALL Right + CALL Fetch + JR NZ,RfmNL1 ;just spaces and CR? doublespacing, + CALL Right ; go on to next line + JR RfmNL1 +RfmPL: CALL QuikLf ;return to previous line of text +RfmPL0: CALL Left + CALL FetchB ;(may be blank) + CP CR + JP Z,RfmPLx ;yes, take next + CP ' ' + JR Z,RfmPL0 + JP QuikLf ;no, fine +RfmPLx: CALL Left + JP QuikLf +; +RfmSD: CALL Fetch ;delete a soft CR if present + CP ' ' + RET NZ + CALL Right + CALL Fetch + PUSH AF + CALL Left + POP AF + RET NZ + CALL EChar + JP EChar +; +; +;Center or flush a line +; +Center: LD E,1FH ;(RRA) if Center + CP 'F'-40H + JR NZ,Ctr0 + LD E,0C9H ;(RET) if Flush +Ctr0: LD A,E + LD (Flush),A + LD A,(RtMarg) + CP 1 + RET Z ;not if no margin + CALL QuikLf ;start of line +CtrL1: CALL Fetch + JR Z,CtrXit ;end? done + CALL IsBlnk + JR NZ,CtrL1F + CALL EChar ;delete spaces + JP C,Error9 + JR CtrL1 +CtrL1F: CALL QuikRt ;end of line +CtrL2: CALL Left + CALL IsBlnk + JR NZ,CtrL2F + CALL EChar ;delete spaces + JR CtrL2 +CtrL2F: CALL ColCnt ;where are we? + CALL IgnCtl ;ignore ctlchars + LD HL,CurCol + LD A,(LfMarg) + DEC A + LD B,A + LD A,(RtMarg) + ADD A,E ;(ctlchars) + SUB B + SUB (HL) + JP C,Error9 ;error + CALL Flush + JR Z,CtrXit + PUSH AF + CALL QuikLf ;start again + CALL DoLM + POP BC +CtrL3: PUSH BC ;insert spaces to center + CALL InsSpc + POP BC + DJNZ CtrL3 +CtrXit: CALL QuikLf + CALL ShoCu + CALL QuikRt ;to next line(?) + JP Right +; +Flush: RRA ;<--- goes to RET if Flush + AND 7FH ;take half the difference for Center + RET +; +; +;Fetch character at (or before) cursor +; +Fetch: LD HL,(AftCu) + LD A,(HL) + AND 7FH ;ignore any hidden space + CP CR + RET +FetchB: LD HL,(BefCu) + LD A,(HL) + BIT 7,A + RET Z ;ordinary byte + LD A,' ' + RET ;hidden space +; +;Tests on char at cursor (use only A,HL) +; +IsBlnk: LD HL,BlkTbl ;point to tbl + JR IsTest +IsPara: LD HL,ParTbl + JR IsTest +IsParB: LD HL,ParTbl + JR IsTstB +IsPunc: LD HL,PunTbl + JR IsTest +IsPunB: LD HL,PunTbl + JR IsTstB +IsEndS: LD HL,EndTbl +; +IsTest: PUSH HL + CALL Fetch + POP HL + JR IsTLp +IsTstB: PUSH HL + CALL FetchB + POP HL +IsTLp: BIT 7,(HL) + JR NZ,IsTst1 ;at end of tbl? + CP (HL) + RET Z ;Z set if match + INC HL + JR IsTLp +IsTst1: OR A ;clear Z if none + RET ;ret char in A +; +PunTbl: DB ',;:-' ;fall thru... +EndTbl: DB '.?!',0FFh ;end with 0FFh +ParTbl: DB CR ;fall thru... +BadTbl: DB 0,EOF ;characters not "part" of file text +BadLen EQU $-BadTbl ;(<--BlkChr patches in here) +BlkTbl: DB ' ',TAB,0FFh ;end with 0FFh +; +;DISK I/O +; +IOon: LD DE,DspEsc ;show Wait.... + CALL GoTo + CALL MakAlt + LD HL,IOmsg + LD B,4 + CALL BHLMsg + CALL UnAlt + RET +; +BDOSfc: LD DE,FCB +; +;Enter BDOS, but latch onto warm start for +;recovery purposes. (CP/M 2 ONLY) +; +BDOS: CALL DOSVer + JP NC,BDOSep ; just do the BDOS call for CP/M 3.0 + LD A,(DE) ; grab drive # + LD (FcbDrv+1),A ; and stuff it into code + PUSH DE + LD HL,(0001H) + INC HL ;trap warm boot vector in BIOS JP table + LD E,(HL) + INC HL + LD D,(HL) + LD (BIOSws+1),DE + LD DE,BIOSws + LD (HL),D + DEC HL + LD (HL),E + POP DE + CALL BDOSep ;DO IT + PUSH HL + LD DE,(BIOSws+1) ;Restore real warm boot + LD HL,(0001H) + INC HL + LD (HL),E + INC HL + LD (HL),D + POP HL + RET +BIOSws: LD DE,0 ;<--- Warm boot vector + LD HL,(0001H) + INC HL + LD (HL),E ;restore it + INC HL + LD (HL),D +FcbDrv: LD A,0 ;<----- + LD (FCB),A ;restore drive + LD SP,Stack ;restore stack + CALL RDlog ;and disks + CALL Error3 ;Give I/O message + JP Sk1Ed ;Continue editing +; +DOSVer: LD A,0 ;<---- Version + CP 30H ;(Carry set if 2.2, reset if CP/M3, ZxDOS) + RET +; +RstDrv: OR A ;CP/M 2 drive reset (A=1 etc) + JR Z,RDlog + LD HL,FixDsk + RES 6,(HL) ;(have to adjust from ASCII) + CP (HL) ;one of 2 fixed drives? ignore + RET Z + INC HL + RES 6,(HL) + CP (HL) + RET Z + PUSH AF + LD C,GDRV + CALL BDOSep + POP BC + INC A + CP B ;is it logged drive? + JR Z,RDlog + LD HL,1 ;if NOT, can be selective +RDlp: DEC B + JR Z,RDok + ADD HL,HL + JR RDlp +RDok: EX DE,HL + LD C,RSTV ;reset single drive + JR RDxit +RDlog: LD C,RSTD ;sigh, whole system +RDxit: JP BDOSep +; +; +Parse: PUSH AF ;parse FCB w/Duu: and [A/W (NO WILDCARDS) + LD A,(DFMode) + LD (FMode),A + PUSH HL ;Entry: HL=string, A=length + CALL BlkFCB ;Exit: set FCB, FCBU, FMode + POP HL ;...now checks filetypes too + LD D,H + LD E,L + POP AF + OR A + JP Z,PNODRV + LD C,A + LD B,0 ;chars there + LD A,':' + CPIR ;find drivespec? + JR NZ,PNODRV + DEC HL ;yep...NDR? + LD (HL),0 + CALL NdrChk + LD (HL),':' + JR Z,Parse1 ;not an NDR name + INC HL + LD A,B + LD (FCB),A ;store drive + LD A,C + LD (FCBU),A ;store user number + LD E,A + LD C,USRN + PUSH HL + CALL BDOSep ;set user number + POP HL + JR PNAME +Parse1: DEC HL ;yep...User number? + LD A,(HL) + CP '0' + JR C,PDRV + CP '9'+1 + JR NC,PDRV +; +PUSR: SUB '0' + LD E,A ;Got user... figure units + DEC HL + LD A,(HL) + CP '0' + JR C,ZPAR1 ;thats all? + CP '9'+1 + JR NC,ZPAR1 + SUB '0' + LD D,A ;nope, tens too + ADD A,A + ADD A,A + ADD A,A ;*8 + ADD A,D + ADD A,D + ADD A,E ;*(8+2)+units = user + LD E,A + DEC HL + CP 32 + JR NC,ZPBAD ;illegal? +ZPAR1: LD A,E + LD (FCBU),A ;set user + LD C,USRN + PUSH HL + CALL BDOSep + POP HL +; +PDRV: BIT 7,L ;now, parse FCB (start with drive) + JR Z,ZPAR2B ;(Kludge: stay above 0080h) + LD A,(HL) + CP ' ' ;oops, was it there? + JR Z,ZPAR2B +ZPAR2: SUB 'A' + JR C,ZPBAD ;make sure it's legal + LD E,A + LD A,15 + CP E + JR C,ZPBAD + DEC HL + BIT 7,L + JR Z,ZPAR2A ;kludge again (stay about 0080H) + LD A,(HL) + CP ' ' + JR NZ,ZPBAD +ZPAR2A: INC HL + LD A,E + INC A + LD (FCB),A +ZPAR2B: LD BC,4 + LD A,':' + CPIR ;skip over user, to filename + JR PNAME +PNODRV: LD A,' ' ;no du: at all + EX DE,HL + DEC HL ;find filename +PNDL: INC HL + CP (HL) + JR Z,PNDL ;(first nonblank) +; +PNAME: LD B,8 + LD DE,FCB+1 ;do filename at (HL) + EXX + LD DE,FNamBf + LD H,D + LD L,E + LD B,13 + XOR A + CALL Fill + EXX +ZPRL1: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP '.' + JR Z,ZPRL1X + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZRLP1A + CP (HL) + JR NZ,POPT + INC HL +ZRLP1A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL1 + JR ZPRL1F +ZPRL1X: LD A,' ' ;fill with " " + CALL Fill + JR PTYP +ZPBAD: CALL BlkFCB ;bad entry + SCF + RET +ZPRL1F: XOR A + ADD A,(HL) + JR Z,ZPARX + CP '.' + JR NZ,ZPRL2F ;no "."? leave type blank + INC HL +; +PTYP: LD B,3 ;fill type at (HL) + EXX + LD A,'.' + LD (HL),A + INC HL + EXX +ZPRL2: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZPRL2A + CP (HL) + JR NZ,POPT + INC HL +ZPRL2A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL2 +ZPRL2F: LD A,(HL) ;(eat spaces) + CP ' ' + JR NZ,POPT + INC HL + JR ZPRL2F +; +POPT: LD A,(HL) ;process W/A/N option + CP '/' + JR NZ,POPT1 + INC HL + LD A,(HL) ;process W/A/N option +POPT1: OR A + JR Z,ZPARX + CALL VerOpt ;verify legality + JR NZ,ZPBAD + LD (FMode),A + JR ZPARX2 ;any specification overrides defaults +; +ZPARX: LD HL,FCBt1 ;check filetype mode defaults + LD DE,FDflt1 + CALL TypDfl + LD DE,FDflt2 + CALL TypDfl + LD DE,FDflt3 + CALL TypDfl + LD DE,FDflt4 + CALL TypDfl +ZPARX2: LD A,(FCB+1) + CP ' ' + JR Z,ZPBAD + OR A ;DONE. + RET +; +ZPBADC: PUSH HL ;check bad chars + PUSH BC + LD HL,ZPBLST + LD BC,ZPBLEN + CPIR ;Z set if bad + POP BC + POP HL + RET +ZPBLST: DB ' .,;:?*=' ;illegal chars +ZPBLEN EQU $-ZPBLST +; +TypDfl: PUSH HL + LD B,3 ;Set mode from filetype if (HL),(DE) MATCH +TypDLp: LD A,(DE) + CP '?' + JR Z,TypD2 + CP (HL) + JR NZ,TypDex ;no match, quit +TypD2: INC DE + INC HL + DJNZ TypDLp + LD A,(DE) ;match, here's your mode + CALL VerOpt +TypDex: POP HL + RET NZ + LD (FMode),A + RET +; +; +VerOpt: CP 'A' ;verify mode option legal + RET Z + CP 'N' + RET Z + CP 'W' + RET +; +; +;IN: DE=string to match +;OUT: Z=0,B=drive,C=user# (if NDR match found) +; Z=1 if no NDR match +; +NdrChk: PUSH HL + PUSH DE + EX DE,HL ;string addr to HL + LD A,' ' + DEC HL +NdrSpc: INC HL ;skip over spaces + CP (HL) + JR Z,NdrSpc + LD D,H ;addr of 1st non blank to DE + LD E,L + LD B,Z3NdrM+1 ;# chars to allow before + XOR A ;we MUST see a NUL +NdrEos: CP (HL) ;find terminating NUL + JR Z,NdrNul + INC HL + DJNZ NdrEos + JR NoNdr ;more than 8 chars, not an NDR +NdrNul: LD BC,Z3NDR + CALL Z3EAdr + JR Z,NoNdr ;no NDR block + EX DE,HL ;start of string to HL + LD D,B ;NDR addr to DE + LD E,C +NxtNdr: LD A,(DE) ;end of NDRs? + OR A + JR Z,NoNdr ;yep, no match + INC DE + INC DE ;DE points to NDR string + PUSH HL ;save start of string + PUSH DE ;save NDR string addr + LD B,Z3NdrM +NdrNxC: LD A,(DE) + CP ' ' ;end of NDR name string? + JR NZ,NdrChC ;not yet + INC (HL) ;did we hit the NUL + DEC (HL) ;at the end of string + JR NdrMis ;(i.e. was it a full match?) +NdrChC: CP (HL) + JR NZ,NdrMis + INC HL ;next char in string + INC DE ;next char in NDR entry + DJNZ NdrNxC +NdrMis: POP DE ;restore start of NDR string + POP HL ;restore start of string + JR Z,NdrMtc ;all chars match, got an NDR + EX DE,HL ;start of NDR string to HL + LD BC,Z3NdrL + ADD HL,BC ;next NDR entry to HL + EX DE,HL ;and now to DE + JR NxtNdr +NdrMtc: EX DE,HL ;NDR matched + DEC HL + LD C,(HL) ;fetch user number + DEC HL + LD B,(HL) ;fetch drive + OR 0FFh ;Z=0H +NoNdr: POP DE + POP HL + RET +; +;Read in a word from the Z3ENV block. +;IN: offset in BC +;OUT: addr in BC +; Z=1 if addr is invalid +; +Z3EAdr: PUSH HL + LD HL,(Z3Env) + LD A,H + OR L + JR Z,NoZEnv ;no Z3ENV: Z=1 + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + LD A,B + OR C ;Z=1 if no address at offset +NoZEnv: POP HL + RET +; +; +;Read in the file. (HL=prev byte, BC=max size) +;Return with HL=last byte, Z=out of room, C=input error. +; +MSIn: PUSH HL ;Initialize FCBex thru FCBrc and FCBcr + PUSH BC + XOR A + LD DE,FCBex + LD B,4+16+1 + CALL Fill + LD (MSIFlg),A + CPL + LD (SftFlg),A + LD C,FOPN + CALL BDOSfc + INC A ;Not found? + JR NZ,MSIfnd +MSIerr: POP BC ;Error... + POP BC + OR 1 ;Clear Z + SCF ;Set C + RET +MSIfnd: LD DE,DMA + LD C,SDMA + CALL BDOS +; +MSIlp1: LD C,RSEQ + CALL BDOSfc + CP 1 ;No more reocrds? + JP Z,MSIefX + JR NC,MSIerr ;Other error? + LD IX,DMA + POP DE ;target count + LD B,128 ;1 record + POP HL ;target address +MSIlp2: LD A,(FMode) + CP 'W' + JR NZ,MSIlp3 + LD A,(IX) ;Wordstar: handle soft hyphens + CP 1Fh + JR NZ,MSIl2x + LD A,'-' + LD (IX),A +MSIl2x: CP 1Eh ;remove dead soft hyphens + JR Z,MSIlf + CP ' '+080H ;remove soft spaces + JR NZ,MSIl2a + LD A,(SftFlg) + OR A ;(unless at beginning of line) + JR Z,MSIlf + JR MSIlp3 +MSIl2a: XOR A + LD (SftFlg),A + LD A,(IX) ;and keep hard/soft CRs straight + CP CR+80H + JR NZ,MSIl2b + LD A,(HL) ;SCR must have space before... + CP ' ' + JR Z,MSIlp3 + SET 7,(HL) + JR NC,MSIlp3 + RES 7,(HL) ;can't set hi bit on ctlcodes + LD A,' ' + INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z + JR MSIlp3 +MSIl2b: CP CR + JR NZ,MSIlp3 +MSIl2c: RES 7,(HL) ;...and HCR must not have space + LD A,(HL) + CP ' ' + JR NZ,MSIlp3 + DEC HL + INC DE + JR MSIl2c +MSIlp3: LD A,(IX) ;take the byte + AND 7Fh ;Mask parity + CP EOF ;EOF? + JR Z,MSIeof + CP LF ;toss line feeds + JR NZ,MSIl3a + LD (SftFlg),A ;but record them + JR MSIlf +MSIl3a: LD IY,BlkChr + CP (IY) ;toss block chars + JR Z,MSIlf + CP ' ' ;take non-spaces + JR NZ,MSIok + LD A,(HL) + CP 20H ;Last one CTL? take space + JR C,MSIsp + BIT 7,(HL) ;Already hidden space? take space + JR NZ,MSIsp + SET 7,(HL) ;Hide space + JR MSIlf +; +MSIsp: LD A,' ' +MSIok: INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z +MSIlf: INC IX ;Bump input + DEC B ;Go through record + JP NZ,MSIlp2 + PUSH HL + PUSH DE + JP MSIlp1 ;Get next block +; +MSIefX: POP DE ;(for last rec bug fix) + POP HL +MSIeof: OR 1 ;clear Z/C + LD (MSIFlg),A ;Show load OK + RET +; +; +;Write out BC characters at HL to file FCB (C=error) +; +MSOut: PUSH BC + PUSH HL + ADD HL,BC ;ending address + PUSH HL + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD HL,FCB+1 ;strip attributes + LD B,11 +MSOlp0: RES 7,(HL) + INC HL + DJNZ MSOlp0 + LD B,4 + XOR A +MSOlp1: LD (HL),A ; zero out FCBex, FCBs1, FCBs2, FCBrc + INC HL + DJNZ MSOlp1 + LD DE,tStamp ; set the buffer for the + LD C,SDMA ; file timestamp + CALL BDOSep + LD C,GETS ; get the file timestamp + CALL BDOSfc + LD (tsFlg),A ; A=1 if we got a stamp + LD A,(FilFlg) ; make a backup file? + OR A + JR Z,MSOdel ; no backup needed + LD HL,FCB ; copy original filename and extension + LD DE,DMA + LD BC,16 ;FCB length + LDIR ;copy it + LD BC,8+1 ;copy original filename only + LD HL,FCB + LDIR ;again + LD BC,3 ;extension of BAK + LD HL,Bak + LDIR + LD DE,DMA+16 ;delete BAKfil + LD C,FDEL + CALL BDOS + INC A + JR NZ,MSOren + OR H ;no BAK deleted, h/w error? + JP NZ,MSOer2 ;yep... +MSOren: LD DE,DMA ;rename old file to BAK + LD C,FREN + CALL BDOS + JR MSOmak +; +MSOdel: CALL DOSVer + JR C,MSOdl2 ; skip if plain CP/M + CP 'S' + JR Z,MSOdl2 ; skip if ZSDOS + CP 'D' + JR Z,MSOdl2 ; skip if ZDDOS + LD C,ERRM ; ... we get here, we're CP/M 3.0 + LD E,0FFH ; return error, no print + CALL BDOS + XOR A + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK ;make a new file + CALL BDOSfc + PUSH AF + PUSH HL + LD C,ERRM ; return error, print + LD E,0FEH + CALL BDOS + POP HL + POP AF + PUSH AF + OR A + JR Z,MSOnSt + POP AF + LD A,H + CP 8 + JR NZ,MSOmak + LD C,FTRU ; truncate file to 0 bytes + XOR A + LD (FCBr0),A + LD (FCBr1),A + LD (FCBr2),A + CALL BDOSfc + OR A + JP NZ,MSOer2 + LD C,FOPN + CALL BDOSfc ; open the file + PUSH AF + JR MSOnSt ; --- end of CP/M3 specific open code +; +MSOdl2: LD C,FDEL ; +++ CP/M2.2, ZxDOS specific + CALL BDOSfc ; delete any old BAK file + INC A + JR NZ,MSOmak ; jump if all good + OR H ; hardware error code? + JP NZ,MSOer2 ; ...yep +; +MSOmak: XOR A ;Initialize FCB + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK + CALL BDOSfc + PUSH AF + LD A,(tsFlg) ;+++ timestamp code start + DEC A ;do we have a timestamp? + JR NZ,MSOnSt ;no, don't update the timestamp + LD C,SETS ;set create timestamp of new file + CALL BDOSfc ;to the same as existing file +MSOnSt: LD C,SDMA + LD DE,DMA + CALL BDOSep + POP AF ;restore result of FMAK + POP DE ;end + POP HL ;start + POP BC ;(bytes) + INC A + JP Z,MSOerr ;make file failed + LD A,B + OR C ;any bytes? + JP Z,MSOcls + LD C,0 ;Initialize GetNx + LD B,128 ;1 record + LD IX,DMA +MSOlp2: CALL GetNx + EXX + LD HL,BadTbl ;skip illegal chars + LD BC,BadLen + CPIR + EXX + JR Z,MSOsk1 ;0 or EOF +MSOlp3: LD (IX),A ;put it out + LD A,(FMode) + CP 'W' ;Wordstar mode? + JR NZ,MSOWSx + LD A,(IX) + CP ' ' + JR NZ,MSOWSa + LD A,(IX-1) ;add microjustification bits + CP 21h + JR C,MSOWS2 + SET 7,(IX-1) + JR MSOWS2 +MSOWSa: CP CR + JR Z,MSOWS1 + CP LF + JR Z,MSOWSx +MSOWS0: XOR A + LD (SftFlg),A + JR MSOWSx +MSOWS1: LD A,(IX-1) ;soften CRs after spaces + AND 7FH + CP ' ' + JR NZ,MSOWS0 +MSOW1a: SET 7,(IX) + LD A,0FFH + LD (SftFlg),A + JR MSOWSx +MSOWS2: LD A,(SftFlg) ;and spaces after soft CRs + OR A + JR NZ,MSOW1a +MSOWSx: LD A,(IX) + INC IX ;bump pointer + DJNZ MSOsk1 ;Skip if buffer not full + PUSH BC + PUSH DE + PUSH HL + LD C,WSEQ + CALL BDOSfc + POP HL + POP DE + POP BC + OR A + JR Z,MSOook + CALL MSOcls ;output error + JR MSOerr +MSOook: LD B,128 + LD IX,DMA + LD A,(DMA+127) + LD (IX-1),A +MSOsk1: AND 7FH + CP CR ;Add LF after CR + LD A,LF + JR Z,MSOlp3 + LD A,H + XOR D ;At end yet? + JP NZ,MSOlp2 + LD A,L + XOR E + JP NZ,MSOlp2 + OR C ;Still got hidden space? + JP NZ,MSOlp2 + OR B ;need EOF? + JR Z,MSOsk2 +MSOefL: LD (IX),EOF ;yes + INC IX + DJNZ MSOefL +MSOsk2: LD C,WSEQ + CALL BDOSfc + OR A + JR Z,MSOcls + CALL MSOcls + JR MSOerr +MSOcls: LD C,FCLO ;all done, close up + CALL BDOSfc + INC A + OR A ;bug fix 2.67 + RET NZ +MSOerr: SCF + RET +MSOer2: POP HL ;discard start, + POP HL ;end, + POP HL ;(bytes) + LD C,SDMA + LD DE,DMA + CALL BDOSep ;reset DMA buffer + JR MSOerr +; +; +; +; +; DISPLAY FUNCTIONS +; +;(Re)initialize screen to begin editing +; +DoHdr: LD A,(NoHdrF) + OR A + RET NZ + LD DE,0 + CALL GoTo + LD HL,Header + CALL AltDsp + CALL ShoFnm ;Show file name + LD HL,OPoff + LD A,(FMode) + CP 'N' + JR NZ,DoHdr1 ;show "Pg " if document + LD A,(PgLen) + OR A + JR NZ,DoHdrT + LD HL,OPon ;show "OP" if ^OP in nondoc +DoHdr1: LD DE,DspOP + CALL TogSho +DoHdrT: CALL ITshow ;show toggles + CALL VTshow + CALL HYshow + CALL AIshow + CALL DblSho +MRshow: LD A,(RMSav) ;requires header display + DEC A + LD HL,MRon + JP Z,PSDisp + LD DE,DspMrg + JP TogSho +; +TogSho: LD A,(NoHdrF) + OR A + RET NZ + PUSH HL ;toggle show subroutine + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + JP UnAlt +; +; +UpLft: LD DE,0100H ;go to "top of text" + LD A,(RulFlg) + OR A + JR Z,UndrX + INC D + JR UndrX +UndrHd: LD DE,0100H ;go below header regardless +UndrX: JP GoTo +; +; +NoHdr: LD HL,NoHdrF ;toggles on/off + CALL ToggHL + OR A + JR Z,HdrOn +HdrOff: CALL AdjLns ;that's one more line + CALL IncVO + JP SetAl +HdrOn: CALL AdjLns + CALL DecVO + CALL DoHdr ;let's see it again + JP SetAl +; +; +;Show current file data in the heading +; +ShoFnm: CALL MakAlt + LD DE,DspFnm+8 ;blank out old stuff + CALL GoTo + LD B,19 + CALL BBlank + LD DE,DspFnm + CALL GoTo + LD A,(FCB) + ADD A,'A'-1 ;drive letter + CALL PutChA + LD A,(FCBU) ;user number 0-15 + LD C,A + LD B,'3' ;user 30+? + SUB 30 + JR NC,ShoFn1 + LD B,'2' ;user 20+? + LD A,C + SUB 20 + JR NC,ShoFn1 + LD B,'1' ;user 10+? + LD A,C + SUB 10 +ShoFn1: PUSH AF + LD A,B + CALL NC,PutChA + POP AF + JR NC,ShoFn2 + LD A,C +ShoFn2: ADD A,'0' ;show LSD of user number + CALL PutChA + LD BC,Z3NDR + CALL Z3EAdr + JR Z,ShoFnN ;skip if no NDR + LD H,B + LD L,C +ShFnNl: LD B,(HL) ;drive of this NDR entry + INC B + DEC B + JR Z,ShoFnN ;0 means no more entries + LD A,(FCB) + CP B ;drive match? + INC HL + JR NZ,ShFnNx + LD C,(HL) + LD A,(FCBU) + CP C ;user # match? + JR Z,ShFnNn ;yes, display NDR name +ShFnNx: LD DE,Z3NdrL+1 ;skip over NDR + ADD HL,DE + JR ShFnNl ;try next NDR +ShFnNn: LD A,'/' + CALL PutChA + LD B,8 ;show up to first 8 chars of NDR +ShFdLp: INC HL + LD A,(HL) + CP ' ' + CALL NZ,PutChA + DJNZ ShFdLp +ShoFnN: LD A,':' + CALL PutChA ;punctuate + LD HL,FCB+1 + LD B,8 ;Name +ShFnLp: LD A,(HL) + RES 7,A + CP ' ' ;Quit on blank + JR Z,ShFnLF + CALL PutChA + INC HL + DJNZ ShFnLp ;Loop for 8 +ShFnLF: LD A,'.' ;punctuate + CALL PutChA + LD HL,FCBt1 + LD B,3 ;Type +ShFnL2: LD A,(HL) + CALL PutChA + INC HL + DJNZ ShFnL2 + CALL PutSpc + LD A,'/' ;option + CALL PutChA + LD A,(FMode) + CALL PutChA + JP UnAlt +; +; +Ruler: LD HL,RulFlg ;toggle ruler on/off + CALL ToggHL + OR A + JP Z,RulOff +; +RulOn: CALL AdjLns ;readjust screen length + CALL DecVO + CALL Z,SetAl ;maybe on line 1? + JR RuShow +; +RulFix: LD A,(RulFlg) ;update ruler if on + OR A + RET Z +RuShow: LD IY,RulBuf ;build ruler here + LD A,(NSkip) ;starting column + INC A + LD C,A + LD A,(View) ;length + LD B,A +RuLp: LD E,'-' ;default char is "-" + LD A,(VTFlg) ;which tab mode? + OR A + JR Z,RuLpH + PUSH BC ;"T" if varitab stop + LD A,C + LD HL,VTList + LD BC,VTNum + CPIR + POP BC + JR Z,RuVtab + JR RuNtab +RuLpH: LD HL,TabCnt ;"I" if hardtab stop + LD A,C + DEC A + AND (HL) + JR Z,RuHtab +RuNtab: LD A,(RtMarg) ;"R" if right margin + CP C + JR Z,RuRM + JR C,RuDot ;or dot if outside + LD A,(LfMarg) + CP C + JR Z,RuLM ;or "L" if left margin + DEC A + CP C + JR NC,RuDot +RuLpF: LD (IY),E ;okay, show it + INC IY + INC C + DJNZ RuLp + LD (IY),0 + CALL UndrHd + LD HL,RulBuf + JP AltDsp +RuLM: LD E,'L' + JR RuLpF +RuRM: LD E,'R' + JR RuLpF +RuDot: LD E,'.' + JR RuLpF +RuVtab: LD E,'!' + JR RuLpF +RuHtab: LD E,'I' + JR RuLpF +; +RulOff: CALL AdjLns ;adjust screen size + CALL IncVO + LD E,A + CALL CrLft ;oops, may be near top + XOR A + ADD A,E + JP Z,ShoLn1 + JP SetAl +; +; +;Display one byte on the screen for messages rather than text. +;Hi bit set = following space. +; +DsByt: CP CR ;Is it a CR + JR Z,Sk1DB ;Yes, skip + CP X ;compressed space? + JR NC,Sk3DB +DsBy1: LD E,A ;normal character + LD HL,HPos ;room? + DEC (HL) + JP NZ,PutCh ;put it out + INC (HL) ;EOL + RET +Sk1DB: LD A,(HPos) ;Fill out spaces for CR + LD E,A ;(needed for attributes, etc) + CALL SpEOL + LD A,(AuWrap) ;does autowrap occur? + OR A + JR NZ,Sk1aDB + LD E,CR ;NO, put out a CRLF + CALL PutCh + LD E,LF + CALL PutCh +Sk1aDB: LD A,(View) + INC A + LD (HPos),A ;new line + RET +Sk3DB: AND 7FH ;compressed space + CALL DsByt +DsSpc: LD A,' ' + JR DsBy1 +; +; +;Display message pointed to by HL. 00h is end. +;80H,nn = skip count. +; +Dspla: LD A,(View) ;initialize + INC A + LD (HPos),A +DspLp: LD A,(HPos) ;or continue, here + LD E,A + LD A,(HL) ;get byte + INC HL + OR A ;All done? + RET Z + CP X ;hidden spaces? + JR NZ,Dsp10 + LD A,(HL) ;get space count + INC HL + LD B,A +Dsp01: PUSH BC + PUSH HL + CALL DsSpc + POP HL + POP BC + DJNZ Dsp01 + JR DspLp +Dsp10: PUSH HL + CALL DsByt ;Put it out + POP HL + JR DspLp ;Do next one +; +;Display message which immediatly follows the CALL +; +Dspl: POP HL + CALL Dspla + JP (HL) +DsplC: POP HL ;same, but continued + CALL DspLp + JP (HL) +; +; +;Make a text "window" at screen bottom +; +Window: LD A,(PhysLn) ;requires 16 lines or more + CP 16 + JP C,Error7 + LD HL,WinFlg ;toggles on/off + CALL ToggHL + OR A + JR Z,WinOff +; +WinOn: CALL AdjLns ;adjust counts + LD A,(PhysLn) + AND 1 + CALL NZ,ClLast ;clear odd line? + CALL TopV ;put chosen text on top + LD A,0FFh + LD (BelowF),A ;go below + CALL ShoSc ;show text + LD A,(NoHdrF) + OR A + JR NZ,WinOn2 + LD DE,0000h ;separator needed? + CALL GoTo + CALL SepLin + CALL ShoFnm ;with name +WinOn2: XOR A + LD (BelowF),A + JP SetAl +; +WinOff: CALL AdjLns + JP SetAl +; +; +AdjLns: LD A,(PhysLn) ;KEEP screen counts consistent + LD HL,WinFlg + BIT 0,(HL) + JR Z,AdjL1 + SRL A +AdjL1: LD (Lines),A ;physical window size + LD HL,NoHdrF + BIT 0,(HL) + JR NZ,AdjL2 + DEC A ;adjust for header if present +AdjL2: LD HL,RulFlg + ADD A,(HL) ;adjust for ruler if present + LD (TxtLns),A + RET +; +; +; SCREEN I/O ROUTINES +; +;Do screen control code strings (return Carry if none) +; +CtlStr: XOR A + ADD A,(HL) ;HL points to #,bytes (# may be 0) + SCF + RET Z + LD B,A + INC HL ;set up count +BHLMsg: +CtlSLp: LD E,(HL) + INC HL + PUSH BC + PUSH HL + CALL ShutUp ;do NOT filter + POP HL + POP BC + DJNZ CtlSLp + OR A + RET +; +BlkFCB: LD B,11 ;blank out FCB name,typ + LD DE,FCB+1 +BlkFil: LD A,' ' ;blank out B bytes at DE + LD (DE),A + INC DE + DJNZ BlkFil + RET +BBlank: PUSH BC ;blank out B spaces + LD E,' ' + CALL ShutUp + POP BC + DJNZ BBlank + RET +; +;Show messages and prompts +; +MsgDsp: PUSH HL ;must start at "top" + CALL UpLft + POP HL +AltDsp: PUSH HL ;display message in alt video + CALL MakAlt + POP HL + CALL Dspla + JR UnAlt +; +Prompt: PUSH HL ;Prompt: blank first line + CALL UpLft ;(with attribute) + CALL MakAlt + LD A,(View) + INC A + LD E,A + CALL SpEOL + CALL UnAlt + POP HL + JR MsgDsp ;then show prompt message +; +;Handle alternate video +; +MakAlt: LD A,(AltHdr) ;optional for messages and prompts + OR A + RET Z +AltY: LD HL,AltOn ;mandatory for ctl-chars + LD A,(AltBit) ;ram always uses hi bit + OR A + JP Z,CtlStr + LD A,X + LD (AltMsk),A + RET +UnAlt: LD A,(AltHdr) + OR A + RET Z +UnAltY: LD HL,AltOff + LD A,(AltBit) + OR A + JP Z,CtlStr + XOR A + LD (AltMsk),A + RET +; +;Character output +; +XPutCh: LD A,(Horiz) ;show character in E + LD HL,View ;UNLESS in lower rt corner + CP (HL) + JR NZ,PutCh + LD A,(Vert) + LD HL,TxtLns + CP (HL) + RET Z +PutCh: PUSH HL ;show char in E + PUSH DE + PUSH BC + LD A,(Filter) ;filtered + CP E + JR C,PutChQ ;'?' if char >= Filter (07FH) +PutCh1: LD A,(AltMsk) + OR E + CALL CONOut + POP BC + POP DE + POP HL + RET +PutChQ: LD E,'?' + JR PutCh1 +; +PutSpc: LD A,' ' +Echo: CP 20H ;echo typed char, IF nice + RET C ; (used for one-char input) +PutChA: PUSH DE ;show char in A + PUSH AF ; save it too (for Echo) + LD E,A + CALL PutCh + POP AF + POP DE + RET +; +CONOut: LD E,A +ShutUp: NOP ;<--- goes to RET for Quiet + LD C,UCON ;put byte to console (mostly ctls) + JP BDOSep +; +PosCur: LD A,(Horiz) + LD E,A + DEC E + LD A,(RulFlg) + AND 1 + LD HL,Vert + ADD A,(HL) + LD D,A +; +;Position cursor to row D column E +; +GoTo: LD A,(NoHdrF) ;lie for lack of header + AND D ;(decrement row if >0) + JR Z,GoTo01 + DEC D +GoTo01: LD A,(BelowF) ;implement window below + OR A + JR Z,GoToIt + LD A,(Lines) + ADD A,D + LD D,A +GoToIt: LD A,D + LD (CurRow),A + LD A,(PosMod) + CP 'N' + JR NZ,GoYPos + LD HL,PCu ;use Down,Right method (gaak) + CALL Go2Byt ;home first + LD A,D + OR A + JR Z,Go2RwF +Go2Row: PUSH DE ;move down to desired row + LD E,LF + CALL ShutUp + POP DE + DEC D + JR NZ,Go2Row +Go2RwF: LD A,E + OR A + RET Z +Go2Col: LD HL,PCu+2 + CALL Go2Byt ;now across to desired col + DEC E + JR NZ,Go2Col + RET +GoYPos: CP 'A' ;Okay, can be more sophisticated... + JR Z,GoANSI + LD HL,PCu ;use ESC = sequence + CALL Go2Byt ;leadin byte(s) + LD HL,PCu+2 + PUSH DE ;now coordinates + PUSH HL + LD A,(PosMod) ;which order? + CP 'R' + JR Z,GoToX ;(backwards) + LD A,D + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,E + ADD A,(HL) + CALL CONOut + JR GoToDl +GoToX: LD A,E + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,D + ADD A,(HL) + CALL CONOut +GoToDl: LD A,(PosDly) ;optional delay for some terminals + OR A + RET Z + LD B,A + LD C,0 + JP BDlyLp +GoANSI: LD HL,ANSIms+3 ;use ANSI sequence + LD A,D + INC A ;origin 1,1 + CALL GoASub + LD HL,ANSIms+6 + LD A,E + INC A + CALL GoASub + LD HL,ANSIms + CALL CtlStr + JR GoToDl +GoASub: LD (HL),'0' ;tens digit +GASl1: CP 10 + JR C,GAS2 + INC (HL) + SUB 10 + JR GASl1 +GAS2: INC HL + ADD A,'0' ;units + LD (HL),A + RET +Go2Byt: CALL Go1Byt ;show one or two bytes at HL + LD A,(HL) + OR A + RET Z +Go1Byt: PUSH DE + LD B,1 ;just do one byte + CALL CtlSLp + POP DE + RET +ANSIms: DB 8,ESC,'[00;00H' ;for use with CtlStr +; +; +IfSpLn: LD A,(AltHdr) ;draw sep line IF headers not alt + OR A + RET NZ +SepLin: CALL MakAlt ;draw separator line + LD A,(View) + LD D,A + LD E,'-' +SLDlp: PUSH DE + CALL PutCh + POP DE + DEC D + JR NZ,SLDlp + JP UnAlt +; +; +;SHOW SCREEN ROUTINES +; +; | +------------------------ +; |HELLO! | ^ +; |This is your |text file, which is seen Vert +; |on the screen| just like this._ v +; | | \ +; |<---NSkip---> <-----Horiz-----> \ +; |<-----------CurCol------------> \Cursor at (H,V) +; +;Recheck current position on screen +; +Orient: LD A,(Vert) ;Adjust Horiz and Vert + LD E,A + CALL CrLft ;Start of first screen line + JR NC,Ornt1 + CALL TopV ;At top, set Vert to 1 + JR Ornt2 +Ornt1: LD A,(Vert) ;Decrement Vert if needed + SUB E ; to avoid whitespace at top + LD (Vert),A +Ornt2: CALL ColCnt ;Update columen (in A,B,CurCol) + INC A + JR NZ,Ornt3 + LD B,0FEH +Ornt3: LD A,(Horiz) ;Compute cursor offset in line + LD C,A + LD A,B + SUB C ;CurCol-Horiz is minimum offset + JR NC,Ornt4a + XOR A ;set 0 if negative +Ornt4a: LD E,A + LD A,(NSkip) ;present offset < min? + CP E + JR C,Ornt4b ;if so, change + CP B ;bigger than CurCol-1? + JR C,Ornt4c ;if not, OK + LD A,B ;round down to small enough + DEC A + AND 0C0H ;multiple of 32 + JR Ornt4c +Ornt4b: LD A,E ;round up to big enough + OR 1FH + JR Z,Ornt4c + INC A +Ornt4c: LD (NSkip),A ;set (new?) offset + SUB B + NEG + LD (Horiz),A + LD HL,(CurLin) ;Figure line, page + LD (CurPgL),HL + LD A,(FMode) + CP 'N' + LD A,(PgLen) + JR NZ,Ornt5 + XOR A ;don't SHOW pagination for nondocs +Ornt5: LD E,A + LD D,0 + DEC HL + LD B,D + LD C,D + OR A ;not paginating? + JR Z,OrnLpF + INC BC +OrntLp: SBC HL,DE + JR C,OrnLpF + INC BC + JR OrntLp +OrnLpF: ADD HL,DE + INC HL + LD (CurPgL),HL + LD (CurPg),BC + RET +; +;Show (just) as much of the text as necessary +; +ShoTx: CALL KyStat ;check keybd + JR NZ,ShoTx1 + CALL TestSc ;check postponed screen disp + JP NZ,ShoAll ;do it! + CALL ShoPos ;quiet? update header + CALL TestCu ;check postponed line disp + JR NZ,DoPost ;do it (or more, if requested) +ShoTx1: LD A,(ShoFlg) ;busy... + OR A ;nothing (0) + RET Z + DEC A + JP Z,ShoRCu ;just one line (1,2) - can be postponed + DEC A + JP Z,ShoCu + DEC A + JP Z,ShoDn ;bottom part (3) + JP ShoSc ;or whole screen +DoPost: LD A,(ShoFlg) + CP 3 + JP C,ShoCu ;at LEAST this + JP Z,ShoDn + JP ShoSc +; +;Show position in file, no matter what +; +ShoPos: LD A,(NoHdrF) + OR A + RET NZ + CALL Force ;must see this + LD DE,DspPg ;Update header + CALL GoTo + CALL MakAlt ;C128 bug fix requires GoTo first + LD HL,(CurPg) + LD A,(FMode) + CP 'N' + CALL NZ,ShPSb1 + LD DE,DspLin + LD HL,(CurPgL) + CALL ShPoSb + LD DE,DspCol + LD A,(CurCol) + LD L,A + LD H,0 + CALL ShPoSb + CALL UnAlt + JP UForce +ShPoSb: PUSH HL ;show a number + CALL GoTo + POP HL +ShPSb1: LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + JP BHLMsg +; +;Show current line only (fast) +; +ShoCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu +ShoCu1: LD A,(Vert) + LD B,A + JP ShoLn +; +ShoRCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu + CALL FetchB + CP TAB ;can't do this with tab at left + JP Z,ShoCu + LD A,(Vert) ;special routine: only RIGHT of cursor + LD D,A ;...modeled on ShoLCu + LD A,(RulFlg) + AND 1 + ADD A,D + LD D,A ;current row + LD A,(Horiz) + DEC A + LD E,A + JP Z,ShoCu ;can't do this at left of screen + DEC E + CALL GoTo ;position to start + LD E,1 ;find start of line + CALL CrLft + PUSH HL + LD HL,Horiz + LD A,(NSkip) + ADD A,(HL) + DEC A + LD D,A + DEC A + LD B,A ;skip till just before cursor + LD A,(View) + INC A + SUB (HL) + LD E,A + INC E + POP HL + CALL ShoLSb ;do part (char!) left of cursor + INC E ;(DON'T ask me why this INC is needed) + LD D,E + DEC D + LD A,(Vert) + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShRCu3 + DEC D +ShRCu3: LD HL,(AftCu) + JP ShoLSb +; +;Display from Cursor line-1 down +; +ShoDn: CALL ConChk ;(postpone if busy!) + JP NZ,HoldSc + LD HL,CsrOff + CALL CtlStr + LD A,(DSFlg) ;(or line-2 if DS) + LD HL,Vert + ADD A,(HL) + JR Z,ShoSc0 + LD B,A + DJNZ ShScLp + JR ShoSc0 +; +;Show everything on emerging from macros etc +; +ShoAll: CALL Orient + CALL DoHdr + CALL ShoPos + JR ShoScX +; +;Display whole text screen (sigh) +; +ShoSc: CALL ConChk ;(Postpone if busy!) + JP NZ,HoldSc +ShoScX: LD HL,CsrOff + CALL CtlStr +ShoSc0: CALL RulFix + CALL SetNo ;kill any pending redisps + XOR A + LD (CuFlg),A + CPL + LD (HorFlg),A + LD B,1 ;Simple method if not memory mapped +ShScLp: PUSH BC + CALL ShoLn + POP BC + INC B + LD A,(TxtLns) + INC A + SUB B + JR NZ,ShScLp + LD HL,CurOn + CALL CtlStr + RET +; +IOoff1: LD DE,DspEsc ;header: blank prompt + CALL GoTo + CALL MakAlt + LD B,4+1 ;(cursor) + CALL BBlank + JP UnAlt +; +IOoff: LD A,(NoHdrF) ;headerless? redo top line + OR A + JR Z,IOoff1 + LD A,(RulFlg) + OR A + JP NZ,RuShow +; +;Show line 1 (to wipe out msgs) +; +ShoLn1: LD B,1 ;fall thru... +; +;Show line number B (=1...TxtLns) +; +ShoLn: LD A,(ShutUp) + OR A + RET NZ + PUSH BC + CALL KyStat ;(helps buffering for slow keyboards) + POP BC + LD A,(RulFlg) + AND 1 + ADD A,B + LD D,A ;position cursor on screen + LD E,0 + PUSH BC + CALL GoTo + POP BC + LD A,(Vert) ;is line before or after cursor? + SUB B + JR Z,ShoLCu ;ouch, it's cursor line + JR C,ShoLAf +ShoLBf: LD E,A ;okay, before + INC E + CALL CrLft + LD A,(View) + INC A + LD E,A + LD A,(NSkip) + LD B,A + LD D,255 + JR ShoLSb +ShoLAf: NEG ;okay, after + PUSH BC ;save line# + LD E,A + CALL CrRit + POP BC + PUSH AF + LD A,(View) + LD D,A + INC A + LD E,A + LD A,(TxtLns) + CP B ;last line? avoid last column + JR NZ,ShLAf0 + DEC D +ShLAf0: POP AF + JR C,ShLAf1 + JR Z,ShLAf2 +ShLAf1: JP ClEOL ;no line! +ShLAf2: LD A,(NSkip) + LD B,A + ADD A,D + LD D,A + JR ShoLSb +ShoLCu: LD E,1 ;hmm, right on cursor + PUSH BC ;save line# + CALL CrLft + LD A,(NSkip) + LD B,A + LD A,(CurCol) ;do part to left + DEC A + LD D,A + LD A,(View) + INC A + LD E,A + CALL ShoLSb + LD D,E + DEC D + POP AF ;line# + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShLCu1 + DEC D +ShLCu1: LD HL,(AftCu) +; +ShoLSb: LD A,D ;Show up to column D of text starting at HL + OR A ;E=room+1, B=Cols to skip (if any) + RET Z + XOR A + EXX + LD B,A ;B',C' keep track of previous chars + LD C,A + LD E,A ;E' is count skipped + EXX + LD C,A ;initialize GetNx + ADD A,B + JR Z,ShLSL2 +ShLSL1: CALL GetNx ;eat skipped columns + JP Z,ClEOL ;end of line? + CP TAB + JR Z,ShLS1T + EXX + INC E ;E' + EXX + DEC D + DJNZ ShLSL1 + CALL ShSvCh + INC D + DEC D + RET Z + JR ShLSL2 +ShLS1T: EXX ;count for tabs + LD A,E + LD HL,TabCnt + AND (HL) + XOR (HL) ;extra spaces + INC A ;plus usual one + PUSH AF + ADD A,E + LD E,A + POP AF + EXX + PUSH AF + SUB D + NEG + LD D,A + POP AF + SUB B + NEG + LD B,A + JR NZ,ShLSL1 + LD A,TAB + CALL ShSvCh + INC D + DEC D + RET Z +ShLSL2: CALL GetNx ;show the rest + EXX + LD C,B + LD B,A + EXX + JR Z,ShLSCr ;take care of CR,TAB + CP ' ' + JR C,ShCtl + PUSH DE + LD E,A + CALL PutCh + POP DE +ShLSL3: DEC E + DEC D + RET Z + LD A,E + DEC A + RET Z + JR ShLSL2 +ShCtl: PUSH HL + PUSH BC + PUSH DE + CP TAB + JR Z,ShLSTb + ADD A,40H ;other ctls are hili letters + EX AF,AF' + CALL AltY ;(mandatory) + EX AF,AF' + CALL PutChA + CALL UnAltY + JR ShLRet +ShLSCr: PUSH HL + PUSH BC + PUSH DE + EXX + LD A,C ;last char + EXX + CP ' ' + JR Z,ShLCrF ;SCR doesn't show + LD A,(HCRFlg) + OR A + JR Z,ShLCrF ;HCRs also MAY not... + LD E,'<' + CALL PutCh + POP DE + DEC D + DEC E + PUSH DE + LD A,E ;don't ClEOL if now in last col + CP 2 +ShLCrF: CALL NC,ClEOL + POP DE ;end of line + POP BC + POP HL + RET +ShLSTb: LD A,(View) ;hit a tab... + INC A + SUB E ;column + LD HL,TabCnt + AND (HL) + XOR (HL) ;figure extra spaces + LD B,A + JR Z,ShLTLF +ShLTbL: CALL PutSpc ;do them + POP DE + DEC E + DEC D + PUSH DE + JR Z,ShLRet + DJNZ ShLTbL ;then one last +ShLTLF: CALL PutSpc +ShLRet: POP DE + POP BC + POP HL + JR ShLSL3 +ShSvCh: EXX ;keep track of prev chars + LD C,B + LD B,A + EXX + RET +; +; +ClEOL: LD HL,CIL ;clear to EOL (quickly if possible) + CALL CtlStr + RET NC +SpEOL: DEC E ;this always SPACES (for attributes) + RET Z +ClELp: LD A,(CurRow) + INC A + LD HL,PhysLn + CP (HL) + JR NZ,ClEL3 + DEC E ;avoid last char on last line + RET Z +ClEL3: CALL PutSpc + DEC E + JR NZ,ClEL3 + RET +; +ClLast: LD A,(PhysLn) ;clear last line on screen + DEC A + LD D,A + LD E,0 + CALL GoToIt + LD A,(View) + LD E,A ;do NOT INC this, it's last line + JR ClEOL +; +; +;Set level of display required +; +SetAl: LD A,0FFH ;routines to set it + JR Set1 ;(must preserve ALL REGS and FLAGS) +SetDn: LD A,3 + JR Set1 +SetCu: LD A,2 + JR Set1 +SetRCu: LD A,1 + JR Set1 +SetNo: XOR A ;this one WILL shut it up... + JR Set2 +Set1: PUSH AF ;...otherwise, do not DEcrease previous requests + EX (SP),HL + LD A,(ShoFlg) + CP H + EX (SP),HL + JR NC,Set3 + POP AF +Set2: LD (ShoFlg),A + RET +Set3: POP AF + RET +; +SmlDly: LD A,(Timer) + LD B,A + LD C,1 + JP BDlyLp +; +ScrUDx: LD A,0C9H ;(RET) + LD (UpLft),A + CALL ScrlUD + CALL NC,SmlDly ; delay if scrolled + LD A,11H ;(LD DE,nnnn) + LD (UpLft),A + RET +; +ScrlU2: LD HL,DelL + CALL ScrlUD + JR C,SetAl ; no scroll + JR SetCu +; +ScrlU: LD HL,DelL + JR ScrlX +; +EdgeU: LD A,(Vert) + DEC A ;first line: scroll + RET NZ +ScrlD: LD HL,InsL +ScrlX: CALL ScrlUD + JR C,SetAl ; no scroll + CALL SmlDly + JR SetCu +ScrlUD: PUSH HL ;[common sbr, used in one-liners too] + CALL TestCu + CALL NZ,ShoCu1 + LD A,(NoHdrF) ;canNOT do this if header is suppressed + LD HL,OddDel ; and ins/del specific to ln 1. + AND (HL) + LD HL,WinFlg ; or if Windowing (in any event) + OR (HL) + POP HL + JR NZ,NoScrl + PUSH HL + CALL UpLft + POP HL + CALL CtlStr ;do it + RET C ;(maybe couldn't) + LD A,(OddDel) + OR A + CALL NZ,RulFix + RET +NoScrl: SCF ; didn't scroll + RET +; +; Set flag for redisplay due to arrow keys +; +EdgeL: LD A,(Vert) + DEC A + RET NZ + LD A,(CurCol) + DEC A + RET NZ + JR ScrlD ;scroll if at top left +EdgeR: CALL Fetch + JR Z,ER01 + LD A,(Horiz) ;not CR: if off right edge, scroll + LD HL,View + CP (HL) + JR Z,HorScl + RET +ER01: LD A,(Vert) ;CR: if at bot right, scroll + LD HL,TxtLns + CP (HL) + JP Z,ScrlU +EdgeD: LD A,(Vert) + LD HL,TxtLns + CP (HL) + JP Z,ScrlU ;last line: scroll + RET +; +;Watch for horizontal scroll +; +IfScl: LD A,(NSkip) ;request scroll if already scrolled + OR A + RET Z +HorScl: CALL SetCu ;request scroll + XOR A + LD (HorFlg),A + RET +; +;Postpone display for speed +; +HoldCu: LD A,0FFH ;save if busy + LD (CuFlg),A + RET +HoldSc: LD A,0FFH + LD (ScFlg),A + RET +TestSc: LD HL,ScFlg ;test & reset postponement + JR TestX +TestCu: LD HL,CuFlg +TestX: XOR A ;(ret with Z if none) + ADD A,(HL) + LD (HL),0 + RET +; +; Position cursor for input +; +Cursr: CALL PosCur ;turn on cursor + CALL Fetch + RET NZ + LD A,(HCRFlg) ;oops, on a CR + OR A ;HCRs showing? + RET Z + CALL FetchB ;got to fix HCR flag + LD E,' ' ;kludge to " " or "<" + CP E + JR Z,Csr01 + CALL NdCnt + JR C,Csr01 + LD E,'<' +Csr01: CALL XPutCh + LD E,BS + JP PutCh +; +; +; MESSAGES +; +ErrTab: DW 0,MSG1,MSG2,MSG3,MSG4,MSG4,MSG7,MSG7,MSG8,MSG9 +; +MSG1: DB 'Ou','t'+X,'o','f'+X,'Memory',0 +MSG2: DB 'Invali','d'+X,'Key',0 +MSG3: DB 'I/','O'+X ;(fall through to 7) +MSG7: DB 'Error',0 +MSG4: DB 'No','t'+X,'Found',0 +MSG8: DB 'Synta','x'+X,'Error',0 ;(note 5,6 not used) +MSG9: DB 'Canno','t'+X,'Reformat',0 ;(note error 10 has no MSG) +; +NameQ: DB 'Name',':'+X,0 +ReadQ: DB 'Read',':'+X,0 +WritQ: DB 'Write',':'+X,0 +EraQ: DB 'Erase',':'+X,0 +LoadQ: DB 'Load',':'+X,0 +FindQ: DB 'Find',':'+X,0 +ChgQ: DB 'Chang','e'+X,'to',':'+X,0 +DirQ: DB 'Dir',':'+X,0 +PrtQ: DB 'Options',':'+X,0 +PgLnQ: DB 'Length',':'+X,0 +ColQ: DB 'Column',':'+X,0 +PageQ: DB 'Page',':'+X,0 +LineQ: DB 'Line',':'+X,0 +MacroQ: DB 'Macro',':'+X,0 +RptcQ: DB 'Repea','t'+X,'coun','t'+X,'([Q],0-9/*)',':'+X,0 +KeyQ: DB 'Ke','y'+X,'numbe','r'+X,'([N/Q],0-9)',':'+X,0 +QuitQ: DB 'Abando','n'+X,'changes','?'+X,'(Y/N)',':'+X,0 +UnchgQ: DB 'Unchanged',';'+X,'save','?'+X,'(Y/N)',':'+X,0 +; +; Changed: Q File size: NNNNN Memory used: NNNNN Free: NNNNN +InfMsg: DB CR + DB ' '+X,'Changed',':'+X +ModQQQ: DB 'Q',X,7,'Fil','e'+X,'size',':'+X +SizNNN: DB 'NNNNN',X,5,'Memor','y'+X,'used',':'+X +UsdNNN: DB 'NNNNN',X,5,'Free',':'+X +FreNNN: DB 'NNNNN',CR,0 +; +; [Menus disabled; see VDE.DOC or .QRF] +; [See VDE.DOC and .QRF for help] +; +HlpMsg: DB X,26,'[Menu','s'+X,'disabled',';'+X,'se','e'+X + DB 'Manual]',CR,0 +; +;A4/DOC:FILENAME.TYP /A Pg 1 Ln 1 Cl 51 INS vt by AO DS scr top ^QY del to EOL ^QF Find +; ^QP to Place mk ^Q scr bot ^QDel " to BOL ^QA replAce +; ^QR goto TOF ^Q ln start ^QT del to char ^QP to last cursor +; ^QC goto EOF ^Q ln end ^QU UNdel line ^QI goto pg/ln +; ^QQ goto ZCPR queue line +; +QMenu: DB X,4,'^Q','B'+X,'got','o'+X,'Block',X,4,'^Q'+X,'sc','r'+X,'top' + DB X,5,'^Q','Y'+X,'de','l'+X,'t','o'+X,'EOL',X,4,'^Q','F'+X,'Find',CR + DB X,4,'^Q','Z'+X,'t','o'+X,'plac','e'+X,'mk',X,3,'^Q'+X,'sc' + DB 'r'+X,'bot',X,5,'^QDe','l'+X,'"'+X,'t','o'+X,'BOL',X,4,'^Q','A'+X + DB 'replAce',CR + DB X,4,'^Q','R'+X,'got','o'+X,'TOF',X,6,'^Q'+X,'l','n'+X,'start' + DB X,4,'^Q','T'+X,'de','l'+X,'t','o'+X,'char',X,3,'^Q','P'+X,'t','o'+X + DB 'las','t'+X,'cursor',CR + DB X,4,'^Q','C'+X,'got','o'+X,'EOF',X,6,'^Q'+X,'l','n'+X,'end' + DB X,6,'^Q','U'+X,'UNde','l'+X,'line',X,4,'^Q','I'+X,'got','o'+X + DB 'Pg/Ln',CR + DB X,'(^Q','Q'+X,'got','o'+X,'ZCP','R'+X,'queu','e'+X,'line',CR,0 +; +;^OL,R marg set ^OI tab set ^OP Page length ^O make top ln ^OA Auto-in +; ^OX marg rel ^ON tab clr ^OS dbl Spacing ^OW Window ^OQ Quiet +; ^OC Center ^OV Vari tabs ^OH Hyphenation ^OJ proportional +; ^OF Flush rt ^OT ruler ^OD Display CRs ^OZ Zap screen +; +OMenu: DB '^OL,','R'+X,'mar','g'+X,'set',X,2,'^O','I'+X,'ta','b'+X,'set' + DB X,4,'^O','P'+X,'Pag','e'+X,'length',X,2 + DB '^O'+X,'mak','e'+X,'to','p'+X,'ln',X,2,'^O','A'+X,'Auto-in',CR + DB X,2,'^O','X'+X,'mar','g'+X,'rel',X,2,'^O','N'+X,'ta','b'+X,'clr' + DB X,4,'^O','S'+X,'db','l'+X,'Spacing',X,4,'^O','W'+X,'Window',X,7 + DB '^O','Q'+X,'Quiet',CR + DB X,2,'^O','C'+X,'Center',X,4,'^O','V'+X,'Var','i'+X,'tabs' + DB X,2,'^O','H'+X,'Hyphenation',X,4,'^O','J'+X,'proportional',CR + DB X,2,'^O','F'+X,'Flus','h'+X,'rt',X,2,'^O','T'+X,'ruler' + DB X,6,'^O','D'+X,'Displa','y'+X,'CRs' + DB X,4,'^O','Z'+X,'Za','p'+X,'screen',CR,' ',CR,0 +; + DS 4 +MnuEnd: ;menus end here, text can begin + END + \ No newline at end of file diff --git a/Source/Apps/ZDE/zde18.z80 b/Source/Apps/ZDE/zde18.z80 new file mode 100644 index 00000000..7e769db6 --- /dev/null +++ b/Source/Apps/ZDE/zde18.z80 @@ -0,0 +1,8567 @@ + ;Assembles with Al Hawley's ZMAC and loads with MLOAD + ; ZMAC ZDE18 /H + ; MLOAD ZDE18.COM=ZDE18.HEX + ;Assembles with SLR's Z80ASM directly to COM file + ; Z80ASM zde18 + ;Assembles with ZASM (Cromemco ASMB) & loads with MLOAD +; .Z80 ;Uncomment these two lines and rename +; ASEG ;to ZDE18.MAC for M80 + ;(use RELHEX to convert ZDE18.REL to ZDE18.HEX) + ;then generate ZDE18.COM with MLOAD. +; +;*** ZDE assembly sequence +; +CR EQU 0DH ;ASCII stuff +LF EQU 0AH +FF EQU 0CH +BS EQU 08H +TAB EQU 09H +ESC EQU 1BH +DEL EQU 7FH +BEL EQU 07H +EOF EQU 1AH +X EQU 80H ;hibit +; +BDOSep EQU 0005h ;BDOS stuff +FCB EQU 005Ch +FCBt1 EQU FCB+9 +FCBex EQU FCB+12 +FCBs1 EQU FCB+13 +FCBd0 EQU FCB+16 +FCBcr EQU FCB+32 +FCBr0 EQU FCB+33 +FCBr1 EQU FCB+34 +FCBr2 EQU FCB+35 +DMA EQU 0080h +; +LSTO EQU 5 +UCON EQU 6 +CPMV EQU 12 ;return version number +RSTD EQU 13 ;reset drives +SELD EQU 14 ;select drive +FOPN EQU 15 ;open file +FCLO EQU 16 ;close file +SRCH EQU 17 ;search for first +SRCN EQU 18 ;search for next +FDEL EQU 19 ;delete file +RSEQ EQU 20 ;read next record +WSEQ EQU 21 ;write next record +FMAK EQU 22 ;create file +FREN EQU 23 ;rename file +GDRV EQU 25 ;get current drive +SDMA EQU 26 ;set dma address +USRN EQU 32 ;get/set user number +RSTV EQU 37 ;selectively reset drives +ERRM EQU 45 ;set error mode +DOSV EQU 48 ;return extended version +GOBIOS EQU 50 ;CP/M3 BIOS call +FTRU EQU 99 ;set time(ZSDOS)?or truncate file (CP/M#)? +GETF EQU 100 ;get flags +SETF EQU 101 ;set flags +GETS EQU 102 ;get stamp +SETS EQU 103 ;set stamp +; +Z3NdrL EQU 16 ; length of NDR dir/pwdstring +Z3NdrM EQU 8 ; length of NDR name to match +Z3NDR EQU 0015H ; offset to NDR address in Z3ENV +Z3MSG EQU 0022H +MsgUsr EQU 64 ; User area offset in message buffer +MsgNmU EQU 16 ; # of user registers +TPAful EQU 12 ; Z33 TPA full error code +ErrBit EQU 00000010B +EcpBit EQU 00000100B +ExtBit EQU 00001000B +; +;ErrSta is the value to be returned in the Z33 Message Buffer command +;status to inform the command processor that an error has occurred in +;an external program and that the error handler should be invoked. +; +ErrSta EQU ErrBit+EcpBit+ExtBit +; +;*** ZDE.ASM - Z-System Display Editor +;*** Universal Version - (c)1988 Eric Meyer +;*** Z-System Version - (c)1989 Carson Wilson +; ------------------- +; VDE,VDE-2 - 9-12/84 - Enhanced VDO, added functions +; VDE-OS,OX - 7/85-1/86 - Small additions and fixes +; VDE-PX - 7-9/85 - Epson Geneva terminal version +; VDE 1.2-3 - 9/85-1/86 - Generic terminal version +; VDE/M 2.0 - 4/86 - Generic memory map version; CP/M+ support; additions +; 2.1 - 6/86 - New Keys 0-9; window; undo; directory; new pagination, +; compression, block marker, scroll; etc. +; 2.2 - 8/86 - WS-like commands; left mrgn, hyphenation; macros +; 2.3 - 9/86 - VINSTALL; Print options; word fns; real ^QA; RstDrv +; 2.4 - 1/87 - vidRAM/window redone; "W" mode; ^OZ,^QP; block print +; 2.5 - 3/87 - User#s; "N" mode; ^OS, ^OV/+/-; new block fns; hard-CRs +; 2.6 - 7/87 - Allow blank filename; ^U abort; new toggles; ruler; +; ^O; AltBit fixes; works w/o curpos; key buffer; faster +; scrolling; case insensitive searches; no fake "VIDRAM" +; 2.61 - 8/87 - Bug fixes (incl FastFi), improved hyphenation +; 2.62 - 11/87 - ^JKL synonyms; ^W prefix; ^OH; several small fixes +; 2.63 - 1/88 - ^KV; WS style ^W/^Z; chgs to ^OP, ^OI/N, word fns +; 2.64 - 3/88 - ^OQ,^QT,^QI; ^KD; ^QA fixes; dbl spc; top margin; +; backward find; ShoRCu +; 2.65 - 4/88 - ^OI/N args; Esc-TAB; ^OA; menu removal; minor fixes +; 2.66 - 6/24/88 - Printer margins; Minor fixes. LAST RELEASE! +; 2.67b - 10/14/88 - Minor fixes +; ZDE 1.0 - 3/10/89 - Z-System Display Editor +; 1.3 - 8/26/89 +; 1.6 - 6/2/90 +; 1.6 - 11/19/20 - ZDE 1.6 source reconstituted using VDE 2.67 +; source as a guide - MECPARTS +; 1.7 - 11/21/20 - Incorporated Al Hawley's timestamp fixes - MECPARTS +; 1.8 - 12/03/22 - Added ability to retain file create datestamp +; on CP/M+ systems. - Lars Nelson +; ------------------- +; + ORG 0100H +; + JP Start ;Entry and exit vectors + DB 'Z3ENV' + DB 1 +Z3Env: DW 0 +Boot: JP 0 + DW 0 +; +;Following VINSTALL data MUST be at 0110-0121 +; + DW 1006H ;Version compatibility + DW UsrPat + DB UPatL + DW PSTbl + DB PsL + DW MnuSt + DW KMnuSt + DW EMnuSt + DW OMnuSt + DW QMnuSt + ;version message (28 chars, used in menu) +; [----5----10---15---20---25--] +VersID: DB 'ZDE 1.8, Copr. 1990 C.Wilson',0 +; +; +;USER PATCHABLE VALUES +; + ORG 0140H +BAKFlg: DB 0FFH ;0140H - create BAK files (y/n) +DFMode: DB 'A' ;default file modem W/A/N +FDflt1: DB 'Z80N' ;1st default override +FDflt2: DB 'WS W' ;2nd +FDflt3: DB 'CMDN' ;3rd +FDflt4: DB 'LIBN' ;4th +InsFlg: DB 0FFH ;defulat insert on (y/n) +RulFlg: DB 0FFH ;default rules on (y/n) +HCDflt: DB 0FFH ;default HCR disp on (y/n) +HypFlg: DB 0FFH ;enable hyphenation (y/n) +PSFlg: DB 0 ;default proportional flag (y/n) +PSokFl: DB 0FFH ;default allow proportional flag (y/n) +DfltLM: DB 1 ;left margin column (1=OFF) +DfltRM: DB 65 ;right margin column (1=OFF) +Ovlap: DB 2 ;scroll overlap (0=none) +DirSys: DB 0 ;include SYS files (y/n) +FixDsk: DB '@@' ;fixed drives +Ring: DB 0FFH ;error ring bell (y/n) +Help: DB 0FFH ;use help menus (y/n) +AltHdr: DB 0FFH ;use alt video in header (y/n) +NoHdrF: DB 0 ;suppress header +MHz: DB 40H ;clock speed (40h=4MHz) +Timer: DB 38H ;horiz scroll delay (01..FF) +TabCnt: DB 7 ;hard tab cols -1 (1/3/7/15) +VTList: DB 6,11,16,21 ;variable tab columns (8) + DB 0,0,0,0 +VTNum EQU $-VTList +WildCd: DB EOF ;wildcard character +BlkChr: DB 0 ;block characters (^@) +TogTbl: DB 02H,04H,13H,19H ;toggles ^B,^D[^T],^S,^Y +NTgTbl: DB 11H,17H,5,12H ;switches ^Q,^W,^E,^R (last 015C) +; +;INSTALLATION +; + ORG 180H +Z3tcap: DB 'Generic CRT ' ;ID + ORG 190H +View: DB 80 ;viewable columns (max 128) +AuWrap: DB 0FFH ;does autowrap cursor +Lines: DB 24 ;lines +UsrKys: DB 0FFH ;DEL key + DB 0FFH ;arrow up + DB 0FFH ;arrow down + DB 0FFH ;arrow right + DB 0FFH ;arrow left + DB 0 +CIL: DB 0,0,0,0,0,0,0 ;clear to end of line, 6 bytes +TInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal init, 7 bytes +TUInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal uninit +AltOn: DB 0,0,0,0,0,0,0 ;alt video on, 6 bytes +AltOff: DB 0,0,0,0,0,0,0 ;alt video off +AltBit: DB 0 ;high bit gives alt video? +Filter: DB 7FH ;highest ASCII to send to screen +PosMod: DB 'N' ;curpos mode (Std/Rev/ANSI/None) +PCu: DB 1EH,0,0CH,0 ;position cursor to (0,0) +PosDly: DB 0 ;delay after curpos (00-FF) +InsL: DB 0,0,0,0,0,0,0 ;insert line [1], 6 bytes +DelL: DB 0,0,0,0,0,0,0 ;delete line [1], 6 byts +OddDel: DB 0 ;ins/del line specific? +CsrOff: DB 0,0,0,0,0,0,0 ;cursor off +CurOn: DB 0,0,0,0,0,0,0 ;cursor on +; + ORG 01F0H ;Printer codes + DB 'Teletype ' ;ID + ORG 0200H +UseLF: DB 0FFH ;use LF after CR in print? +FormL: DB 54 ;form length (0=no pag) +PTMarg: DB 0 ;top margin skip +DotPO: DB 0 ;left margin skip +PInit: ;printer init, 19 bytes + ORG 0218H +PUInit: ;printer uninit, 7 bytes + ORG 0220H +PCodes: DB 0,0,0,0,0,0,0,0 ;^B toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^T [^D] toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^S toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^Y toggle on + DB 0,0,0,0,0,0,0,0 ;...and off +UCodes: DB 0,0,0,0,0,0,0,0 ;sw 1 (^Q) + DB 0,0,0,0,0,0,0,0 ;sw 2 (^W) + DB 0,0,0,0,0,0,0,0 ;sw 3 (^E) + DB 0,0,0,0,0,0,0,0 ;sw 4 (^R) +; + ORG 0280H +UsrPat: ;0280-02AFH - User Patch Area +;(Can extend back into UCodes section if fewer switches used) +; + ORG 02B0H ;02B0-030EH - Proportinal table +UPatL EQU $-UsrPat +PSTbl: DB 0,-12, 0, 0, 0, 6, 6,-12 ;" "-";" + DB -6, -6, 0, 0,-12, 0,-12, 0 ;"("-"/" + DB 0, 0, 0, 0, 0, 0, 0, 0 ;"0"-"7" + DB 0, 0,-12,-12, 0, 0, 0, 0 ;"8"-"?" + DB 6, 6, 6, 6, 6, 6, 6, 6 ;"@"-"G" + DB 6, -6, 0, 6, 6, 12, 6, 6 ;"H"-"O" + DB 6, 6, 6, 6, 6, 12, 6, 12 ;"P"-"W" + DB 6, 6, 0, -6, 0, -6, 0, 0 ;"X"-"_" + DB -12, 0, 6, 0, 6, 0, -6, 6 ;"'"-"g" + DB 6,-12, -6, 6,-12, 12, 6, 0 ;"h"-"o" + DB 6, 6, 0, 0, -6, 6, 6, 12 ;"p"-"w" + DB 0, 6, 0, -6,-12, -6, 0 ;"x"-"~" +PsL EQU $-PSTbl +; + ORG 0310H ;0310-04AFH - Macro keys +Keys: DS 2 ;free count (VDE does this) + DS 510 +KT: +; +; +;----- EXECUTION BEGINS HERE ------- +; + ORG 0510H +; +Start: SUB A ;check for Z80 + RET PE + LD SP,Stack + LD HL,Data ;zero out data area + LD DE,Data+1 + LD BC,DataLn-1 + LD (HL),0 + LDIR + LD C,CPMV ;get cp/m version in A + CALL BDOSep + LD (DOSVer+1),A ;save CP/M version + CP 30H + JR NC,ItsCP3 + LD C,DOSV ; get extended dos version + CALL BDOSep ; what kind of enhanced BDOS + LD A,H + CP 'S' + JR Z,ZxDOS + CP 'D' + JR NZ,ItsCP3 +ZxDOS: LD (DOSVer+1),A ; store ZS/ZDDOS version + LD C,GETF ; get ZSDOS flags + CALL BDOSep + LD (ZDflgs+1),HL + EX DE,HL + RES 1,E ; public files are R/O + LD C,SETF + CALL BDOSep ; set ZSDOS flags +ItsCP3: CALL DOSVer + LD C,ERRM ; set action on hardware error + LD E,0FEH ; return error code to program + CALL NC,BDOSep ; for anything other than CP/M 2.2 + LD C,GDRV + CALL BDOSep ;save logged drive + LD (CurDsk),A + INC A + LD (FCB),A ; store A=1..P=16 in FCB->drive + LD C,USRN ;and user + LD E,0FFH + CALL BDOSep + LD (CurUsr),A + LD (FCBU),A + LD A,(Lines) + LD (PhysLn),A + CALL AdjLns + LD A,(FormL) + LD (PgLen),A + LD HL,(DfltLM) + LD (LfMarg),HL + LD A,(BlkChr) + LD (BadTbl),A + LD A,(UseLF) + CPL + OR LF + LD (LFChr),A + LD HL,MacStr + DEC (HL) ;make a FF terminator + XOR A ;a bad load will exit and invoke Z33's + LD (BadLdX+1),A ;error handler +; + LD HL,DMA + LD A,(HL) + INC HL + CALL Parse ;parse command line +; + CALL VerKey ;verify keys + LD HL,TInit + CALL CtlStr ;Clear and home cursor + JR Edit ;start editing. +; +;Clear it all out and start over. +; +Restrt: LD A,1 ;a bad load will not exit and invoke + LD (BadLdX+1),A ;Z33's error handler + LD HL,LoadQ + CALL NewNam + LD A,(EdErr) ;bad name? + OR A + JR NZ,BadLdX +; +;Start editing a File +; +Edit: CALL IniRAM ;initialize memory + CALL DfltM ;adjust defaults + CALL DoHdr ;show header + CALL Top ;Start at TOF + CALL Error0 ;No errors + LD A,(FCB+1) + CP ' ' ;Filename blank? + JR Z,Edit1 + CALL SavNam ;save it for LoadIt kludge + CALL LoadIt ;Get input file + LD A,(EdErr) + CP 1 ;is it too big? + JR NZ,Edit1 +BadLdX: LD A,0 ;a non-zero value will set up Z33's message + OR A ;buffer to have the Z33 error handler handle + JR NZ,BadLd ;the 'TPA full' condition when we exit + LD BC,Z3MSG + CALL Z3EAdr + JR Z,BadLd + LD H,B + LD L,C + LD (HL),TPAful ; Z3MSG error byte: file too big + INC HL + INC HL + INC HL ; point HL at Z3MSG command status byte + LD (HL),ErrSta ; error, ECP running, external invocation + JP QuitY +BadLd: CALL DoErr ;Too big, or bad name + CALL BlkFCB ;(Other error means new file) + JR Edit +Edit1: LD A,(MSIFlg) ;set up BAKflag + LD HL,BAKFlg + AND (HL) + LD (FilFlg),A + XOR A + LD (Modify),A +; +Reset: LD SP,Stack ;recover from ^U prompt abort + CALL ShoLn1 +; +; +;MAIN LOOP: SHOW TEXT, GET KEY +; +Ready: CALL Orient ;Get bearings + LD HL,(OldLin) ; ### + LD (SavLin),HL ; ### + LD A,(OldCol) ; ### + LD (SavCol),A ; ### + LD A,(MacFlg) ; ### + OR A ; ### + JR NZ,RdyMac ; ### + LD HL,(CurLin) ; ### + LD (OldLin),HL ; ### + LD A,(CurCol) ; ### + LD (OldCol),A ; ### +RdyMac: CALL ShoTx ; then show text as needed + CALL Cursr ;position cursor + CALL TRptKy ;Get input + PUSH AF + CALL Error0 ;Clear error indicator + CALL SetNo ;default NO redisp + POP AF + CALL AdjKey ;translate arrows/DEL +; +DoKey: CALL Case ;try to match control code? + DB MnuLn/3 + DW IChar ;Default : Insert character +MnuSt EQU $ + DB 0 ;(internal use: null key) + DW CKCan + DB 80H ;DEL + DW Delete + DB 81H ;Up arrow + DW Up + DB 82H ;Down + DW Down + DB 83H ;Right + DW Right + DB 84H ;Left + DW Left + DB ESC + DW Escape + DB '^'-40H + DW UpLow + DB '\'-40H + DW Repeat ;Synonym for ^L + DB 'A'-40H + DW WordLf + DB 'B'-40H + DW Reform + DB 'C'-40H + DW PageF + DB 'F'-40H + DW WordRt + DB 'G'-40H + DW EChar + DB 'I'-40H + DW TabKey + DB 'J'-40H + DW DoMnu + DB 'K'-40H + DW CKKey + DB 'L'-40H + DW Repeat + DB 'M'-40H + DW ICR + DB 'N'-40H + DW ICRA + DB 'O'-40H + DW Onscrn + DB 'P'-40H + DW CtlP + DB 'Q'-40H + DW Quick + DB 'R'-40H + DW PageB + DB 'T'-40H + DW WordDl + DB 'U'-40H + DW Undel + DB 'V'-40H + DW IToggl + DB 'W'-40H + DW Scr1LU + DB 'Y'-40H + DW Eline + DB 'Z'-40H + DW Scr1LD +MnuLn EQU $-MnuSt +; +Sk1Ed: LD A,(EdErr) ;Check for error, repeat main loop + OR A + CALL NZ,DoErr + JP Ready +; +;Block commands: ^K toggle is on +; +CKKey: LD HL,CKTog + CALL Prefix +CKSyn: CALL XCase ;Entry for ESC synonyms + CALL Case + DB KMnuLn/3 + DW Error2 ;complain if unknown +KMnuSt EQU $ + DB 'B'-40h + DW Block + DB 'C'-40h + DW Copy + DB 'D'-40h + DW Done + DB 'E'-40h + DW Era + DB 'F'-40h + DW Dir + DB 'H'-40h + DW DoMnu + DB 'I'-40h + DW Info + DB 'K'-40h + DW Termin + DB 'L'-40h + DW Load + DB 'N'-40h + DW ChgNam + DB 'P'-40h + DW Print + DB 'Q'-40h + DW Quit + DB 'R'-40h + DW Read + DB 'S'-40h + DW Save + DB 'U'-40h + DW Unmark + DB 'V'-40h + DW MovBlk + DB 'W'-40h + DW Write + DB 'X'-40h + DW Exit + DB 'Y'-40h + DW EBlock + DB ESC + DW CKCan + DB ' ' + DW CKCan +KMnuLn EQU $-KMnuSt +CKCan: RET +; +;ESC commands: ESC toggle is on. +; +Escape: LD HL,ESCTog + CALL Prefix + CALL AdjKey + CALL UCase + CP '0' + JR C,Esc01 ;macro Keys: special case + CP '9'+1 + JP C,UseKey +Esc01: CALL Case + DB EMnuLn/3 + DW CKSyn ;default: ^K synonym +EMnuSt EQU $ + DB 81H ;Up arrow + DW ShftU + DB 82H ;Down + DW ShftD + DB 83H ;Right + DW ShftR + DB 84H ;Left + DW ShftL + DB '[' ;ANSI cursor sequences + DW ANSIcu + DB TAB + DW TaBack + DB 'M' + DW DoMac + DB '#' + DW MacKey + DB '!' ;macro prog stmts + DW MacJmp + DB '=' + DW MacTst + DB '~' + DW MacTsX + DB '+' + DW ChainK + DB ';' + DW Wait +EMnuLn EQU $-EMnuSt + RET +; +;Onscreen commands. ^O toggle is on. +; +Onscrn: LD HL,COTog + CALL Prefix + CALL XCase ;force to ctl + CALL AdjKUp ;adjust UP ARROW ONLY + CALL Case ;What function? + DB OMnuLn/3 + DW Error2 ;complain if unknown +OMnuSt EQU $ + DB 81H ;up + DW MakTop + DB 'A'-40h + DW AITog + DB 'C'-40h + DW Center + DB 'D'-40h + DW HCRTog + DB 'F'-40h + DW Center ;same fn as 'C' + DB 'H'-40h + DW HypTog + DB 'I'-40h + DW VTSet + DB 'J'-40h + DW PSTog + DB 'L'-40h + DW SetLM + DB 'N'-40h + DW VTClr + DB 'P'-40h + DW PgSet + DB 'Q'-40h + DW NoHdr + DB 'R'-40h + DW SetRM + DB 'S'-40h + DW DblTog + DB 'T'-40h + DW Ruler + DB 'V'-40h + DW VTTog + DB 'W'-40h + DW Window + DB 'X'-40h + DW RelM + DB 'Z'-40h + DW Blank + DB ESC + DW COCan + DB ' ' + DW COCan +OMnuLn EQU $-OMnuSt +COCan: RET +; +;Quick commands. ^Q toggle is on. +; +Quick: LD HL,CQTog + CALL Prefix + CALL XCase + CALL AdjKey ;translate arrow/DEL + CALL Case ;What function? + DB QMnuLn/3 + DW Error2 ;complain if unknown +QMnuSt EQU $ + DB 80H ;DEL + DW EBLine + DB 81H ;Up arrow + DW QuikUp + DB 82H ;Down + DW QuikDn + DB 83H ;Right + DW QuikRt + DB 84H ;Left + DW QuikLf + DB 'A'-40h + DW Rplace + DB 'B'-40h + DW QikBlk + DB 'C'-40h + DW Bottom + DB 'F'-40h + DW Find + DB 'Q'-40h + DW Queue + DB 'I'-40h + DW ZipTo + DB 'P'-40h + DW QuikLc + DB 'R'-40h + DW Top + DB 'T'-40h + DW E2Char + DB 'U'-40h + DW UndlLn + DB 'Y'-40h + DW EOLine + DB 'Z'-40h + DW QuikMk + DB ESC + DW CQCan + DB ' ' + DW CQCan +QMnuLn EQU $-QMnuSt +CQCan: RET +; +; +; +Prefix: PUSH HL ;show prefix, get suffix + LD DE,DspEsc + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + LD B,1 + CALL BBlank + LD DE,DspEsQ ;position cursor + CALL GoTo + CALL RptKey ;get suffix + PUSH AF + LD A,(NoHdrF) + OR A + JR NZ,PrefNH + LD DE,DspEsc + CALL GoTo + LD B,4 ;clean up + CALL BBlank + CALL UnAlt + POP AF + RET +PrefNH: CALL UnAlt ;(if no header) + CALL ShoLn1 + CALL RulFix + POP AF + RET +; +; +;Return to CP/M ... With or without saving +; +Exit: CALL Save ;Save the file + LD A,(EdErr) ;Was it ok? + OR A + RET NZ ;No, do not quit + JR QuitY1 +; +Done: CALL Save ;Save, and load new + LD A,(EdErr) + OR A + RET NZ + JP Restrt +; +Quit: LD A,(Modify) ;Quit to CP/M + OR A + JR Z,QuitY1 + LD HL,QuitQ + CALL Prompt + CALL Confrm ;warn if file changed... + JP NZ,ShoLn1 +QuitY1: XOR A ;### + LD (WinFlg),A ;### + CALL AdjLns ;### + LD BC,Z3MSG ;### + CALL Z3EAdr ;### + JR Z,QuitY ;### + LD HL,MsgUsr ;### offset to user area in message buffers + ADD HL,BC ;### + LD DE,CurLin ;### store the current line# in the Z3 + EX DE,HL ;### + LD BC,2 ;### + LDIR ;### +QuitY: LD HL,TUInit ;Clear screen + CALL CtlStr + LD A,(CurDsk) ;restore logged disk + LD E,A + LD C,SELD + CALL BDOS + LD A,(CurUsr) ;and user + LD E,A + LD C,USRN + CALL BDOSep + CALL DOSVer + JP C,Boot ;### restart if CP/M 2.2 + CP 'S' ;### + JR Z,ZSErrR ;### + CP 'D' ;### + JR NZ,CPM3xt ;### +ZSErrR: LD C,SETF ;### restore ZxDOS flags +ZDflgs: LD DE,0 ;### + CALL BDOSep ;### +CPM3xt: LD C,ERRM ;### reset ZxDOS, CP/M 3 error mode + LD E,0 ;### + CALL BDOSep ;### + JP Boot ;### and restart +; +;Error handler +; +DoErr: CALL Loud ;Show error message, wait for ESC + CALL SetNo + LD A,(MacFlg) + OR A ;### + CALL NZ,RstI1x ;### + XOR A ;### + LD (MacFlg),A ;### kill any running macro + LD A,(EdErr) + CP 10 + JP NC,SetAl ;error 10 does NOT show + LD A,(Ring) + OR A + LD E,BEL + CALL NZ,ShutUp ; ring bell + CALL MakAlt + CALL UpLft + CALL Dspl + DB X,31,'[[','['+X,0 + LD A,(EdErr) + ADD A,A ;Double the code + LD L,A + LD H,0 + LD DE,ErrTab + ADD HL,DE + LD E,(HL) ;Get msg addr from table + INC HL + LD D,(HL) + EX DE,HL + CALL DspLp ;show it + CALL DsplC + DB ' ]]]',CR,0 + CALL UnAlt + CALL ESCLp + LD A,(EdErr) + CP 1 + JR Z,DoErr2 + CP 5 + JR Z,DoErr2 + CP 9 + JP C,ShoLn1 ;(errors 2-8 need no redisp) +DoErr2: JP SetAl +ESCLp: CALL RptKey ;await ESC from console + CP ESC + RET Z + CP ' ' + JR NZ,ESCLp + RET +; +Error0: LD A,0 ;clear error (don't change flags) + JR ErrSet +Error1: LD A,1 ;error set fns + JR ErrSet +Error2: LD A,2 + JR ErrSet +Error3: LD A,3 + JR ErrSet +Error4: LD A,4 + JR ErrSet +Error5: LD A,5 ;6 currently not used + JR ErrSet +Error7: LD A,7 + JR ErrSet +Error8: LD A,8 + JR ErrSet +Error9: LD A,9 + JR ErrSet +Eror10: LD A,10 +ErrSet: LD (EdErr),A + RET +; +; +;INPUT ROUTINES +; +KeyIn: LD HL,(Timer) ;Get key, regardless + LD H,0 + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL + INC HL +KyIn1: PUSH HL + CALL KyStat + POP HL + DEC HL + JR NZ,Keybd ;read key if got one + LD A,(HorFlg) + LD E,A + LD A,(KeyFlg) + OR E + OR H + OR L ;allow redisp for horizontal scroll? + JR NZ,KyIn1 + CPL + LD (HorFlg),A ;yep (just once) + CALL ShoAll + CALL Cursr + JR KyIn1 +; +Keybd: CALL KyStat ;Get key, or 0 if none + RET Z + LD HL,ConBuf + DEC (HL) ;uncount it + INC HL + LD A,(HL) ;here it is + LD D,H + LD E,L + INC HL + LD BC,ConBufL-1 + LDIR ;remove it + AND 7FH ;strip parity + RET +; +KyStat: CALL CONSt ;Console status with buffering + JR Z,ConChk ;all quiet + LD HL,ConBuf ;got key + INC (HL) ;ok, count it + LD E,(HL) + LD D,0 + ADD HL,DE ;point there + LD (HL),A ;put it in + LD A,E + CP ConBufL ;buffer full? + JR C,ConChk +ConBsy: LD A,0C9H ;(RET) + LD (Plug),A ;plug up the console until buffer empty +ConChk: LD A,(ConBuf) ;check buffer (FAST) + OR A + RET NZ + LD (Plug),A ;buffer empty, unplug console + RET +; +CONSt: XOR A +Plug: NOP ;<--- RET plugs up console + LD E,0FFH ;console status/input + LD C,UCON + CALL BDOSep + OR A ;test for null + RET +; +KyPeek: CALL KyStat ;key available? + RET Z ;no + LD A,(ConBuf+1) ;return 1st char in buffer + AND 7FH ;strip parity + RET +; +; +Confrm: CALL RptKey ;get a Y/N answer + CALL UCase + CP 'Y' ;return Z if confirmed + RET Z + CP 'U'-40h + JR Z,IsCtlU + CP ESC ;allow this too +IsCtlU: JP Z,Reset + CP 'N' + JR NZ,Confrm +CnfNo: OR A + RET +; +;Translate four arrow keys and BS,DEL +; +AdjKey: CP BS ;First handle ^H (special case) + JR NZ,AdjK0 + LD C,80h ;make it DEL + LD HL,UsrKys + CP (HL) ;Is it installed as DEL? + JR Z,AKret + LD C,84h ;no, then it's Left arrow + CP A + JR AKret +AdjK0: LD B,5 ;Not ^H, try the rest + JR AdjK1 +AdjKUp: LD B,2 ;only do (DEL and) UP arrow +AdjK1: LD HL,UsrKys + LD DE,WSKys + LD C,7FH ;encode 80h=DEL, 81h=up, etc. +AKlp: INC C + CP (HL) + JR Z,AKret + EX DE,HL + INC DE + CP (HL) + JR Z,AKret + INC HL + DJNZ AKlp + CP C + LD C,A ;NO match: return NZ, char in A and C +AKret: LD B,A ;MATCH: return Z, code in A, char in C + LD A,C + LD C,B + RET +WSKys: DB DEL,'E'-40H,'X'-40H,'D'-40H,'S'-40H +; +; +ANSIcu: CALL RptKey ;Handle ANSI cursor keys ESC-[... + SUB 'A' + JP Z,Up + DEC A + JP Z,Down + DEC A + JP Z,Right + DEC A + JP Z,Left + JP Error2 +; +;Get string input +; +GetStr: LD A,LinLen+1 ;string length +1 +GSEnt: LD (GSlen+1),A ;(entry for GetNum and NewNam) + LD HL,DMA ;*** MUST be 0080h *** +Lp1GSx: EXX + POP HL ;word after call + PUSH HL + LD E,(HL) ;storage/recall buffer address + INC HL + LD D,(HL) + LD (GSbufA),DE + EXX +Lp1GSy: XOR A + LD (RclFlg),A +Lp1GS: LD A,L + SUB DMA ;length +GSlen: CP 0 ;<---- max length pastes in here + JR NC,GSBS ;full? + LD A,(RclFlg) + OR A + JR NZ,GSrcl + PUSH HL + CALL RptKey ;Get next input + CALL AdjKey ;translate key + POP HL + CP 80H ;corrections? DEL, + JR Z,GSBS + CP 84H ;left + JR Z,GSBS + CP 83H ;right + JR Z,GSrcl ;recall a char + CP CR ;CR ends + JR Z,GSCR + CP 'U'-40H ;^U aborts operation + JP Z,Reset + CP 'P'-40H ;^P for ctlcode + JR Z,GSctl + LD A,C ;restore orig char + CP 'X'-40H ;wipeout + JR Z,GSwipe + CP 'R'-40H + JR Z,GSrcl ;recall the last string +; +Sk1GS: LD (HL),A ;Store byte + INC HL ;Move along + CP 20H ; ctl char? + PUSH HL + JR NC,Sk2GS ;no, just a normal char + ADD A,40H ;ctls are hili letters + PUSH AF + CALL AltY + POP AF + CALL PutChA + CALL UnAltY + JR Sk3GS +Sk2GS: CALL PutChA ;show byte +Sk3GS: POP HL + JR Lp1GS +; +GSBS: CALL GSBSsb + JR Lp1GSy +GSwipe: CALL GSBSsb + JR NZ,GSwipe + JR Lp1GSx +GSBSsb: LD A,DMA ;Are we at start + CP L + RET Z ;return Z if so + DEC HL ;back up pointer + LD E,BS ;wipe out char + CALL PutCh + LD E,' ' + CALL PutCh + LD E,BS + CALL PutCh + OR 1 ;clear flags + RET +; +GSrcl: EX AF,AF' ;save original char + EXX ;save HL + LD HL,(GSbufA) ;recall buffer ptr + LD A,H + OR L + EXX ;restore HL + JP Z,Lp1GS ;no recall buffer + EXX ;recall buffer ptr in HL + LD A,(HL) ;fetch char from recall buffer + EXX ;restore HL + OR A ;any char? + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + CP 0FFH + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + EXX ;recall buffer pre in HL + INC HL ;point to next char + LD (GSbufA),HL ;update recall buffer ptr + EXX ;restore HL + EX AF,AF' ;restore original char + CP 'R'-40h ;^R? (whole string) + JR NZ,GSrclX ;no, just a single char + LD (RclFlg),A +GSrclX: EX AF,AF' ;restore char from recall buffer + JR Sk1GS ;store char +; +GSCR: LD (HL),0 ;terminator + LD A,L + SUB DMA ;Compute input length (Z=zero) + POP DE ;skip over buffer address + INC DE + INC DE + PUSH DE + RET ;HL points past end of string +; +GSctl: PUSH HL + CALL RptKey + CALL XCase + POP HL + JP Sk1GS +; +;Get numeric input (0-65535 decimal), return C if bad +; +GetNbr: PUSH BC ;BC = default if no input + LD A,5+1 + CALL GSEnt ;get up to 3 digits + DW 0 + POP DE + JR NZ,GNyes + LD B,D + LD C,E + LD A,B ;no entry, use default + OR C + RET +GNyes: LD DE,DMA ;fall thru to GetNNN +; +GetNNN: PUSH HL ;gets decimal # pointed by DE + LD H,D + LD L,E + LD B,0 +GNL: LD A,(HL) + CP '0' + JR C,GotN ;terminated by any nondigit. + CP '9'+1 + JR NC,GotN + INC HL + INC B + LD A,B + CP 5+1 + JR NC,GNErr ;5 digits max. + JR GNL +GotN: LD A,B ;okay, do them + LD BC,0 + OR A ;digits? + JR Z,GNErr + CP 2 + JR Z,Got2 + JR C,Got1 + CP 4 + JR Z,Got4 + JR C,Got3 + CP 5 + JR NZ,GNErr +Got5: LD HL,10000 + CALL GNNdig + JR C,GNErr +Got4: LD HL,1000 + CALL GNNdig + JR C,GNErr +Got3: LD HL,100 + CALL GNNdig + JR C,GNErr +Got2: LD HL,10 + CALL GNNdig + JR C,GNErr +Got1: LD HL,1 + CALL GNNdig + JR C,GNErr + POP HL + LD A,B + OR C + RET +GNErr: POP HL + SCF ;error + RET +; +GNNdig: LD A,(DE) ;do a digit: HL=power of 10 + INC DE +GNNLp: CP '0' + RET Z + DEC A + PUSH HL + ADD HL,BC + LD B,H + LD C,L + POP HL + RET C ;overflow + JR GNNLp +; +;Versions of above for 0...255 only: GetNum, GetNN take # in A +; +GetNum: LD C,A + LD B,0 + CALL GetNbr + JR GetNN1 +GetNN: CALL GetNNN +GetNN1: RET C + XOR A + OR B + JR NZ,GetNNX + OR C ;result in A, OK + RET +GetNNX: SCF ;oops, too big + RET +; +; +;Convert 16-bit number in HL to a one to five +;digit decimal number in the area pointed to by DE +; +BCDCon: LD IX,P10Tab ;Point at table + PUSH DE ;Save output pointer +BCDlp1: LD B,(IX+1) + LD C,(IX) + LD A,C ;low byte + CP 1 ;Clear carry flag + JR Z,BCDend + SBC HL,BC ;Subtract from input + JR NC,BCDok ;Got one in range + ADD HL,BC ;Restore it + INC IX + INC IX + JR BCDlp1 ;Try next one +; +BCDok: LD A,'1' + LD (DE),A ;Set initial digit +BCDlp2: SBC HL,BC ;Subtract again + JR C,BCDsk1 ;Went negative + EX DE,HL + INC (HL) ;Increment digit + EX DE,HL + JR BCDlp2 +; +BCDsk1: ADD HL,BC ;Restore it + INC DE ;Bump output + INC IX + INC IX + LD C,(IX) + LD B,(IX+1) + LD A,C + CP 1 ;Is this last entry + JR Z,BCDend + LD A,'0' + LD (DE),A + JR BCDlp2 +; +BCDend: LD A,L + OR '0' + LD (DE),A + INC DE + EX DE,HL + POP BC + SBC HL,BC ;Number filled + LD A,5 ; needed + SUB L ; to do + RET Z + ADD HL,BC ;Restore pointer +BCDlp3: LD (HL),' ' ;Clear field + INC HL + DEC A + JR NZ,BCDlp3 + RET +; +P10Tab: DW 10000,1000,100,10,1 +; +; +; +;PRINT text from memory +; +Print: LD HL,PgLen ;set defaults + XOR A + CP (HL) + JR NZ,Pr00 + INC A ;bit 0 set if no pagn +Pr00: LD (POByt),A + XOR A + LD (HdrLen),A + LD (POff),A + CPL + LD (PNum),A + LD (PrFlg),A + LD A,1 + LD (Copies),A + LD (PBeg),A + LD A,(DotPO) + LD (PrLMrg),A + LD A,(PTMarg) + LD (PrTMrg),A + LD HL,PrtQ ;options? + CALL Prompt + CALL GetStr ;get string into 80 + DW 0 +PO1st: LD DE,DMA ;point to option string +PrOlp: LD A,(DE) + INC DE + LD HL,POByt ;set up bit flags + LD BC,PrOlp + PUSH BC ;(return) + CALL UCase + CP ' ' ;eat spaces + RET Z + CP 'B' + JR Z,POBlk + CP 'D' + JR Z,PODblS + CP 'P' + JR Z,POPau + CP 'L' + JR Z,POLMrg + CP 'T' + JR Z,POTMrg + CP '*' + JR Z,POCpy + CP '^' + JR Z,POCtl + CP '@' + JR Z,POBeg + CP '#' + JR Z,PONum + CP '=' + JP Z,POPgS + CP '"' + JP Z,POHdrT + POP BC ;kill return + OR A + JP NZ,Error7 ;unexpected char + LD A,(PrFlg) + LD B,A + XOR A ;zero PrFlg + LD (PrFlg),A + OR B + JR NZ,PO1st + JP PORdy +; +PrFlg: DB 0 +; +POCpy: CALL GetNN ;"*" sets copy count + JP C,POBad + LD (Copies),A + RET +POLMrg: CALL GetNN ;"Lnn" sets left margin + JP C,POBad + LD (PrLMrg),A + RET +POTMrg: CALL GetNN ;"Tnn" sets top margin + JR C,POBad + LD (PrTMrg),A + RET +POPau: SET 4,(HL) ;bit 4 is for "P" + RET +PODblS: SET 3,(HL) ;bit 3 is for "D" + RET +POCtl: SET 2,(HL) ;bit 2 is for "^" + RET +POBlk: LD A,(HL) + AND 11000010B ;bits 1,6,7 must be clear + JR NZ,POBad + SET 5,(HL) ;set bit 5 (BLOCK) + RET +POBeg: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"@" page beginning + JR C,POBad + OR A + JR Z,POBad + LD (PBeg),A + SET 6,(HL) ;bit 6 is for "@" (suppresses output) + SET 7,(HL) ;so is bit 7 (multicopy) + INC A + NEG ;255-@ is most # can be + LD B,A + LD A,(PNum) + CP B + RET C ;okay, less + LD A,B + LD (PNum),A + RET +PONum: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"#" page count + JR C,POBad + OR A + JR Z,POBad + LD B,A + LD A,(PBeg) + ADD A,B ;@ + # cannot exceed 255 + JR C,POBad + LD A,B + LD (PNum),A + RET +POPgS: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"=" starting pagination + JR C,POBad + OR A + JR Z,POBad + LD (POff),A ;offset beginning page + RET +POHdrT: BIT 0,(HL) ;must be paginating + JR NZ,POBad + SET 1,(HL) ;bit 1 requests header + LD (HdrPtr),DE ;point to header text + LD B,50 ;and figure its length +POHlp: LD A,(DE) + INC DE + CP '"' + JR Z,POHlpF + DJNZ POHlp + JR POBad ;too long +POHlpF: LD A,50 + SUB B ;length + LD (HdrLen),A + RET +POBad: POP HL ;eat return + JP Error7 +; +PORdy: CALL IOon ;say Wait + LD HL,PInit ;init string? + LD B,(HL) + INC HL + CALL LSTStr + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;move to top of file + LD A,(POff) + OR A + JR NZ,PORdy0 + LD A,(PBeg) +PORdy0: LD HL,PBeg + SUB (HL) ;adjust starting page offset + LD (POff),A + LD HL,POByt + BIT 5,(HL) + JR Z,PORdy1 + CALL IsBlk ;block print requested + BIT 1,A ; must be marked + JP Z,PrOops + INC DE + PUSH HL + SBC HL,DE + POP HL + RET Z ;block empty + DEC HL + EX DE,HL + JR PORdy2 +PORdy1: CALL NdCnt ;print whole file + JP C,PrDone ;file empty + LD HL,(AftCu) + LD DE,(EndTx) +PORdy2: LD (StPrt),HL + LD (EndPr),DE + CALL PCR ;### +; +RePrt: LD HL,POByt ;[reprint reentry] + BIT 7,(HL) + JR Z,PRP0 + SET 6,(HL) ;remember if "@" was used +PRP0: XOR A + LD (PageN),A + INC A + LD (IgnFlg),A ;TOF is start of line (DotChk) + LD A,(PgLen) ;start first page + LD B,A + OR A + PUSH AF ;### + CALL Z,DoPOf ;### + POP AF ;### + CALL NZ,PgBrk + JR C,Sk4Pr + LD HL,(StPrt) ;Point at first one + LD C,0 ;Initialize GetNx +Lp1Pr: CALL GetNx ;Get a character + CALL DotChk ;(maybe ignore dot command lines) + CP CR + JR NZ,Sk2Pr + CALL PrOut ;It's a CR + PUSH BC + PUSH HL + CALL Keybd + CP ESC ;Abort request? + POP HL + POP BC + JR Z,Sk1Pr + LD A,(POByt) + BIT 3,A ;doublespacing? do extra CR(LFCR)LF + JR Z,Sk0Pr + CALL PLF + CALL PCR + LD A,B ;count it (if paginating) + OR A + JR Z,Sk0Pr + DEC B + JR Z,Sk01Pr +Sk0Pr: LD A,B + OR A ;Not paginating? B is and stays 0 + LD A,(LFChr) ;Add usual line feed + JR Z,Sk2Pr + DJNZ Sk2Pr +Sk01Pr: CALL PgBrk ;time for NEW PAGE + JR C,Sk4Pr ;done? + JR Sk2aPr +Sk1Pr: LD A,1 ;abort + LD (Copies),A + JR Sk3Pr +Sk2Pr: CALL ChekC ;Check for masking + CALL PrOut ;Output char + XOR A + CP C ;Hidden space waiting? + JR NZ,Lp1Pr +Sk2aPr: LD DE,(EndPr) ;At end? + LD A,E + SUB L + LD A,D + SBC A,H + JR NC,Lp1Pr ;Loop if more to go +Sk3Pr: CALL PCR ;last CRLF for some matrix printers + LD A,(LFChr) + LD C,A + LD A,(PgLen) + OR A ;Finish page? + JR Z,Sk3aPr + LD C,FF +Sk3aPr: LD A,C + CALL PrOut +Sk4Pr: LD HL,PCodes ;undo toggles if on + LD DE,16 + LD B,4 +Lp2Pr: BIT 7,(HL) + JR Z,Lp2PrF + RES 7,(HL) + PUSH BC + PUSH DE + PUSH HL + LD DE,8 + ADD HL,DE + LD B,(HL) + INC HL + CALL LSTStr + POP HL + POP DE + POP BC +Lp2PrF: ADD HL,DE + DJNZ Lp2Pr + LD HL,Copies ;more copies? + DEC (HL) + JP NZ,RePrt + LD HL,PUInit ;uninit string? + LD B,(HL) + INC HL + CALL LSTStr + JR PrDone +PrOops: CALL Error7 +PrDone: LD HL,(LastCu) ;all finished + DEC HL + CALL MoveR ;go back to position + CALL IOoff + JP ShoLn1 +; +PgBrk: PUSH BC ;call this for new page (returns C for EOP) + PUSH HL + LD A,(PageN) + OR A + LD A,FF ;start new sheet IF not 1 + CALL NZ,PrOut + LD A,(POByt) + BIT 4,A ;pause requested? + JR Z,NP00 + CALL IOoff ;do it + LD HL,RdyQ + CALL Prefix + CP ESC + JP Z,NPquit + CALL IOon +NP00: LD HL,PageN + INC (HL) + JP Z,NPquit ;255 page limit. + LD C,(HL) ;check "#" limit? + LD A,(PBeg) + LD E,A + LD A,(PNum) ;Pnum+Pbeg-1 = Lastpage# + DEC A + ADD A,E + JP C,NPquit ;255 page limit + CP C + JP C,NPquit ;"#" pages printed... quit. + LD A,(PBeg) + LD C,A + LD A,(PageN) + CP C + LD HL,POByt + JR C,NP10 ;are we "@" yet? + RES 6,(HL) ;yes (start) printing + LD A,0C9H ;begin with margin offset + LD (DoPOf),A +NP10: LD A,(PrTMrg) + OR A + JR Z,NP20 + LD B,A +NP11Lp: CALL PCRLF ;top margin? + DJNZ NP11Lp +NP20: LD HL,POByt + BIT 1,(HL) + JR Z,NPnoh ;want header? + LD A,(HdrLen) + ADD A,6 + LD B,A + LD A,(RtMarg) ;column for page no. + SUB B + JR NC,NPlp + LD A,70 ;default if margin unusable + SUB B +NPlp: PUSH AF ;space over to right justify header + CALL PrSpc + POP AF + DEC A + JR NZ,NPlp + LD HL,(HdrPtr) ;put out header + LD A,(HdrLen) + LD B,A + CALL POStr + CALL PrSpc + LD A,(PageN) ;put out page + LD HL,POff + ADD A,(HL) ;adjust for "=" option + LD L,A + LD H,0 + LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + CALL POStr + CALL PCRLF + CALL PCRLF ;two blank lines + CALL PCRLF +NPnoh: XOR A + LD (DoPOf),A + CALL DoPOf + POP HL + POP BC + LD A,(PgLen) ;reset TOP + LD B,A + OR A + RET +NPquit: POP HL + POP BC + SCF + RET +PNBuf: DB 'nnnnn',0 ;(also used elsewhere) +; +DotChk: CP CR ;may ignore dot commands + JR Z,DotCCR + CP '.' + JR Z,DotCDt +DtC01: EX AF,AF' ;ordinary char + LD A,(IgnFlg) + CP 0FFh ;ignoring chars? + RET Z ;(returns 0FFh, nonprinting) + XOR A + LD (IgnFlg),A ;nope, clear dot search +DtCRet: EX AF,AF' ;no action, accept char + RET ;leave it 0FFh (ignore) +DotCCR: CALL DtC01 + EX AF,AF' + LD A,1 ;1 = ready to ignore if next char dot + LD (IgnFlg),A + EX AF,AF' + RET +DotCDt: EX AF,AF' + LD A,(FMode) ;Only ignore dotcmds in "W" mode + CP 'W' + JR NZ,DtCRet + LD A,(IgnFlg) + OR A + JR Z,DtCRet + LD A,0FFh ;FF = dot seen, ignore + LD (IgnFlg),A + RET +; +ChekC: CP ' ' ;may mask ctl chars + RET NC + CP CR ;exceptions: CR,LF,BadTbl + RET Z + CP LF + RET Z + PUSH HL + PUSH BC + LD HL,BadTbl + LD BC,BadLen + CPIR + POP BC + POP HL + RET Z + PUSH AF + LD A,(POByt) + BIT 2,A + JR NZ,CMask + POP AF + RET +CMask: LD A,'^' ;mask: print "^", + CALL PrOut + POP AF + OR 40H ;turn ^A into A, etc. + RET +; +PCR: LD A,CR + JR PrOut +PrSpc: LD A,' ' +PrOut: CP 0FFH ;(FF=dummy code, ignore) + RET Z + PUSH BC ;Print byte + PUSH DE + PUSH HL + LD HL,POByt ;printing yet? + BIT 6,(HL) + JR NZ,Sk2PO + CP ' ' + JR NC,Sk1PO ;non-ctl + LD HL,BadTbl + LD BC,BadLen + CPIR + JR Z,Sk2PO ;ILLEGAL + LD HL,TogTbl + LD BC,4 + CPIR ;toggle? + JR Z,Sk3PO + LD BC,4 + CPIR ;switch? + JR NZ,Sk1PO ;arbitrary ctl-code + LD A,4-1 + SUB C ;nontog# (0..n) + ADD A,A + ADD A,A + ADD A,A ;*8 + LD E,A + LD D,0 + LD HL,UCodes + ADD HL,DE +Sk00PO: LD B,(HL) + INC HL ;string to send +Sk0PO: CALL LSTStr + JR Sk2PO +Sk3PO: LD A,4-1 + SUB C ;tog# (0..n) + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;*16 + LD E,A + LD D,0 + LD HL,PCodes + ADD HL,DE + BIT 7,(HL) ;toggle status? + JR NZ,Sk3aPO + LD B,(HL) ;off, turn on + SET 7,(HL) + INC HL + JR Sk0PO +Sk3aPO: RES 7,(HL) ;on, turn off + LD DE,8 + ADD HL,DE + JR Sk00PO +Sk1PO: LD E,A ;byte to send + PUSH AF + CALL LSTOut + POP AF + LD HL,LFChr + CP (HL) + CALL Z,DoPOf ;LF? need margin skip +Sk2PO: POP HL + POP DE + POP BC + RET +; +DoPOf: NOP + LD A,(PrLMrg) ;do printer margin offset + OR A + RET Z + LD B,A +DoPOfL: CALL PrSpc + DJNZ DoPOfL + RET +; +PCRLF: CALL PCR ;do CR(LF?) +PLF: LD A,(LFChr) + JP PrOut +; +POStr: LD A,B ;send B chars at (HL) to PrOut + OR A + RET Z + LD A,(HL) + CALL PrOut + INC HL + DJNZ POStr + RET +; +LSTStr: LD A,B ;send B chars at (HL) to LST directly + OR A + RET Z + LD E,(HL) + PUSH BC + PUSH HL + CALL LSTOut + POP HL + POP BC + INC HL + DJNZ LSTStr + RET +; +LSTOut: LD C,LSTO ;print char in E + JP BDOSep +; +; +; +; ASSORTED SUPPORT ROUTINES +; +;RAM initialization functions +; +IniRAM: LD HL,MnuEnd ;Figure what used to be TxtOrg + LD A,(Help) ;help menus disabled? + OR A + JR NZ,IniR02 + LD HL,HelpY ;yes, use that memory for editing +IniR02: LD (BegTx),HL + LD HL,(BDOSep+1) ;BDOS origin (xx06) + LD L,-4 ;a few bytes room + DEC H ;back a page + LD (EndTx),HL + XOR A ;initialize screen + LD (NSkip),A + INC A + LD (Horiz),A + LD (Vert),A + LD (CurCol),A + LD (OldCol),A ;### + LD HL,1 + LD (CurPg),HL + LD (CurPgL),HL + LD (CurLin),HL + LD (OldLin),HL ;### + LD HL,(BegTx) ;set up cursor gap, mark CRs at ends + DEC HL + LD (BefCu),HL + LD (HL),CR + LD HL,(EndTx) + INC HL + LD (AftCu),HL + LD (HL),CR + RET +; +;Case selection subroutine +; CALL Case +; DB # of entries in list +; DW Default subroutine if no match +; DB value1 +; DW subroutine1.... +; +; +Case: POP HL + LD B,(HL) ;entries + INC HL + LD E,(HL) ;DE=default sbr + INC HL + LD D,(HL) + INC HL +Lp1Ca: CP (HL) ;Value matches? + INC HL + JR NZ,Sk2Ca + LD E,(HL) ;yes, get address + INC HL + LD D,(HL) + JR Sk3Ca ;finish up +; +Sk2Ca: INC HL ;No match, skip ahead +Sk3Ca: INC HL + DJNZ Lp1Ca ;Try again + EX DE,HL ;Swap sbr and return + PUSH DE ;Store return (end of list) + JP (HL) ;Go do sbr (LAST match) +; +; +XCase: CALL UCase ;force A to ctl-codes + CP '@' + RET C + CP '_'+1 + RET NC + AND 1FH + RET +UXCase: CP ESC ;uppercase A if letter OR ctl-code + JR NC,UCase + ADD A,40H + RET +UCase: CP 'a' + RET C ;uppercase A if letter + CP 'z'+1 + RET NC + AND 5FH + RET +; +; +Wait: LD A,(MacFlg) ;Macro Pause function + OR A + JP Z,Error2 + LD A,3 ;Wait about 3/2 sec + JR Dly0 +; +Delay: LD B,A ;Delay about A/2 sec + LD A,(MacFlg) ;but NOT if Macro going + OR A + RET NZ + LD A,B +Dly0: ADD A,A + ADD A,A +Dly1: PUSH AF + CALL BDly + POP AF + DEC A + JR NZ,Dly1 + RET +BDly: LD A,(MHz) + LD B,A + LD C,0 +BDlyLp: DEC BC + LD A,B + OR C + JR NZ,BDlyLp + RET +; +; +; UR-ROUTINES +; +Fill: LD (DE),A ;fill B bytes at DE with A + INC DE + DJNZ Fill + RET +; +GpCnt: LD BC,(BefCu) ;Count cursor gap size + LD HL,(AftCu) + DEC HL + DEC HL +SubDP: PUSH HL ;Double precision subtract + OR A ;BC = HL - BC + 1 + SBC HL,BC + LD B,H + LD C,L + INC BC + POP HL + RET +; +BgCnt: LD HL,(BegTx) ;Count bytes before cursor +LCnt: LD B,H + LD C,L + PUSH HL + LD HL,(BefCu) + CALL SubDP + POP HL + RET +NdCnt: LD HL,(EndTx) ;Count bytes after cursor +RCnt: LD BC,(AftCu) + JR SubDP +; +;Move bytes across cursor gap so the gap moves left. +;HL points to what will become BefCu. +; +MoveL: CALL LCnt ;bytes to move + RET C + LD DE,(AftCu) + DEC DE + LD HL,(BefCu) + LDDR + LD (BefCu),HL + INC DE + LD (AftCu),DE + RET +; +;MoveR - Moves gap right. HL will become BefCu. +; +MoveR: CALL RCnt + RET C + LD DE,(BefCu) + INC DE + LD HL,(AftCu) + LDIR + LD (AftCu),HL + DEC DE + LD (BefCu),DE + RET +; +;CrLft - Find CRs to left of cursor (up to E) +; +CrLft: CALL BgCnt + JR NC,Sk1Lf + XOR A ;no bytes, return with C and no Z + SUB 1 + RET +Sk1Lf: CALL FetchB + CP CR ;Is cursor on a CR + JR NZ,Sk2Lf + LD A,1 + CP E + JR NZ,Sk2Lf + SCF ;Asked for 1, and already there: ret C and Z + RET +Sk2Lf: LD A,CR +Lp3Lf: CPDR ;find a CR + JP PO,Sk4Lf ;count exhausted? + DEC E + JR NZ,Lp3Lf ;Do more? + INC HL ;Back up to before CR + INC HL + XOR A ;Found AOK, ret Z and no C + RET +Sk4Lf: INC HL ;Back to first byte + SCF + CCF ;Clear C + JR Z,Sk5Lf ;Was first byte CR + DEC E ;No, reduce count + RET +Sk5Lf: INC HL ;Back after CR + DEC E ;the one we wanted? + RET Z + DEC HL ;No, back in front of it + DEC E + RET +; +;CrRit - same, to right. +; +CrRit: CALL NdCnt + JR NC,Sk1Ri + XOR A + SUB 1 ;no bytes, return C and no Z + RET +Sk1Ri: LD D,E + LD A,CR + LD HL,(AftCu) +Lp2Ri: CPIR + JP PO,Sk3Ri + DEC E + JR NZ,Lp2Ri + SCF + CCF ;found AOK, ret Z and no C + RET +Sk3Ri: LD A,D + CP E + JR NZ,Sk4Ri + SCF ;none found, return C and Z + RET +Sk4Ri: LD HL,(EndTx) + DEC HL + LD A,CR + LD BC,0FFFFh + CPDR + INC HL + INC HL + OR 1 ;some but not enough, ret no C and no Z + RET +; +;cursor positioning subroutines +; +TopV: LD A,1 + JR LoadV +MidV: LD A,(TxtLns) + SRL A + JR LoadV +DecV: EXX + LD HL,(CurLin) + DEC HL + LD (CurLin),HL + EXX +DecVO: LD A,(Vert) ;returns Z if cannot Dec + CP 1 + JR Z,LoadV + DEC A + JR LoadV +IncV: EXX + LD HL,(CurLin) + INC HL + LD (CurLin),HL + EXX +IncVO: LD A,(Vert) ;returns Z if cannot Inc + EXX + LD HL,TxtLns + CP (HL) + EXX + JR Z,LoadV + INC A + JR LoadV +BotV: LD A,(TxtLns) +LoadV: LD (Vert),A + RET +LftH: LD A,1 + JR LoadH +LTabH: LD A,(Horiz) + DEC A + JR Z,RitH + CALL WhatC ;ouch, got to calculate + LD HL,NSkip ;Horiz = CurCol-NSkip + SUB (HL) + JR C,RitH + JR LoadH +DecH: LD A,(Horiz) + DEC A + RET Z + JR LoadH +TabH: LD A,(Horiz) + DEC A + EXX + LD HL,TabCnt + OR (HL) + EXX + INC A + JR IncT +IncH: LD A,(Horiz) +IncT: EXX + LD HL,View + CP (HL) + EXX + RET NC + INC A + JR LoadH +RitH: LD A,(View) +LoadH: EX AF,AF' ;### + LD A,(CurCol) ;### + INC A ;### + JR NZ,LoadH2 ;### + EX AF,AF' ;### + RET ;### +LoadH2: EX AF,AF' ;### + LD (Horiz),A + RET +; +; +;Get next text character from memory +;(HL and C keep track across repeated calls) +; +GetNx: XOR A + CP C ;Have we a hidden space? + JR NZ,Sk1Gt + LD A,(HL) ;No, get next byte + INC HL + CP 80H ;Does it have hidden space? + JR NC,Sk2Gt ;Yes, note and remove + CP CR + RET +Sk1Gt: DEC C ;Fetch hidden space + LD A,' ' + CP CR ;Set Z flag if CR + RET +Sk2Gt: AND 7FH + INC C + CP CR ;Set Z flag if CR + RET +; +;Hide any hideable spaces. (NEW ALGORITHM) +; +Cmprs: CALL BgCnt ;bytes to left + JR C,Sk2Cm ;none? + LD D,H + LD E,L + DEC DE +Lp1Cm: LD A,(HL) ;Get a byte + CP ' ' ;Nonspace? fine + JR NZ,Sk1Cm + LD A,(DE) ;Last byte CTL? fine + CP 20H + LD A,' ' + JR C,Sk1Cm + LD A,(DE) ;Hidden space already? fine + BIT 7,A + LD A,' ' + JR NZ,Sk1Cm + LD A,(DE) + OR 80h ;Got to hide the space. + DEC DE +Sk1Cm: INC DE ;Store byte + LD (DE),A + INC HL ;Bump input + DEC BC + LD A,B + OR C ;more to do? + JR NZ,Lp1Cm + LD (BefCu),DE ;This is now BefCu +; +Sk2Cm: CALL NdCnt ;How many after cursor? + RET C + LD HL,(EndTx) ;work back from end + LD D,H + LD E,L + INC DE +Lp3Cm: LD A,(DE) + CP ' ' ;Last byte space? + JR NZ,Sk3Cm + LD A,1FH ;This byte CTL? + CP (HL) + JR NC,Sk3Cm + BIT 7,(HL) ;This byte already hiding? + JR NZ,Sk3Cm + SET 7,(HL) ;Got to hide that space + INC DE +Sk3Cm: DEC DE + LDD ;Store byte, Bump input + INC DE + JP PE,Lp3Cm ;more to do? + LD (AftCu),DE ;This is now AftCu + RET +; +;Set BC to gap size (make room if needed, or set EdErr) +; +Space: LD L,A ;Save A + PUSH HL + CALL GpCnt ;Count gap size + CALL C,Cmprs ;No room? Hide spaces + CALL GpCnt ;Room now? + CALL C,Error1 ;out of memory + POP HL + LD A,L + RET +; +InsSpc: LD A,' ' +; +;Put ordinary byte in A into text at cursor. +; +Insrt: CALL Space ;Insert Before cursor + RET C + CP EOF + JR Z,Insrt1 + LD HL,BlkChr + CP (HL) + JR Z,Insrt1 + LD HL,Modify + LD (HL),0FFh +Insrt1: LD HL,(BefCu) ;Bump pointer + INC HL + LD (HL),A ;Store byte + LD (BefCu),HL + OR A ;Clear flags + RET +InsrtA: CALL Space ;same, but After cursor + RET C + LD HL,Modify + LD (HL),0FFh +InsrA1: LD HL,(AftCu) + DEC HL + LD (HL),A + LD (AftCu),HL + OR A + RET +; +;Compute absolute line number +; +CountS: LD HL,1 ;Hard way: from start + LD (CurLin),HL + CALL BgCnt + JR Sk0CL +CountL: LD HL,(LastCu) ;same but faster, using LastCu + INC HL + CALL LCnt +Sk0CL: RET C ;(At start, or have not moved) + LD DE,0 + LD A,CR + LD HL,(BefCu) +Lp1CL: CPDR + JR NZ,Sk1CL + INC DE + JP PE,Lp1CL +Sk1CL: LD HL,(CurLin) + ADD HL,DE + LD (CurLin),HL + RET +CountR: LD HL,(LastCu) ;same, but for backward move + DEC HL + CALL RCnt + RET C ;(have not moved) + LD DE,0 + LD A,CR + LD HL,(AftCu) +Lp1CR: CPIR + JR NZ,Sk1CR ;(have not moved) + INC DE + JP PE,Lp1CR +Sk1CR: LD HL,(CurLin) + OR A + SBC HL,DE + LD (CurLin),HL + RET +; +; +;MACRO functions +; +MacKey: LD HL,KeyQ + CALL Prompt + CALL RptKey ;which key? + CALL UCase + LD (MKsav),A + CP 'N' ;no-rpt request? + JR Z,MK0 + CP 'Q' ;no-rpt & macro request? + JR NZ,MK00 +MK0: CALL Echo ;show N or Q, get next + CALL RptKey +MK00: SUB '0' + JP C,Error7 + CP 10 + JP NC,Error7 + LD D,A ;save key + LD A,0FFH + LD HL,MacStr + LD BC,StrSiz+1 ;find end + CPIR + LD A,StrSiz + SUB C ;figure length + LD E,A ;save it + LD HL,Keys+2 + LD A,D + OR A + JR Z,MKlp1F +MKlp1: LD C,(HL) + LD B,0 ;find key in list + ADD HL,BC + INC HL + DEC A + JR NZ,MKlp1 +MKlp1F: LD A,(HL) ;old length + OR A + JR Z,MK1 + PUSH DE + PUSH HL ;delete old one + LD E,(HL) + LD D,0 + LD (HL),0 + INC HL + EX DE,HL + ADD HL,DE + LD B,H + LD C,L + PUSH HL + LD HL,Keys+200H + OR A + SBC HL,BC ;bytes to move + LD B,H + LD C,L + POP HL + LDIR + CALL VerKey + POP HL + POP DE +MK1: LD A,E ;anything to add? + OR A + JR Z,MKDone + LD A,(Keys+1) ;will it fit + OR A + JR NZ,MK1a + LD A,(Keys) + SUB E + JP C,Error1 ;out of memory +MK1a: LD (HL),E ;yes + INC HL + LD C,E + LD B,0 + PUSH HL + LD HL,Keys+200H-1 + LD D,H + LD E,L + OR A + SBC HL,BC ;from here + POP BC + PUSH HL + SBC HL,BC ;bytes to move + LD B,H + LD C,L + INC BC ;inclusive + POP HL + LDDR ;make room + LD C,(HL) + LD B,0 + INC HL + EX DE,HL + LD HL,MacStr + PUSH DE + LDIR ;insert new one + POP HL + LD A,(MKsav) + CP 'N' ;take care of N/Q request + JR Z,MK2 + CP 'Q' + JR NZ,MKDone + DEC HL + LD A,(HL) ;Q only works if length >1 + CP 2 + INC HL + JR C,MK2 + INC HL + SET 7,(HL) ;indicate quiet + DEC HL +MK2: SET 7,(HL) ;indicate no-rpt +MKDone: CALL VerKey + JP ShoLn1 +; +; +VerKey: LD B,10 ;verify key area + LD HL,200H-12 + LD D,0 + LD IX,Keys+2 +VKlp: LD A,StrSiz ;check size + CP (IX) + JR C,VKwipe + LD E,(IX) + SBC HL,DE ;decrement + JR C,VKwipe + ADD IX,DE ;move to next + INC IX + DJNZ VKlp + LD (Keys),HL ;free bytes + LD A,H + OR L + RET Z ;full? +VKlp2: LD (IX),0 + INC IX ;zero fill + DEC HL + LD A,H + OR L + JR NZ,VKlp2 + RET +VKwipe: LD HL,200H-12 ;oops, bad + LD (Keys),HL + LD IX,Keys+2 + LD HL,200H-2 + JR VKlp2 +; +ChainK: LD HL,MacFlg ;chain to new macro + BIT 0,(HL) ;(used only if macro going) + RET Z + CALL RstI1x ;reset INS to saved state + CALL RptKey ;get key # + CP '0' + JP C,Error8 + CP '9'+1 + JP NC,Error8 + PUSH AF + CALL Loud + XOR A + LD (MacFlg),A + POP AF + JR UK0 +; +UseKey: LD HL,MacFlg ;macro going already? + BIT 0,(HL) + RET NZ ;YES, this is just a label +UK0: SUB '0' ;NO, retrieve key 0-9 + LD B,A + LD HL,Keys+2 + JR Z,UKlp1F +UKlp1: LD E,(HL) + LD D,0 ;find it + ADD HL,DE + INC HL + DJNZ UKlp1 +UKlp1F: LD A,(HL) ;length + INC HL + OR A + JP Z,Error7 ;none? + LD C,A + LD B,0 + PUSH BC ;on stack for Mac00 entry + LD DE,DMA + PUSH DE + LDIR ;fetch it in + POP HL ;point to it + BIT 7,(HL) + RES 7,(HL) + JR Z,Mac00 ;not no-rpt? go ask, etc. + INC HL + BIT 7,(HL) + RES 7,(HL) + CALL NZ,Quiet ;quiet? + LD A,'1' + JR Mac0 ;go do just once +; +DoMac: LD HL,MacroQ ;get Macro defn + CALL Prompt + CALL GetStr + DW MacStr ;### + OR A + JR Z,MacDel ;none? delete + LD C,A ;save count + LD B,0 + PUSH BC +Mac00: LD HL,RptcQ ;(entry for normal Key) + CALL Prompt + CALL RptKey + CALL UCase + CP 'Q' + JR NZ,Mac0 + CALL Echo + CALL Quiet ;Q? do quiet, get rpt cnt + CALL RptKey +Mac0: POP BC ;string cnt (entry for no-rpt Key) + PUSH AF ;save rpt cnt + LD A,C + OR A ;null string? + JR Z,Mac1 + LD HL,DMA ;move in string + LD DE,MacStr + LDIR + EX DE,HL + LD (HL),0FFh ;terminator +Mac1: CALL ShoLn1 + POP AF + LD B,255 + CP '*' ;figure rpt cnt + JR Z,Mac2 ;(* is maximal) + LD B,0 ;(0 is default) + SUB '0' + JR C,Mac2 + CP 9+1 + JR NC,Mac2 + LD B,A +Mac2: LD A,B ;set rpt cnt + LD (RptCnt),A + OR A + JP Z,Loud ;oops, rpt=0 +Mac3: LD HL,MacStr ;Point to it + LD (CmdPtr),HL + LD A,0FFH ;Okay, here goes + LD (MacFlg),A + LD HL,InsFlg ;save INSERT toggle + LD A,(HL) + LD (SavIns),A ;turn INSERT off if on + BIT 7,(HL) + CALL NZ,ToggHL + RET +MacDel: LD A,0FFH + LD (MacStr),A + JP ShoLn1 +; +;"Macro Programming Language" +; +MacJmp: LD A,(MacFlg) ;jump to a label + OR A + JP Z,Error8 ;macro must be going + LD (JmpFlg),A ;say Jump in progress + CALL RptKey + LD HL,JmpFlg + LD (HL),0 + CP '[' ;TOF/EOF? + JR Z,MJtop + CP ']' + JR Z,MJend + CP '>' ;move/loops? + JR Z,MJRt + CP '<' + JR Z,MJLf + LD E,A ;key to find + LD HL,MacStr + LD B,StrSiz +MJlp: LD A,(HL) ;search along + INC HL + CP 0FFH + JP Z,Error8 + CP ESC + JR Z,MJlp01 + DJNZ MJlp + JP Error8 +MJlp01: LD A,E ;found ESC... right one? + CP (HL) + JR NZ,MJlp + INC HL ;yep + LD (CmdPtr),HL + RET +; +MJtop: LD HL,MacStr ;redo it from the top + LD (CmdPtr),HL + RET +MJend: XOR A ;quit + LD (MacFlg),A + LD E,A + CALL RstI1x + JP Loud +MJRt: CALL NdCnt ;right/left jump loops + JP C,Error7 ;stop at EOF + CALL Right + JR MJredo +MJLf: CALL BgCnt + JP C,Error7 + CALL Left +MJredo: LD HL,(CmdPtr) + DEC HL ;back up to the ESC to repeat + DEC HL + DEC HL + DEC HL + LD (CmdPtr),HL + RET +; +MacTst: LD A,0CAH ;(JP Z) + JR MacT1 +MacTsX: LD A,0C2H ;(JP NZ) +MacT1: LD (MacT),A + LD A,(MacFlg) + OR A ;macro must be going + JP Z,Error8 + CALL RptKey ;get char to match + LD E,A + CALL Fetch ;char at cursor + CP E +MacT: JP Z,MacJmp ;yes? jump <--- can be JP NZ too + JP RptKey ;no, just eat label +; +;Get the next key stroke (check Macro first.) +; +TRptKy: XOR A ;enable redisp Timer + JR RK0 +RptKey: LD A,0FFH +RK0: LD (KeyFlg),A + LD A,(MacFlg) + OR A ;macro waiting? + JP Z,KeyIn ;no. +MacIn: CALL Keybd ;YES, check keyboard for abort + CP ESC + JR NZ,MacIn1 + LD HL,(CmdPtr) ;abort, make this last char + LD E,(HL) + LD HL,MacFF+1 ;### + LD (CmdPtr),HL ;### + JR MacIn3 +MacIn1: LD HL,(CmdPtr) ;OK, take waiting char + LD A,(HL) + INC HL ;bump pointer + LD (CmdPtr),HL +MacFF: CP 0FFH ;### + JR Z,MacFFx ;### + LD E,A ;### + LD A,(HL) ;end of macro now? (FF) + INC A + JR NZ,MacIn2 ;NO, return char + LD A,(JmpFlg) ;jump in progress? + OR A + JR NZ,MacIn2 + LD HL,RptCnt ;need to repeat? + LD A,(HL) + INC A + JR Z,McIn1a + DEC (HL) + JR Z,MacIn3 +McIn1a: LD HL,MacStr ;repeat: reset pointer + LD (CmdPtr),HL + JR MacIn2 +MacIn3: CALL Loud +MacIn2: LD A,E + AND 7FH ;strip parity, return char + RET +MacFFx: XOR A ;NO, stop macro execution + LD (MacFlg),A + CALL RstI1x ;restore saved INS state + JP KeyIn +; +; +;Unconditional Q/L for Macros +; +Quiet: LD HL,ShutUp + LD (HL),0C9H ;(RET) + RET +Loud: LD HL,ShutUp + XOR A ;(NOP) + CP (HL) + RET Z + LD (HL),A + JP HoldSc ;gotta see... +; +RstI1x: LD A,(SavIns) + LD HL,InsFlg + CP (HL) + CALL NZ,ToggHL ;switch INS to match the saved state + RET +; +;Conditional Q/L for formatting etc. +; +; +XQuiet: LD HL,ShutUp + LD A,(HL) + LD (HL),0C9H ;(RET) + LD (SavQ),A + RET +XLoud: LD A,(SavQ) + OR A ;(NOP) + RET NZ + LD (ShutUp),A + RET ;do NOT need redisp here +; +;Force loud for header display +; +Force: LD HL,ShutUp + LD A,(HL) + LD (HL),00H ;(NOP) + LD (SavQ2),A + RET +UForce: LD A,(SavQ2) + CP 0C9H ;(RET) + RET NZ + LD (ShutUp),A + RET +; +; +; VDE EDITING FUNCTIONS +; +; +;Show information +; +Info: CALL MakAlt ;show this first for entertainment + CALL UndrHd + CALL Dspl + DB X,26,0 + LD HL,VersID + CALL DspLp + CALL Cmprs ;pack spaces + CALL GpCnt ;count gap size + PUSH BC + LD H,B + LD L,C + LD DE,FreNNN ;show it as "free space" + CALL BCDCon + LD HL,(EndTx) + INC HL + LD DE,(BegTx) + OR A + SBC HL,DE + POP BC + SBC HL,BC ;memory used + LD DE,UsdNNN + CALL BCDCon ;show it as "used" + LD HL,(BegTx) + LD DE,(BefCu) + CALL FSzSbr ;figure actual disk file size + PUSH BC + LD HL,(AftCu) + LD DE,(EndTx) + CALL FSzSbr + POP HL + ADD HL,BC + LD DE,SizNNN ;show it as "file size" + CALL BCDCon + LD A,(Modify) + OR A ;file changed? + LD A,'Y' + JR NZ,Info2 + LD A,'N' +Info2: LD (ModQQQ),A + LD HL,InfMsg ;now display the data + CALL DspLp + CALL UnAlt + CALL ESCLp + JP SetAl +; +FSzSbr: LD BC,0 ;count a block +FSzLp: LD A,E ;done? + SUB L + LD A,D + SBC A,H + RET C + LD A,(HL) + INC HL + INC BC ;count character + CP CR + JR Z,FSz1 ;and (missing) LF? + CP X + JR C,FSzLp ;and (hidden) space? +FSz1: INC BC + JR FSzLp +; +; +; Blank the screen +; +Blank: LD A,(WinFlg) ;window off first (will lose text) + OR A + CALL NZ,Window + LD HL,CsrOff ;### + CALL CtlStr ;### + LD HL,TInit + CALL CtlStr + CALL ESCLp + CALL DoHdr + JP SetAl +; +; +;Move cursor to the beginning of text +; +Top: LD HL,(BegTx) + CALL MoveL ;Move + CALL TopV ;Adjust cursor + CALL LftH + LD HL,1 + LD (CurLin),HL + JP SetAl +; +; +;Move cursor to the last character of text +; +Bottom: LD HL,(BefCu) ;for CountL + LD (LastCu),HL + LD HL,(EndTx) + CALL MoveR ;Move + CALL BotV ;Adjust cursor + CALL RitH + CALL CountL + JP SetAl +; +; +; Queue: move to next line in ZCPR queue +; +Queue: LD BC,Z3MSG + CALL Z3EAdr + JP Z,Error7 ; no Z3 message buffers + LD D,B ; addr of Z3MSG to DE + LD E,C + LD HL,RegNum+1 ; current register addr + LD A,(HL) + CP MsgUsr-2+MsgNmU ; time to wrap around? + JR NZ,QueNxt +QueWrp: LD A,MsgUsr-2 ; yes + LD (HL),A ; update it +QueNxt: INC (HL) ; next register + INC (HL) +RegNum: LD HL,MsgUsr-2 + ADD HL,DE ; point to next line # + LD C,(HL) + INC HL + LD B,(HL) ; line # to BC + LD A,B + OR C + JP NZ,ZipTo2 ; go to it + LD HL,RegNum+1 ; is first register empty? + LD A,(HL) + CP MsgUsr + JP Z,Error7 ; yes, error + JR QueWrp ; no, wrap around +; +; +;QUICK cursor movements +; +QuikMk: CALL NdCnt ;look for next place marker + JR C,QkMk1 + LD HL,(AftCu) + LD A,EOF ;marker + CPIR + JP Z,QikB1 ;found? rest same as ^QB +QkMk1: CALL BgCnt ;not? try from top + JR C,QkMk2 + LD HL,(BegTx) + LD A,EOF + CPIR + JP Z,QikB0 ;found? rest same as ^QB +QkMk2: JP Error7 ;not? error. +; +QuikLf: LD E,1 ;move left to start of line + CALL CrLft + RET C + LD A,1 + LD (CurCol),A ;(useful for format subroutines) + CALL MoveL + CALL LftH + JP IfScl +; +QuikRt: CALL NdCnt ;move right to end of line + JP C,ColCnt + CALL Fetch + JP Z,ColCnt + CALL Right + RET C + JR QuikRt +; +QuikUp: LD A,(Vert) ;move up to top of screen + DEC A + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QUlp: PUSH BC + CALL Up + POP BC + DJNZ QUlp + CALL SetNo + POP AF ;restore col + JP SkQUD +; +QuikDn: LD A,(TxtLns) ;move down to end of screen + LD HL,Vert + SUB (HL) + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QDlp: PUSH BC + CALL Down + POP BC + DJNZ QDlp + CALL SetNo + POP AF + JP SkQUD +; +ZipTo: LD HL,PageQ ;zip to given page + LD A,(PgLen) + OR A + JR Z,ZipTo0 + LD A,(FMode) + CP 'N' + JR NZ,ZipTo1 +ZipTo0: LD HL,LineQ ;or line, in N mode +ZipTo1: CALL Prompt + LD BC,1 + CALL GetNbr + JP C,Error7 + JP Z,Error7 + LD A,(FMode) + CP 'N' + JR Z,ZipTo2 + LD A,(PgLen) ;(calculate line) + OR A + JR Z,ZipTo2 + LD D,0 + LD E,A + LD L,D + LD H,D + DEC BC +ZipMul: LD A,B + OR C + JR Z,ZipMF + ADD HL,DE + DEC BC + JR ZipMul +ZipMF: INC HL +ZipMF2: LD B,H + LD C,L +ZipTo2: PUSH BC + CALL Top + POP DE ;desired line + LD A,D + OR E + JR Z,ZipXit + DEC DE ;lines to move down + XOR A + OR D + JR Z,ZipLpF +ZipLp: PUSH DE ;do multiples of 256 + LD E,0 ;(256) + CALL CrRit + DEC HL + CALL MoveR + POP DE + DEC D + JR NZ,ZipLp +ZipLpF: XOR A + OR E + JR Z,ZipTo3 + CALL CrRit ;do remainder + DEC HL + CALL MoveR +ZipTo3: CALL MidV + CALL RitH + CALL CountS +ZipXit: JP SetAl +; +; +;Move cursor up. +; +Up: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,2 ;start of last line + CALL CrLft + RET NZ ;TOF? quit + PUSH HL + CALL EdgeU + CALL DecV + POP HL + CALL MoveL +SkUpDn: LD A,(CurCol) ;where we were +SkQUD: CALL GoCol + RET Z ;exact? + JP IfScl ;may need to scroll +; +; +;Move cursor down. +; +Down: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,1 ;start of next line + CALL CrRit + DEC HL + JR NC,Sk1Dn ;was there one? + RET NZ ;EOF? quit + LD HL,(EndTx) + LD A,(HL) ;Get that last byte + CP CR + RET NZ ;no next line +Sk1Dn: PUSH HL + CALL EdgeD + CALL IncV + POP HL + CALL MoveR + JR SkUpDn +; +QuikLc: LD HL,(SavLin) + CALL ZipMF2 + LD A,(SavCol) +; +; +GoCol: DEC A ;restore cursor to column A + RET Z + LD HL,(HorFlg) ;don't change show status + PUSH HL + PUSH AF + CALL ColCnt ;where are we? + LD IY,CurCol + JR GRCent +GRCLp: CALL NdCnt + JR C,GRCF ;stop at EOF + CALL Fetch + JR Z,GRCF ;stop at CR + CP TAB ;tabs are special + JR NZ,GRC1 + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A +GRC1: INC (IY) ;Keep CurCol updated + CALL Right +GRCent: POP AF + PUSH AF + CP (IY) ;there yet? + JR NC,GRCLp +GRCF: POP AF + POP HL + LD (HorFlg),HL + INC A + SUB (IY) ;set Z if exact + RET +; +; +;Move cursor one to the left (C=cannot) +; +Left: CALL Space ;Any space left? + RET C + CALL BgCnt ;Are we at front? + RET C + CALL EdgeL + LD HL,(BefCu) ;Look back + LD A,(HL) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1Lt ;No, just move + RES 7,(HL) ;Yes, unhide it + LD A,' ' + INC HL +Sk1Lt: DEC HL ;Back up + LD (BefCu),HL + CALL InsrA1 ;store byte ahead + CP TAB ;Was a TAB moved + JR Z,LftTab + CP CR ;Was a CR moved? + JR Z,LftCR + CALL DecH ;no + OR A + RET NZ + JP IfScl ;at left mgn...scroll? +; +LftCR: CALL RitH ;special cases - scrolling + CALL DecV + CALL ColCnt + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl + OR A + RET +LftTab: LD A,(Horiz) + DEC A + CALL Z,HorScl ;need to scroll if at left + CALL LTabH + OR A + RET +; +; +;Move cursor one to the right +;(return C if can't, char passed in A) +; +Right: CALL Space ;Any room left? + RET C + CALL NdCnt ;Already at end? + RET C + CALL EdgeR + CALL Fetch + JR NZ,Sk0Rt + PUSH HL + CALL TestCu ;change of line: no delays + CALL NZ,ShoCu1 + POP HL +Sk0Rt: LD A,(HL) + BIT 7,A ;Hidden space? + JR Z,Sk1Rt ;No, just move + LD (HL),' ' ;Yes, unhide it + AND 7FH + DEC HL +Sk1Rt: INC HL ;Bump pointer + LD (AftCu),HL + CALL Insrt1 ;put byte in behind + OR A ;and return it + PUSH AF + CP TAB ;TAB and CR are special + JR Z,RtTab + CP CR + JR Z,RtCR + CALL IncH ;no, just move + POP AF + RET +; +RtCR: CALL IfScl ;may have to scroll + CALL IncV ;adjust + CALL LftH + LD A,1 + LD (CurCol),A + POP AF + RET +; +RtTab: LD A,(View) + DEC A + LD HL,TabCnt + SUB (HL) + LD HL,Horiz + SUB (HL) + CALL C,HorScl ;at right, need to scroll + CALL TabH + POP AF + RET +; +; +;Word tab, delete +; +WdMxCh EQU 255 ;max chars to loop +; +WordRt: CALL Fetch ;Word tab right + JP Z,Right ;at EOL? special case + CALL IsBlnk ;on break? just find nonbreak + JR Z,WRlpF + LD B,WdMxCh +WRlp: CALL WRfBrk + JR Z,WRlpF + CP CR ;quit at CR + RET Z + DJNZ WRlp +WRlpF: LD B,WdMxCh +WRlp2: CALL WRfBrk + RET NZ + DJNZ WRlp2 + RET +WRfBrk: PUSH BC + CALL Right + JR C,WRfBrX + CALL IsBlnk ;then nonbreak + CALL NZ,IsPunc + PUSH BC +WRfBrX: POP BC + POP BC + RET +; +WordLf: CALL FetchB ;Word tab left + CP CR ;at BOL? Special case + JP Z,Left + LD B,WdMxCh +WLlp: CALL IsParB ;find a nonbreak + CALL NZ,IsPunB + JR NZ,WLlpF + CP CR ;quit at CR + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp +WLlpF: CALL Left + LD B,WdMxCh +WLlp2: CALL IsParB ;then a break + CALL NZ,IsPunB + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp2 + RET +; +WordDl: CALL Fetch ;Word Delete + JP Z,EChar ;at BOL? special case + CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNB ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNB: LD B,WdMxCh +WDlp2: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak + CP CR ;but quit at CR + RET Z + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2 + RET +WDlB: LD B,WdMxCh +WDlp: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET Z ;delete till reak + PUSH BC + CALL EChar + POP BC + DJNZ WDlp + RET +; +Join: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNBx ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNBx: LD B,WdMxCh +WDlp2x: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak (including CRs) + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2x + RET +; +IsPaPu: CALL IsPara + CALL NZ,IsPunc + RET +; +; +;Move cursor ahead one page +; +PageF: CALL SetAl + LD A,(TxtLns) + DEC A + LD E,A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgF1 + INC A + LD E,A +PgF1: CALL CrRit ;Point that many CRs down + DEC HL ;Back off one byte + JP C,Bottom + JP NZ,Bottom + LD DE,(BefCu) ;Prepare Count + LD (LastCu),DE + CALL MoveR ;Move cursor gap + CALL CountL + JR LDaGoC ;relocate cursor +; +; +;Move cursor back one page +; +PageB: CALL SetAl + LD A,(TxtLns) + LD E,A + DEC A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgB1 + ADD A,2 + LD E,A +PgB1: CALL CrLft ;Point that many CRs back + JP C,Top + JP NZ,Top + LD DE,(AftCu) ;Prepare Count + LD (LastCu),DE + CALL MoveL ;Move cursor gap + CALL CountR +LDaGoC: LD A,(CurCol) + JP GoCol ;relocate cursor +; +; +;Scroll screen 1/4 vertically +; +ShftD: LD A,(TxtLns) ;Down + SRL A + SRL A + INC A + LD B,A +LDLp: PUSH BC + CALL DecVO + JR NZ,LDLpF + CALL Down ;oops, cursor already on top + CALL DecVO +LDLpF: POP BC + DJNZ LDLp + JP SetAl +; +ShftU: LD A,(TxtLns) ;same, up + SRL A + SRL A + INC A + LD B,A +LULp: PUSH BC + CALL IncVO + JR NZ,LULpF + CALL Up ;oops, cursr already on bottom + CALL IncVO +LULpF: POP BC + DJNZ LULp + JP SetAl +; +Scr1LD: CALL DecVO ;FAST one-line scrolls + JR NZ,ScLD1 + CALL Down ;oops, already on top + CALL DecVO +ScLD1: LD HL,DelL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + LD A,(TxtLns) + LD B,A + JP ShoLn ;re-show last line +; +Scr1LU: LD HL,(CurLin) + LD DE,(Vert) + LD D,0 + OR A + SBC HL,DE + RET Z ;oops, nowhere to go + CALL IncVO + JR NZ,ScLU1 + CALL Up ;oops, already on bottom + CALL IncVO +ScLU1: LD HL,InsL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + JP ShoLn1 +; +;Scroll screen 32 cols horizontally +; +ShftR: LD HL,Horiz ;INcrease screen scroll (right) + LD A,(HL) + SUB 32+1 + RET C + INC A + LD (HL),A + LD HL,NSkip + LD A,(HL) + ADD A,32 + JR ShftX +; +ShftL: LD A,(Horiz) ;DEcrease scroll (left) + ADD A,32 + LD HL,View + CP (HL) + RET NC + LD (Horiz),A + LD HL,NSkip + LD A,(HL) + SUB 32 + RET C +; +;Make current line top +; +ShftX: LD (HL),A + JP SetAl +; +MakTop: CALL TopV ;gee boss, that was easy, huh? + JP SetAl +; +; +;FIND/REPLACE +; +;Find next occurance of a given string. +; +Find: CALL FndSub + JP C,Error7 + CALL ShoLn1 +; + LD A,(FGlobl) + OR A + JR Z,RpFind + LD A,(FBackw) ;global search: backwards? + OR A + JR Z,FndBck + CALL Bottom ;...yes, goto bottom of file + JR RpFind +FndBck: CALL Top ;...no, goto top of file +RpFind: LD A,(FndStr) ;length + OR A + RET Z ;no string, quit + LD A,(FBackw) + OR A ;backward? + JR NZ,RpF5 + CALL NdCnt ;number to scan + JP C,Err4x + LD HL,(EndTx) + LD DE,(FndStr) ;string length + XOR A + LD D,A ;extend to 16 bits + SBC HL,DE +RpSsLp: INC HL + BIT 7,(HL) ;soft space? + JR Z,RpSsNo ;nope + INC A ;count soft spaces? +RpSsNo: DEC E ;decrement string length + JR NZ,RpSsLp + ADC A,C + LD C,A + LD A,B + ADC A,0 + LD B,A + LD HL,FndStr + LD A,C + SUB (HL) + LD C,A ;less string length + LD A,B + SBC A,0 + LD B,A + JR C,Err4x + INC BC ;in case last + LD HL,(BefCu) + LD (LastCu),HL ;Mark position + LD HL,(AftCu) + LD A,(ChgFlg) ;was last operation change? + OR A + JR NZ,RpF1 + INC HL ;NO, start at next byte + DEC BC ;YES, start at this byte +RpF1: LD A,B + OR C + JR Z,Err4x ;gotta have bytes + LD A,(FUCase) + CP 0C3H ;ucase? (groan) + JR Z,SlowFi + LD A,(FndStr) ;only one char? (groan) + DEC A + JR Z,SlowFi + LD DE,(FndStr+1) ;space in char 1 or 2? (groan) + LD A,' ' + CP D + JR Z,SlowFi + CP E + JR Z,SlowFi + JR FastFi +; +Err4x: LD A,(FGlobl) + OR A + JP Z,Error4 ;not found + LD HL,(OldLin) + CALL ZipMF2 + LD A,(OldCol) + CALL GoCol + JP Error5 +; +RpF5: CALL BgCnt ;backward: number to scan + JR C,Err4x ;EOF? + LD HL,(AftCu) + LD (LastCu),HL ;Mark position + LD HL,(BefCu) + JR BackFi +; +FastFi: LD A,B ;find lead char FAST with CPIR + OR C + JR Z,Err4x + LD A,(FndStr+1) + CPIR + JP PE,FstFi1 ;jump if P/V=1 (BC-1 is not 0) + JR NZ,Err4x ;NOT found +FstFi1: PUSH BC + PUSH HL + LD C,0 ;no hidden spaces involved + CALL FndChk ;rest of string? + POP HL + POP BC + JR NZ,FastFi ;no match, keep going + LD C,0 + JP Found +; +SlowFi: LD A,(FndStr+1) ;find lead char the slow way + LD (LdChar+1),A ;(spaces or upcase involved) + LD D,H + LD E,L + ADD HL,BC + EX DE,HL + LD C,0 +Lp1Fi: LD (FindSv),BC ;save hidden space status + CALL GetNx + CALL FUCase +LdChar: CP 0 ;<---- + JR Z,Lp1Fi1 ;got one +Lp1Fi0: LD A,H + XOR D + JR NZ,Lp1Fi + LD A,L + XOR E + JR NZ,Lp1Fi + JR Err4x +Lp1Fi1: PUSH BC + PUSH DE + PUSH HL + CALL FndChk ;rest of string? + POP HL + POP DE + POP BC + JR NZ,Lp1Fi0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR Found +; +BackFi: LD A,(FndStr+1) ;find lead char backwards + LD (LdChr2+1),A + PUSH HL + OR A + SBC HL,BC + PUSH HL + POP DE + POP HL + INC HL + INC HL ;adjust for kludge below + LD C,0 +Lp1BF: LD A,C + LD (FindSv),A ;clear hidden space status + OR A + JR Z,Lp1BFa + DEC C + LD A,' ' + JR Lp1BFb +Lp1BFa: DEC HL ;back up + DEC HL + LD A,(HL) + INC HL ;simulate GetNx in reverse + BIT 7,A + JR Z,Lp1BFb + INC C +Lp1BFb: AND 7Fh + CALL FUCase +LdChr2: CP 0 ;<----- + JR Z,Lp1BF1 ;got one +Lp1BF0: LD A,H + XOR D + JR NZ,Lp1BF + LD A,L + XOR E + JR NZ,Lp1BF + JP Err4x +Lp1BF1: PUSH HL + PUSH DE + PUSH BC + CALL FndChk ;rest of string? + POP BC + POP DE + POP HL + JR NZ,Lp1BF0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR FoundB +; +FndChk: LD A,(FndStr) ;is (HL) a hit? + DEC A + RET Z ;just one char: already matched + LD B,A + LD DE,FndStr+2 ;start at char2 +Lp1FC: CALL GetNx + CALL FUCase + EX DE,HL + CP (HL) + EX DE,HL + JR Z,Sk1FC + LD A,(DE) ;hmm, no match + PUSH HL + LD HL,WildCd ;consider wildcard + CP (HL) + POP HL + RET NZ ;NOPE. +Sk1FC: INC DE ;match, keep on + DJNZ Lp1FC + RET ;YES. +; +; +Found: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back to char1 + DEC HL ;put cursor BEFORE char1 + CALL MoveR + LD HL,(AftCu) ;Hidden space there? + BIT 7,(HL) + JR Z,Found1 + OR A ;need to be on it? + JR Z,Found1 + LD A,(HL) + AND 7FH ;Yep, unhide it + LD (HL),' ' + CALL Insrt1 +Found1: CALL MidV ;Center on screen +Chged0: CALL CountL ;Adjust line number +Chged: CALL RitH ;Adjust cursor + LD HL,ChgFlg + BIT 0,(HL) + JP Z,SetAl ;find? redisplay + LD HL,FndStr + XOR A + ADD A,(HL) + JR Z,Chgd1 + LD C,A ;change: CR involved? + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl ;yes +Chgd1: LD HL,ChgStr + XOR A + ADD A,(HL) + JP Z,SetCu ;no + LD C,A + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl + JP SetCu +; +FoundB: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back before char1 + CALL MoveL ;Move to found string + LD HL,(AftCu) ;hidden space there? + BIT 7,(HL) + JR Z,FounB1 + OR A ;yes, need to be on it? + JR Z,FounB1 + LD A,(HL) ;Yes, unhide it + AND 7Fh + LD (HL),' ' + CALL Insrt1 +FounB1: CALL MidV ;Center on screen + CALL RitH ;Adjust cursor + CALL CountR ;Adjust line number + JP SetAl +; +FndSub: LD HL,FindQ ;Get Find string + CALL Prompt + CALL GetStr ;Put string in 80 + DW FndStr+1 + LD DE,FndStr + LD (DE),A + RET Z ;no string + INC DE + XOR A + LD (ChgFlg),A ;find, not change + LD (FBackw),A ;not (yet) backwards + LD (FGlobl),A ;not (yet) global + LD A,0C3H ;(JP) + LD (FUCase),A ;ignore case + LD HL,DMA + LD A,(HL) + CP '/' + JR NZ,FndSb2 + INC HL +FndSL1: LD A,(HL) + INC HL + OR A + RET Z + CP '/' ;do /options/ + JR Z,FndSb2 + CALL UCase + CP 'C' + JR Z,FOptC + CP 'B' + JR Z,FOptB + CP 'G' + JR Z,FOptG + SCF + RET +FOptC: LD A,0C9H ;(RET) respect case + LD (FUCase),A + JR FndSL1 +FOptB: LD (FBackw),A ;backward + JR FndSL1 +FOptG: LD A,0FFH + LD (FGlobl),A + JR FndSL1 +FndSb2: LD B,0 +FndSL2: LD A,(HL) ;move string in + INC HL + CALL FUCase + OR A + LD (DE),A + JR Z,FndSLF + INC DE + INC B + JR FndSL2 +FndSLF: LD A,B ;count + LD (FndStr),A + RET +; +FUCase: JP UCase ;<--- becomes RET +; +;Change found string [this entry NOT currently in use] +; +;Change: CALL ChgSub ;get string +; +RepChg: LD HL,(BefCu) ;mark position + LD (LastCu),HL + LD A,(FndStr) + OR A + JR Z,RpCh1F ;no string + LD B,A ;count to erase +RpCh1: PUSH BC + CALL EChar + POP BC + JP C,Error7 + DJNZ RpCh1 +RpCh1F: LD HL,ChgStr ;point to string + LD A,(HL) ;count to replace + OR A + JR Z,RpCh3 ;quit if no new string + LD B,A + PUSH BC +RpCh2: INC HL + PUSH BC + PUSH HL + LD A,(HL) + CALL Insrt + POP HL + POP BC + CALL C,Error1 ;out of memory + DJNZ RpCh2 + POP BC + LD A,(FBackw) + OR A +RpCh3: JP Z,Chged0 +RpCh4l: PUSH BC + CALL Left + POP BC + RET C + DJNZ RpCh4l + CALL CountR + JP Chged +; +ChgSub: LD A,0FFH ;say we've done a change + LD (ChgFlg),A + LD HL,ChgQ + CALL Prompt + CALL GetStr ;Put string in 80 + DW ChgStr+1 + PUSH AF + CALL ShoLn1 ;may need this later + POP AF + LD DE,ChgStr + LD (DE),A + RET Z ;do not LDIR with B=0 + INC DE + LD C,A + LD B,0 + LD HL,DMA + LDIR ;Move string in + XOR A + LD (DE),A ;zero terminate it + RET +; +;Global replace +; +Rplace: LD A,0FFH + LD (YNFlg),A + CALL FndSub + JP C,Error7 + LD A,(FndStr) + OR A + JP Z,ShoLn1 ;no string? + LD A,(FGlobl) ;global replace? + OR A + JR Z,RplcGo + LD A,(FBackw) ;backward? + OR A + JR Z,RplTop + CALL Bottom ;goto end + JR RplcGo +RplTop: CALL Top ;goto start +RplcGo: LD A,(MacFlg) + PUSH AF ;(got to do this before Chg Input) + CALL ChgSub + POP AF + OR A + CALL NZ,Global ;within Macro: force Global + CALL RepFCh ;do first one + JR C,RplLpQ ;none found? +RplLp: CALL Keybd + CP ESC ;abort? + JR Z,RplLpX + XOR A + LD (FGlobl),A ;turn off global + CALL RepFCh + JR NC,RplLp +RplLpX: LD A,(EdErr) + CP 4 ;suppress "not found" error + CALL Z,Error0 +RplLpQ: CALL XLoud ;turn CONOut back on + JP SetAl +; +;Repeat last find/replace +; +Repeat: LD A,0FFH + LD (YNFlg),A + CALL RepFCh + LD A,(YNFlg) + OR A + JR Z,RplLp + RET +; +RepFCh: CALL RpFind ;[entry from Replace] + LD A,(EdErr) ;return Carry if not found or error + OR A + SCF + RET NZ ;not found + LD A,(ChgFlg) + OR A + RET Z ;find only, all done + CALL ShoAll ;replace, gotta show it + CALL YesNo ;..and ask + JR C,RepFC0 + JR Z,RepFC1 + LD A,(FBackw) ;NC,NZ = No + OR A + LD A,(FndStr) + CALL Z,GoRtA ;skip ahead + OR A + RET +RepFC0: RET NZ ;C,NZ means Esc: abort +RepFC1: CALL RepChg ;Z (C or NC) means Yes + LD A,(EdErr) + CP 1 ;error? set carry + CCF + RET +; +YesNo: LD A,(YNFlg) ;return C=abort, Z=yes + OR A + SCF + RET Z ;"*" mode? Z,C = yes,global + CALL Loud ;MUST see this +YesNo1: LD DE,DspEsc ;entry for hyphenation Y/N + CALL GoTo + CALL MakAlt + LD HL,YNMsg ;say "Y/N/*" + LD B,4 + CALL BHLMsg + CALL UnAlt + CALL Cursr + CALL KeyIn ;MUST come from keyboard + PUSH AF + LD DE,DspEsc ;clean up + CALL GoTo + LD A,(NoHdrF) + OR A + CALL Z,MakAlt + LD B,4 + CALL BBlank + CALL UnAlt + POP AF + CP ESC ;abort? + JR NZ,YN1 + OR A + SCF ;C, NZ = yes + RET +YN1: CP '*' + JR NZ,YN2 +Global: CALL XQuiet + XOR A + LD (YNFlg),A ;set global flag + SCF + RET ;Z,C = yes,globally +YN2: AND 5FH ; upper case + CP 'Y' + RET Z ;Z,NC = yes,once + CP 'N' + JR NZ,YesNo1 + OR A + RET ;NZ,NC = no +; +; +;Variable Tabs. +;"VTList" is a list of settings, increasing order, zero fill +; +VTTog: LD HL,VTFlg ;toggle variable on/off + CALL ToggHL + CALL RulFix +VTshow: LD A,(VTFlg) ;requires header display + OR A + LD HL,VTon + JR NZ,VTsho1 + LD HL,TogOff +VTsho1: LD DE,DspTab + JP TogSho +; +; +VarTab: CALL ColCnt ;advance to next VT setting + LD B,VTNum + LD HL,VTList +VTlp1: CP (HL) ;find it + JR C,VTb2 + INC HL + DJNZ VTlp1 + RET ;none, no action. +VTb2: LD A,(HL) + PUSH HL + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl ;may need to scroll + POP HL + LD A,(InsFlg) + OR A ;is insert on? + LD A,(HL) ;column to move to + JP Z,MvCol + JP MvColI ;move by inserting spaces +; +TaBack: CALL ColCnt ;retreat to last tab setting + DEC B + RET Z + LD A,(VTFlg) + OR A + JR Z,BThard + LD C,B + XOR A + LD B,VTNum + LD HL,VTList+VTNum-1 +BTlp1: CP (HL) ;skip 0s + JR NZ,BTb1 + DEC HL + DJNZ BTlp1 + RET ;no tabs at all, no action +BTb1: LD A,C +BTlp2: CP (HL) ;find it + JR NC,BTb2 + DEC HL + DJNZ BTlp2 + JP QuikLf ;no more left, go to col 1 +BTb2: LD A,(HL) ;that's it + JR BTabX +BThard: LD A,(TabCnt) ;back to last multiple + CPL + DEC B + AND B + INC A +BTabX: PUSH AF + CALL QuikLf ;go all the way back + POP AF + JP MvCol ;then go there +; +; +VTSet: LD HL,ColQ ;Set tab(s) + CALL Prompt + CALL GetStr + DW 0 + LD A,(CurCol) ;default is Here + JR Z,VTSt01 ;nothing entered? + LD HL,DMA + LD A,(HL) + CP '@' + JR Z,VTSInt ;interval specified? + CP '#' + JR Z,VTSGrp ;group? + EX DE,HL + CALL GetNN ;nope, single tab set + JR Z,VTErr +VTSt01: CALL VTStCl + JR C,VTErr + JR VTStX +VTStCl: LD E,A ;[sbr: set VT here] + LD A,(VTList+VTNum-1) + OR A + SCF + RET NZ ;must be room in list + LD BC,VTNum + LD HL,VTList +VTSlp1: LD A,(HL) ;find it + OR A + JR Z,VTSt1 + CP E + RET Z ;(quit if already set) + JR NC,VTSt2 + INC HL + DEC C + JR NZ,VTSlp1 + DEC HL ;last place +VTSt1: LD (HL),E ;add at end + OR A + RET +VTSt2: LD A,E + LD HL,VTList+VTNum-2 ;make room here + LD DE,VTList+VTNum-1 + DEC BC + LDDR + LD (DE),A ;put it in + OR A + RET +VTErr: JP Error7 +; +VTSInt: LD DE,VTList ;"@" interval specified + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL + INC DE + CALL GetNN + OR A + JR Z,VTStX + LD C,A + INC A ;"@n" means n+1, 2n+1 etc + LD DE,VTList + LD B,VTNum +VTSlp2: LD (DE),A + INC DE + ADD A,C + JR C,VTStX + DJNZ VTSlp2 + JR VTStX +VTSGrp: LD DE,VTList ;'#' group specivied + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL +VTGlp: INC DE + CALL GetNN ;get one from list + OR A + PUSH DE + CALL NZ,VTStCl ;set it? + POP DE + JR C,VTErr + LD A,(DE) + OR A + JR NZ,VTGlp +VTClX: +VTStX: CALL ShoLn1 ;all done + JP RulFix +; +; +VTClr: LD HL,ColQ ;clear a tab + CALL Prompt + LD A,(CurCol) ;default is Here + CALL GetNum + JR C,VTErr + JR Z,VTErr + LD B,VTNum + LD HL,VTList +VTClp1: CP (HL) ;find it + JR Z,VTCl2 + INC HL + DJNZ VTClp1 + JR VTErr ;wasn't set +VTCl2: LD (HL),0 + DEC B + JR Z,VTClX ;was last, all done + LD D,H + LD E,L + INC HL + LD C,B + LD B,0 + LDIR ;delete it + XOR A + LD (DE),A ;zero fill + JR VTClX +; +; +; INSERTION FUNCTIONS +; +;Store a ctl-code in text +; +CtlP: LD HL,CPTog ;say "^P-_", get key + CALL Prefix + CALL XCase + CP DEL + JR Z,CtlP1 + CP ' ' ;error if not now ctl-char + RET Z ;(space cancels) + JP NC,Error2 ;invalid key +CtlP1: LD HL,BlkChr + CP (HL) ;don't allow block char + JP Z,Error2 ;invalid key + CP TAB ;tabs are special + JR Z,ITab + CP CR ;so are CRs + JP Z,ICRB1 + JR Sk2IC +; +IChar: CP ' ' ;Main menu entry: no control codes allowed + RET C +Sk2IC: PUSH AF + CALL ChkLM ;Check for left margin + JR NC,Sk2aIC + CALL UpToLM + CALL SetCu +Sk2aIC: POP AF + LD E,A + CP 7FH ;redo line if DEL/ctl + CCF + JR C,Sk3IC + CP ' ' +Sk3IC: CALL C,SetRCu + PUSH DE + CALL NC,XPutCh ;just show nice chars + POP DE + PUSH DE + LD A,E + CALL Insrt ;Put byte in + POP DE + RET C ;Full? + PUSH DE + LD A,(Horiz) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if at edge + CALL IncH ;Move cursor + CALL ChkIns ;adjust for insert mode + POP DE + LD A,E + CP ' ' + RET Z ;if not space + CP EOF + RET Z + LD HL,BlkChr + CP (HL) + RET Z + JP WdWrap ;check wordwrap +; +TabKey: LD A,(VTFlg) + OR A + JP NZ,VarTab ;maybe variable tabbing +ITab: LD A,TAB + CALL Insrt + RET C + CALL SetCu + CALL ChkIns + LD A,(Horiz) + LD HL,TabCnt + ADD A,(HL) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if needed + JP TabH +; +;Do a carriage return +; +ICR: LD A,(DSFlg) + OR A + CALL NZ,ICR1 +ICR1: LD A,(InsFlg) + BIT 7,A ;Is insert flag on? + JR NZ,ICRB1 + CALL QuikRt ;noo... + LD A,(FMode) + CP 'N' + JR Z,ICR01 +ICR00: CALL FetchB ; in Document: make HCR + CP ' ' + JR NZ,ICR01 + CALL Delete + JR ICR00 +ICR01: CALL Cursr ;may need to show new HCR + CALL NdCnt ;Are we at end? + JR C,ICRB1 ;Yes, add a new line + CALL IfScl ;no, just move cursor + CALL Right + JP ChkAI +ICRB: CALL ICRB1 +ICRB0: LD A,(DSFlg) + OR A + RET Z + CALL InsSpc ;doublespace? add soft CRLF +ICRB1: XOR A + LD (NumTab),A + CALL IfScl + LD A,CR + CALL Insrt ;Put it in + RET C + LD A,(Vert) + LD HL,TxtLns + CP (HL) + CALL Z,ScrlU2 ;end of screen? scroll + CALL SetDn + CALL IncV ;Move cursor down + CALL LftH ;Move to start of line + JR ChkAI +ICRA: CALL ICRA1 + LD A,(DSFlg) + OR A + RET Z + LD A,' ' ;doublespace? add soft CRLF + CALL InsrtA +ICRA1: LD A,CR ;Used as ^N routine only + CALL InsrtA + RET C + CALL FetchB + CP CR + JR NZ,ICRAx + LD HL,InsL + CALL ScrUDx + RET NC +ICRAx: JP SetDn +; +; +;Check for insert mode +; +ChkIns: LD A,(InsFlg) + OR A ;INSERT on? + JP NZ,SetRCu ;Yes, all done + LD HL,(BefCu) + LD A,(HL) + CP EOF + JP Z,SetRCu + LD HL,BlkChr + CP (HL) + JP Z,SetRCu + LD HL,(AftCu) ;No, Look at the character + LD A,CR + CP (HL) ;Is it a CR? + RET Z ;Yes, leave it + LD A,TAB + CP (HL) ;TAB? redo line + CALL Z,SetCu + LD A,(ShoFlg) + PUSH AF + CALL EChar ;overwrite character + POP AF + LD (ShoFlg),A + RET +; +;Check for auto indent mode +; +ChkAI: LD A,(AIFlg) ;AI on? + OR A + RET Z + LD A,(DSFlg) + OR A + RET NZ ;done if doublespacing + CALL NdCnt ;add text at cmd? + JR C,ChkAll + LD A,(InsFlg) ;insert on? + OR A + JR Z,ChkALp +ChkAll: CALL QuikLf ;#inline version of IndPL + CALL BgCnt ;# / + RET C ;# / + CALL Up ;#/ + CALL CntSpc ;get indentation + PUSH BC ;back to this line + CALL QuikRt ;#inline version of IndNL + CALL Right ;#these are just like RfmNL/PL, + POP BC ;#except they DON'T skip over blank lines + LD A,B + CP TAB + LD A,(NumTab) + JR Z,ChkAtb + INC A + JP MvColI ;do it +ChkALp: CALL Fetch ;NO, just move to first nonspace + CP ' ' + JR Z,ChkAI1 + CP TAB + RET NZ +ChkAI1: CALL Right + JR ChkALp +ChkAtb: OR A + RET Z + DEC A + PUSH AF + CALL ITab + POP AF + JR ChkAtb +; +; +; DELETION FUNCTIONS +; +;UNdelete a character +; +Undel: CALL GpCnt ;Anything to undelete? + RET C + CALL ELret2 + LD HL,(AftCu) + DEC HL ;here goes + LD (AftCu),HL + LD A,(HL) + CP CR ;was it a CR? + JP Z,SetDn + JP SetRCu +; +UndlLn: CALL GpCnt ;Do a whole line + RET C + CALL ELret2 + LD A,B + OR A ;max 256 chars + JR Z,UdLn1 + LD BC,256 +UdLn1: LD HL,(AftCu) + DEC HL + DEC HL + LD A,CR + CPDR ;look for CR + RET NZ + INC HL + INC HL ;start of line + LD (AftCu),HL + JP SetDn +; +; +;Erase character to left of cursor (C=error) +; +Delete: CALL Left + RET C ;Fall through to EChar +; +; +;Erase character to right of cursor (C=error) +; +EChar: CALL NdCnt ;Anything to erase? + RET C + CALL ELret2 + CALL SetRCu + LD HL,(AftCu) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1EC + CALL GpShft ;unhide it + LD HL,(AftCu) + LD A,(HL) + LD (HL),' ' + AND 7FH + DEC HL + LD (HL),A + RET +Sk1EC: LD A,(HL) + INC HL ;Move up, past character + LD (AftCu),HL ;Store updated value + CP CR + CALL Z,SetDn ;ate a CR? + OR A + RET +; +GpShft: CALL GpCnt ;Shift gap contents left (for Undel sake) + RET C + DEC BC + LD A,B + OR C + SCF + RET Z + LD HL,(BefCu) + INC HL + LD A,B + SUB 08H ;Maximum 2k worth + JR C,GpS1 + LD B,08H + ADD A,H + LD H,A +GpS1: LD D,H + LD E,L + INC HL + LDIR + OR A + RET +GpCR: CALL GpShft ;mark BOL for ^QU + RET C + LD A,CR + LD (DE),A + RET +; +; +;Line erase functions +; +Eline: LD HL,(AftCu) ;first left end + PUSH HL + CALL QuikLf + POP HL + LD (AftCu),HL + LD E,1 ;now right end + CALL CrRit + JR NC,Eline1 ;found CR? good + JR NZ,Eline2 ;EOF? return + LD HL,(EndTx) ;Cursor is in last line + INC HL +Eline1: LD (AftCu),HL +Eline2: CALL ELret2 + LD HL,DelL + CALL ScrUDx + JP C,SetDn + LD A,(TxtLns) + LD B,A + JP ShoLn +; +EOLine: LD E,1 ;Erase to EOL + CALL CrRit + JR NC,Sk1EO ;Found CR? good + RET NZ ;EOF? return + LD HL,(EndTx) ;cursor is in last line + LD A,(HL) + CP CR ;Is last byte a CR? + INC HL + JR NZ,Sk2EO ;No +Sk1EO: DEC HL ;Point at trailing CR +Sk2EO: PUSH HL + JR EBLret ;delete to there +; +EBLine: LD HL,(AftCu) ;Erase to BOL + PUSH HL + CALL QuikLf +EBLret: CALL GpCR ;delete to there + POP HL + CALL SetRCu +ELret: LD (AftCu),HL +ELret2: LD A,0FFh + LD (Modify),A + RET +; +E2Char: LD HL,CQTTog ;Erase to character + CALL Prefix + CP ESC + RET Z + CP 'U'-40h ;^U? + RET Z + LD (PrevCh),A +E2CLp: CALL EChar ;always eat first char + CALL NdCnt + RET C + CALL Keybd + CP ESC + RET Z + CALL Fetch + LD HL,PrevCh + CP (HL) + JR Z,E2CLpF + LD (PrvCh2),A + JR E2CLp +E2CLpF: CP CR + RET NZ + LD A,(FMode) + CP 'N' + RET Z + LD HL,PrvCh2 ;CR means HARD CR in Doc modes + LD A,(HL) + CP ' ' + RET NZ + LD (HL),CR + JR E2CLp +; +; +; BLOCK FUNCTIONS +; +;MARK Block start and termination +; +Block: CALL UnBlAb ;Remove any markers above + CALL UnBlB1 ;Remove all but last marker below +Blk01: LD A,(BlkChr) ;mark it now + JP Sk2IC +; +Termin: CALL UnBlA1 ;Remove all but first marker above + CALL UnBlBl ;Remove any markers below + JR Blk01 +; +Unmark: CALL UnBlAb ;Remove all block markers + CALL UnBlBl + RET +; +;Move cursor to block start +; +QikBlk: CALL IsBlk + EX DE,HL + INC HL + BIT 0,A + JP Z,Error7 ;must be marked + BIT 6,A + JR NZ,QikB1 +QikB0: CALL MoveL ;before cursor (entries from QuikMk) + JR QikB2 +QikB1: DEC HL ;after cursor + CALL MoveR +QikB2: CALL CountS ;Adjust count + CALL RitH ;Adjust cursor + CALL MidV + JP SetAl +; +;Basic query returns: +; A= {bit 7=gap in block; 6=start after gap; 1=block marked; 0=start marked} +; DE,HL= start, end (if marked) +; +IsBlk: LD IX,IsBVal + LD (IX),0 ;result byte + CALL BgCnt + JR C,IsB1 + LD A,(BlkChr) ;look before cursor + CPIR + JR NZ,IsB1 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + JP PO,IsB0 + CPIR + JR NZ,IsB0 + SET 1,(IX) ;found end + DEC HL +IsB5: LD A,(IX) ;exit + RET +IsB0: SET 7,(IX) ;straddle + JR IsB1a +IsB1: SET 6,(IX) ;block after cursor +IsB1a: CALL NdCnt ;now look after cursor + JR C,IsB5 + LD HL,(AftCu) +IsB3: LD A,(BlkChr) ;search loop + CPIR + JR NZ,IsB5 + BIT 0,(IX) + JR NZ,IsB2 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + LD A,B + OR C + JR Z,IsB5 + JR IsB3 +IsB2: SET 1,(IX) ;found end + DEC HL + JR IsB5 +; +; +UnBlA1: CALL BgCnt ;undo all but 1st marker above + RET C + LD A,(BlkChr) + CPIR + JP PE,UnBA01 ;one? leave and look for more + RET ;no more, finished +UnBlAb: CALL BgCnt ;undo all markers above + RET C +UnBA01: LD A,(BlkChr) + CPIR + RET NZ ;none, finished + CALL SetAl + PUSH BC + PUSH HL + LD D,H + LD E,L + DEC DE + CALL LCnt + JR C,UnBA02 + LDIR ;remove it +UnBA02: DEC DE + LD (BefCu),DE + POP HL + DEC HL + POP BC + LD A,B + OR C + JR NZ,UnBA01 + RET +; +UnBlB1: CALL NdCnt ;undo all but 1st marker below + RET C + LD HL,(EndTx) + LD A,(BlkChr) + CPDR + JP PE,UnBB01 ;one, leave and continue + RET ;none, finished +UnBlBl: CALL NdCnt ;undo all markers below + RET C + LD HL,(EndTx) +UnBB01: LD A,(BlkChr) + CPDR + RET NZ ;none, finished + CALL SetDn + PUSH BC + PUSH HL + LD D,H + LD E,L + INC DE + CALL RCnt + JR C,UnBB02 + LDDR ;remove it +UnBB02: INC DE + LD (AftCu),DE + POP HL + INC HL + POP BC + LD A,B + OR C + JR NZ,UnBB01 + RET +; +;Erase Block +; +EBlock: CALL IsBlk + BIT 1,A ;must be marked + JP Z,Error7 + BIT 7,A + JR NZ,EPrt3 ;straddles cursor? + BIT 6,A ;is it after cursor? + JR NZ,EPrt2 + LD B,H ;no, before cursor + LD C,L + LD HL,(BefCu) + SBC HL,BC ;bytes to move + PUSH HL + LD H,B + LD L,C + POP BC + JR Z,EPrt1a + INC HL + LDIR +EPrt1a: DEC DE + LD (BefCu),DE + JR EPrtRt +EPrt2: EX DE,HL ;it's after cursor + LD BC,(AftCu) + PUSH HL + SBC HL,BC + LD B,H + LD C,L + POP HL + JR Z,EPrt2a + DEC HL + LDDR +EPrt2a: INC DE + LD (AftCu),DE + JR EPrtRt +EPrt3: DEC DE ;cursor straddles it + LD (BefCu),DE + INC HL + LD (AftCu),HL +EPrtRt: CALL RitH ;Adjust cursor + CALL CountS + CALL ELret2 + JP SetAl +; +;Block Copy +; +Copy: CALL IsBlk + AND 82H ;must be marked, not straddled + CP 2 ;(bit 1 set, 7 clear) + JP NZ,Error7 + CALL CmpLng ;compute length + RET Z ;was empty + CALL CpSafe + JR NC,Copy02 ;okay, go do it + CALL Cmprs ;try to get more room + CALL IsBlk + CALL CmpLng ;compute length now + CALL CpSafe ;well? + JP C,Error1 ;REALLY won't fit +Copy02: LDDR + INC DE + LD (AftCu),DE + CALL RitH ;adjust cursor + CALL CountS + CALL ELret2 + JP SetDn +; +CmpLng: DEC HL + INC DE + PUSH HL + INC HL + SBC HL,DE ;compute length now + LD B,H + LD C,L + POP HL + LD DE,(AftCu) + DEC DE + RET +; +CpSafe: PUSH HL ;Set C if BC bigger than gap + PUSH BC + CALL GpCnt + LD H,B + LD L,C + POP BC + SCF ;(just to be safe) + SBC HL,BC + POP HL + RET +; +;Block Move +; +MovBlk: CALL Copy ;first copy + LD A,(EdErr) + OR A + RET NZ + JP EBlock ;then delete +; +; +; DISK FUNCTIONS +; +;View Directory +; +Dir: LD HL,DirQ + CALL Prompt + LD A,8+1 ;ask for Duu: or NDR name (8 chars max) + CALL GSEnt + DW 0 + PUSH AF + LD A,(FCB) ;defaults + LD B,A + LD A,(FCBU) + LD C,A + POP AF + JR Z,Dir00 + LD B,A + LD HL,DMA +DirULp: LD A,(HL) + CALL UCase ;new D (?) + LD (HL),A + INC HL + DJNZ DirULp + CP ':' + JR NZ,Dir0x ;jump if not a ":" + DEC HL + LD (HL),0 +Dir0x: LD DE,DMA + CALL NdrChk + JR NZ,Dir00 ;is an NDR name + LD A,(DE) ;new D (?) + CP '0' + JP C,Error7 ;<'0', not even a user # + CP '9'+1 + JR C,Dir0 ;jump is just a user # + SUB 'A'-1 + CP 17 ;drive letter > 'P'? + JP NC,Error7 ;yep.. a no no + LD B,A + INC DE +Dir0: PUSH BC + CALL GetNN ;new uu + POP BC + JR NC,Dir0a + LD A,(FCBU) ; fetch user # + JR Dir0y +Dir0a: CP 32 ;0-31 ok + JP NC,Error7 +Dir0y: LD C,A +Dir00: PUSH BC + LD E,C + LD C,USRN + CALL BDOSep ;set user + POP BC + LD HL,FCBBuf + LD (HL),B ;and drive + INC HL + LD (HL),'?' ;set up *.* FCB + LD DE,FCBBuf+2 + LD BC,10+1 + LDIR ; wildcard filename, type and extent + LD (HL),0 + LD BC,19 + LDIR ; zero out S1, S2, RC and alloc. map + CALL MakAlt + LD DE,010Fh ;position to col 2 + LD A,(RulFlg) + OR A + JR Z,Dir1 + INC D ;move down a line to preserve the ruler +Dir1: CALL GoTo + LD A,(View) ;initialize + SUB 14 + LD (HPos),A + LD A,(TxtLns) ;lines free on screen + DEC A + LD (DirLns),A + LD A,(View) ;columns free + LD HL,DirCls + LD (HL),A + XOR A + RRD ;cols=view/16 + LD C,(HL) + DEC C + PUSH BC + LD DE,FCBBuf ;first file? + LD C,SRCH + CALL BDOS ; search for first matching file + POP BC + CP 0FFH + JR NZ,Sk1Dir + CALL DsplC + DB 'N','o'+X,'File',CR,0 + JP Sk3Dir +; +Lp3Dir: PUSH BC + LD DE,FCBBuf ;next one... + LD C,SRCN + CALL BDOS ; search for next matching file + POP BC + CP 0FFH + JP Z,DirEnd ;all done? +Sk1Dir: ADD A,A + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;desired FCB is at 32*A + DMA + LD E,A + LD D,0 + LD HL,DMA + ADD HL,DE + INC HL ;point to filename + EX DE,HL + LD HL,9 + ADD HL,DE ;test SYS attribute + BIT 7,(HL) + JR Z,Sk2Dir + LD A,(DirSys) ;yes, include? + OR A + JR Z,Lp3Dir ;no +Sk2Dir: EX DE,HL + PUSH HL + LD B,11 +Lp4Dir: RES 7,(HL) ;strip flags + INC HL + DJNZ Lp4Dir + LD DE,4 + ADD HL,DE + LD (HL),0 ;terminator + DEC HL + LD A,' ' ;separator + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD D,H + LD E,L + DEC HL + LD A,C ;save DirCls + LD BC,3 ;move TYP + LDDR + EX DE,HL + LD (HL),'.' ;punctuate + POP HL + LD C,A ;save DirCls + PUSH BC + CALL DspLp ;SHOW IT + POP BC + DEC C + JR NZ,Lp3Dir ;finish line? + LD HL,DirLns + DEC (HL) + JR Z,DirFul ;out of room? + LD A,CR + CALL DsByt ;okay, new line + LD A,(DirCls) + LD C,A + JR Lp3Dir +; +DirFul: CALL DsplC ;ran out of lines + DB '...',CR,0 + JR Sk3Dir +DirEnd: LD A,C ;done, need CR? + LD HL,DirCls + CP (HL) + JR Z,Sk3Dir + LD A,CR + CALL DsByt +Sk3Dir: CALL UnAlt + CALL IfSpLn + LD A,(FCBU) + LD E,A + LD C,USRN ;reset user + CALL BDOSep + CALL SetAl + JP ESCLp ;wait for ESC to clear +; +;Load a new file. +; +Load: LD A,(Modify) + OR A + JR Z,LoadY + LD HL,QuitQ ;warn if old file was changed + CALL Prompt + CALL Confrm + JP NZ,ShoLn1 +LoadY: JP Restrt ;go do it +; +;Erase a disk file. +; +Era: CALL SavNam ;save old FCB + LD HL,EraQ + CALL NewNam + LD A,(EdErr) + OR A + JR NZ,EraDon + LD (FCBs1),A ;zero S1 + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD C,FDEL + CALL BDOSfc + INC A + CALL Z,Error7 +EraDon: CALL GetNam ;restore FCB + JP ShoLn1 +; +; +;Read text from disk file to cursor location. +; +Read: CALL SavNam ;save old FCB + LD HL,ReadQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,RdDone +; +LoadIt: CALL IOon ;say wait + CALL Cmprs ;need all our room + CALL GpCnt + JR C,Sk1Rd ;No room? + LD HL,(BefCu) ;Start here + CALL MSIn ;Read it in + JR NZ,Sk2Rd ;Worked? +Sk1Rd: CALL Error1 ;no, out of room + JR RdDone +Sk2Rd: JR NC,Sk3Rd ;Okay? + CALL Error3 ;no, I/O error + JR RdDone +Sk3Rd: LD DE,(BefCu) ;Get old BefCu + LD (BefCu),HL ;Set new one + EX DE,HL + INC HL ;Point at first byte loaded + CALL MoveL ;Move the cursor +RdDone: CALL GetNam ;restore FCB + CALL IOoff + CALL ELret2 + JP SetAl +; +; +;Write the whole file out to disk. +; +Save: LD A,(FCB+1) ;must have filename + CP ' ' + JR NZ,Save00 + CALL ChgNam + LD A,(EdErr) + OR A + RET NZ +Save00: LD A,(Modify) + OR A + JR NZ,Save01 + LD HL,UnchgQ ;hey, no changes! + CALL Prompt + CALL Confrm + PUSH AF + CALL ShoLn1 + POP AF + RET NZ +Save01: CALL IOon ;say wait + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL NdCnt ;count number of bytes + JR NC,Save02 + LD BC,0 +Save02: LD HL,(AftCu) ;point at first byte + CALL MSOut ;write it out + JR NC,Save03 + CALL Error3 ;I/O error + JR Save04 +Save03: XOR A + LD (Modify),A ;clean slate +Save04: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + JP IOoff +; +; +;Write block text to a disk file. +; +Write: CALL SavNam ;save orig FCB + LD HL,WritQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,WrXit + CALL IOon ;say wait + LD HL,(AftCu) ;save position + LD (LastCu),HL + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL IsBlk + BIT 1,A ;must be marked + JR Z,WrOops + INC DE ;point to it + SBC HL,DE ;size of block + EX DE,HL + LD B,D + LD C,E + CALL MSOut + JR NC,WrDone +WrOops: CALL Error7 +WrDone: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + CALL IOoff +WrXit: CALL GetNam ;restore orig FCB + JP ShoLn1 +; +; +SavNam: LD HL,FCB ;Preserve main filename + LD DE,FCBBuf + LD BC,12 + LDIR ; copy drive, file name and type + XOR A + LD (FCBd0),A + LD A,(FCBU) ;and user, W/A, FilFlg + LD (DE),A ; set user number in FCBBuf+13 + INC DE + LD A,(FMode) + LD (DE),A ; set S1 + INC DE + LD A,(FilFlg) + LD (DE),A ; set S2 + RET +GetNam: LD HL,FCBBuf ;And restore them + LD DE,FCB + LD BC,12 + LDIR + XOR A + LD (FCBd0),A + LD A,(HL) + LD (FCBU),A + LD E,A + INC HL + LD A,(HL) + LD (FMode),A + INC HL + LD A,(HL) + LD (FilFlg),A + LD C,USRN + JP BDOSep +; +; +;Accept a new file name to be used for disk i/o. +; +ChgNam: CALL SavNam + LD HL,NameQ + CALL NewNam + LD A,(EdErr) + OR A + CALL NZ,GetNam ;bad? restore + CALL DfltM ;may have changed modes + CALL DoHdr + CALL ELret2 + JP ShoLn1 +; +NewNam: CALL Prompt ;subroutine entry + LD A,24+1 + CALL GSEnt ;Ask for input + DW FNamBf + JP Z,Error7 ;Error if no input + LD B,A + PUSH BC + LD HL,DMA ;uppercase it +NNUlp: LD A,(HL) + CALL UCase + LD (HL),A + INC HL + DJNZ NNUlp + POP BC ;restore length + LD HL,DMA + LD A,(HL) + CP '/' ;watch for mode only + JR NZ,NNMod + INC HL + CP (HL) ;second '/' + DEC HL + JR NZ,NNMod2 +NNMod: LD A,B + CALL Parse ;parse DU:FN.T /O + JP C,Error7 ;check bad entry + XOR A + LD (FilFlg),A ;kill fileflg + RET +NNMod2: INC HL + LD A,(HL) ;do mode only + CP 'W' ;WordStar + JR Z,NNMdOK + CP 'A' ;ASCII + JR Z,NNMdOK + CP 'N' ;non document + JP NZ,Error7 +NNMdOK: LD (FMode),A + RET +; +DfltM: LD HL,0101H + LD (LMSav),HL ;margins set + LD A,(FMode) ;doc or nondoc mode? + SUB 'N' + JR Z,Dflt2 + XOR A + LD (AIFlg),A + DEC A + LD (VTFlg),A + LD A,(HCDflt) + LD (HCRFlg),A ;HCR display? + LD A,(RtMarg) ;If RM set, avoid wierd WW/AI conflict + DEC A + JR NZ,DfltX + LD HL,(DfltLM) ;from NONdoc: reset margins + LD (LfMarg),HL +DfltX: LD A,';' ;punctation chars: , ; : - . ? ! + JR DfltX2 +Dflt2: LD (LfMarg),HL ;NONdocument mode + LD (VTFlg),A ;varitabs off + LD (HCRFlg),A ;HCR display off + DEC A + LD (AIFlg),A ;auto indent ON + LD A,':' ;punctation chars: , : - . ? ! (NOT ;) +DfltX2: LD (PunTbl+1),A + JP RulFix +; +; +;Toggle case of character at cursor +; +UpLow: CALL Fetch ;also points to byte with (HL) + AND 5FH ;strip off both hidden space and case + CP 'A' + JR C,UpLo1 ;leave alone if not letter + CP 'Z'+1 + JR NC,UpLo1 + BIT 5,(HL) ;toggle case + RES 5,(HL) + JR NZ,UpLo0 ;was lower, now up + SET 5,(HL) ;was upper, now low +UpLo0: CALL ELret2 +UpLo1: CALL Right ;move right for next(?) + JP SetRCu +; +; +;Set page length +; +PgSet: LD HL,PgLnQ + CALL Prompt + LD A,(FormL) ;default value + CALL GetNum + JP C,Error7 + LD (PgLen),A + CALL DoHdr + JP ShoLn1 +; +; +;VARIOUS TOGGLES +; +;Simple on/off toggles +; +HCRTog: CALL SetAl ;HCR display + LD HL,HCRFlg +ToggHL: LD A,(HL) + CPL + LD (HL),A + RET +; +;These require header display +; +HypTog: LD HL,HypFlg ;hyphenation + CALL ToggHL +HYshow: LD HL,HYon + LD A,(FMode) + CP 'N' ;irrelevant in N mode + JR Z,HYsho0 + LD A,(HypFlg) + OR A + JR NZ,HYsho1 +HYsho0: LD HL,TogOff +HYsho1: LD DE,DspHyp + JP TogSho +; +IToggl: LD HL,InsFlg ;INSERT + CALL ToggHL +ITshow: LD A,(InsFlg) + LD HL,MacFlg + BIT 7,(HL) + JR Z,ITsho0 + LD A,(SavIns) +ITsho0: OR A + LD HL,INSon + JR NZ,ITsho1 + LD HL,TogOff +ITsho1: LD DE,DspIns + JP TogSho +; +DblTog: LD HL,DSFlg ;double spacing + CALL ToggHL + OR A + CALL NZ,AIoff ;turn off auto ident if double spacing +DblSho: LD A,(DSFlg) + OR A + LD HL,DSon + JR NZ,DSsho1 + LD HL,TogOff +DSsho1: LD DE,DspSpc + JP TogSho +; +AIoff: LD HL,AIFlg + INC (HL) + DEC (HL) + RET Z ;fall thru to turn off auto indent if it's on +; +AITog: LD HL,AIFlg ;auto indentation + CALL ToggHL + OR A + JR Z,AIshow + LD HL,DSFlg ;is double spacing on? + INC (HL) + DEC (HL) + CALL NZ,ToggHL ;turn it off if so + CALL NZ,DblSho ;turn off the old DS display + LD A,1 + CALL SLM1 ;reset left margin to 1 +AIshow: LD A,(AIFlg) + OR A + LD HL,AIon + JR NZ,AIsho1 + LD HL,TogOff +AIsho1: LD DE,DspInd + JP TogSho +; +PSTog: LD A,(PSokFl) + OR A + JP Z,Error2 ;invalid key + LD HL,PSFlg + CALL ToggHL + LD A,(RMSav) + DEC A + RET NZ ;margins released? then we're done +PSDisp: LD A,(FMode) + CP 'N' + JR Z,PSTogU ;no PS in nondocument mode + LD A,(PSFlg) + OR A + LD HL,PSon ;proportional spacing on + JR NZ,PSTogX +PSTogU: LD HL,TogOff ;turn off margin release +PSTogX: LD DE,DspMrg + JP TogSho +; +; +;TEXT FORMAT functions +; +SetRM: CALL StMrCm ;Same for left and right + LD C,A + LD A,(LfMarg) + CP C + JR C,SRM1 ;inside LM? + LD A,1 + LD (LfMarg),A ;if so, reset LM +SRM1: LD A,C + LD (RtMarg),A + JR StMgEn +; +SetLM: CALL StMrCm ;Same for left and right + LD HL,RtMarg + CP (HL) + JR NC,MrgErr +SLM1: LD (LfMarg),A + DEC A + CALL NZ,AIoff +StMgEn: CALL RulFix + JP ShoLn1 +; +StMrCm: LD A,(FMode) ;Set right margin + CP 'N' ;(must be Document mode) + JR Z,MrgErr + LD A,(RMSav) ;okay, do it + DEC A + CALL NZ,RelM ;(undo Margin Release) + LD HL,ColQ + CALL Prompt + LD A,(CurCol) ;default: cursor column + CALL GetNum + JR Z,MrgErr + RET NC +MrgErr: POP HL + JP Error7 +; +RelM: CALL RelLM ;release both margins (Toggle) + LD HL,RtMarg + LD DE,RMSav + CALL RelSb + CALL MRshow + JP RulFix +; +RelLM: LD HL,LfMarg ;SBR: release left only + LD DE,LMSav +RelSb: LD A,(HL) ;common subroutine + CP 1 + JR Z,Rel1 + LD (DE),A ;note: if RMSav>1, margins released + LD (HL),1 + RET +Rel1: LD A,(DE) + LD (HL),A + LD A,1 + LD (DE),A + RET +; +;Check the right margin +; +ChkRM: LD A,(CurCol) ;be sure this is up to date + LD B,A + LD A,(RtMarg) + INC A + LD C,A + SUB B ;set C if over + RET NC + CALL IgnCtl ;yes, ignore ctlchars + LD A,C ;try arithmetic once again + ADD A,E + SUB B + RET ;now C set if really over +; +IgnCtl: CALL Fetch ;count ctlchars to be ignored + LD E,0 ;(up to present cursor) + LD HL,(BefCu) + JR NZ,IgnC1 +IgnCLp: LD A,(HL) ;count em + DEC HL + CP CR ;quit at BOL + RET Z +IgnC1: CP TAB ;tabs don't count + JR Z,IgnCLp + CP 20H + JR NC,IgnCLp + INC E ;others do + JR IgnCLp +; +;Check left margin, space over if needed +; +ChkLM: LD A,(LfMarg) + LD B,A + LD A,(CurCol) + SUB B ;be sure this is uptodate + RET ;ret Z if at, C if over +; +UpToLM: LD A,(LfMarg) ;git on over to the LM column +; +MvCol: PUSH AF ;move to col A saving any existing text + CALL GoCol + POP AF +MvColI: LD HL,CurCol ;move to col A inserting spaces + SUB (HL) + RET C ;we're past already + RET Z ;we're there + LD B,A + CALL SetCu ;this is going to hurt +MvClp: PUSH BC ;insert B spaces + CALL InsSpc + POP BC + RET C ;quit if out of space + CALL IncH + DJNZ MvClp + RET +; +DoLM: LD A,(LfMarg) ;create whole left margin + DEC A + RET Z + LD B,A + JR MvClp +; +;Handle former margin for reformat +; +CntSpc: CALL QuikLf ;count lead spaces/tabs on line + CALL Fetch + LD B,A + EXX + XOR A +CSpLp: LD (NumTab),A + PUSH AF + CALL Fetch + CP ' ' + JR Z,CSpL1 + CP TAB + JR NZ,CSpLpF +CSpL1: EXX + CP B + EXX + JR NZ,CSpLpF + CALL Right ;move 1 char right + POP AF + INC A ;incr # tabs + JR CSpLp +CSpLpF: CALL QuikLf ;back to start + EXX +CntSpX: POP AF + RET +; +EatSpc: OR A ;eat up to A lead spaces on line + RET Z +ESpLp: PUSH AF + CALL Fetch + CP TAB + JR Z,ESpLpF + CP ' ' + JR NZ,CntSpX +ESpLpF: CALL EChar + POP AF + DEC A + JR NZ,ESpLp + RET +; +; +;Update CurCol and return it in A and B +;(NOTE: slow. When possible, LDA CurCol.) +; +ColCnt: CALL WhatC + LD (CurCol),A + RET +; +WhatC: CALL FetchB ;col 1 is spcl case + CP CR + LD A,1 + LD B,A + RET Z + LD E,1 + CALL CrLft ;start of line + LD BC,0 +; +CCLp: CALL GetNx ;get a char + CP TAB + JR NZ,CC1 + LD A,B ;tabs are special + PUSH HL + LD HL,TabCnt + OR (HL) ;round up + POP HL + LD B,A +CC1: INC B ;count char + LD A,B + CP 254 + JR Z,CC2 ;too long? return column 255 forever + XOR A + CP C + JR NZ,CCLp ;get hidden space? + PUSH BC + CALL LCnt ;compare HL to BefCu + POP BC + JR NC,CCLp ;get another, if more exist +CC2: INC B + LD A,B ;that is curcol. + RET +; +; +;Do wordwrap if needed +; +WdWrap: LD A,(RtMarg) ;WW off if RM=1 + DEC A + RET Z + LD IY,CurCol + INC (IY) ;count the char you just put in + CALL ChkRM + RET NC + LD B,0 ;past margin... +WWLp: INC B ;count moves + PUSH BC + CALL Left + DEC (IY) + POP BC + CALL FetchB + CP CR ;oh no Uncle Bill + JP Z,Error9 + CP '-' ;hyphenation + JR NZ,WW1 + LD A,(HypFlg) + OR A + JR Z,WW1 + CALL Fetch + CP ' ' + JR Z,WW1a + INC B + PUSH BC + CALL InsSpc ;tuck in a space if there isn't one + JR WW2 +WW1: CALL Fetch + CP ' ' + JR NZ,WWLp +WW1a: PUSH BC + CALL Right ;leave it if there is + INC (IY) +WW2: CALL ChkLM + JR Z,WWerr + JR C,WWerr + CALL ICRB ;break line + CALL QuikLf + CALL DoLM + POP BC + LD A,(NumTab) + ADD A,B + JP C,WWerr + DEC A ;one spc gone +GoRtA: OR A ;Go right A chars - used by wordwrap etc + RET Z + PUSH AF + CALL Right + POP AF + DEC A + JR GoRtA +; +WWerr: POP BC + JP Error9 +; +;Reform a paragraph +; +Reform: LD A,(RtMarg) ;is RM set? + DEC A + RET Z + CALL QuikLf + CALL NdCnt + JP C,RfmE10 + CALL Fetch ;empty line? + JP Z,Down + CALL XQuiet + LD A,(AIFlg) + OR A + JR NZ,RfmBg + CALL RfmNL ;figure out indentation + JR C,RfmBg + CALL CntSpc + PUSH AF + CALL RfmPL + POP AF + CALL EatSpc ;remove spaces acc. to NEXT line indent + CALL DoLM ;and add current margin +RfmBg: CALL QuikLf + CALL KyPeek ;peek for a keypress + CP ESC ;check for abort + JR NZ,RfmBg1 ;no... keep going + CALL Keybd ;eat the ESC + JP RfmEnd ;and quit +RfmBg1: CALL ColCnt ;only once per line (slow) + LD IY,CurCol + LD A,63 + LD (PScnt),A +; +RfmLp: CALL NdCnt + JP C,RfmE10 ;check for EOF + CALL Fetch + JP Z,Rfm7 ;and EOL + CP TAB ;tabs are special + JR NZ,RfmTab + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A + JR Rfm3 +RfmTab: LD HL,PSFlg + DEC (HL) + INC (HL) + JR Z,Rfm3 + LD HL,PSTbl-32 + ADD A,L + LD L,A + LD A,0 + ADC A,H + LD H,A + LD A,(PScnt) + ADD A,(HL) + CP 63+30 + JR NC,RfmTb1 + CP 63-30+1 + JR NC,Rfm3 + ADD A,30 + JR Rfm3a +RfmTb1: ADD A,-30 + INC (IY) +Rfm3: INC (IY) ;Keep CurCol updated +Rfm3a: LD (PScnt),A + CALL Right + CALL ChkRM + JR NC,RfmLp +; +Rfm4: CALL FetchB ;just the right length? + CP ' ' + JR NZ,Rfm4a + CALL Fetch + JR Z,Rfm7 +Rfm4a: CALL Left ;oops, too long. + CALL FetchB + CP CR + JP Z,RfmErr + CALL Fetch + CP '-' + JR NZ,Rfm4b + LD A,(HypFlg) + OR A + JR Z,Rfm4b + CALL Right + CALL ColCnt ;## + CALL ChkRM ;## + JR NC,Rfm4a2 ;## + CALL Left ;## + JR Rfm4 ;## +; +Rfm4a2: CALL InsSpc + JR Rfm4c +Rfm4b: CALL IsBlnk ;break after blank + JR NZ,Rfm4 + CALL Right +Rfm4c: CALL ColCnt + CALL ChkLM ;watch out for left mgn + JP Z,RfmErr + JP C,RfmErr + CALL ICRB +Rfm5: CALL Fetch ;avoid spurious para + JR Z,Rfm6a ;(stop after CR) + CP ' ' + JR NZ,Rfm6b + CALL EChar + JR Rfm5 +Rfm6a: CALL EChar + JR RfmBg2 +Rfm6b: CALL DoLM + JR RfmBg2 +; +Rfm7: CALL FetchB ;is the CR soft or hard? + CP ' ' + JR NZ,Rfm9 ;hard, quit + CALL Left ;soft, delete any other spaces +Rfm7a: CALL FetchB + CP ' ' + JR NZ,Rfm7b + CALL Delete + JR Rfm7a +Rfm7b: CP '-' ;unhyphenate? + JR Z,Rfm20 +Rfm8: CALL Right ;and now the CR itself + CALL EChar + CALL RfmSD ;and any soft CR following + LD A,255 + CALL EatSpc ;and any leading spaces + CALL Fetch + JR NZ,Rfm8a ;hit bald CR? + CALL Delete ;yep, kill space and quit + JR Rfm9 +Rfm8a: CALL Left + CALL Left + CALL IsEndS ;(extra spc for punc) + JR NZ,RfmBg2 + CALL Right + CALL InsSpc +RfmBg2: JP RfmBg +Rfm9: CALL Right ;hard CR (check following soft?) + CALL RfmSD ;delete, if there + CALL ICRB0 ;may need to separate paras +RfmEnd: CALL XLoud + JP SetAl +RfmErr: CALL XLoud + JP Error9 +RfmE10: CALL XLoud + JP Eror10 +; +Rfm20: LD A,(HypFlg) ;unhyphenation + OR A + JR Z,Rfm8 ;not allowed, continue +Rfm21: CALL Loud + CALL ShoAll + CALL YesNo1 + PUSH AF + CALL XQuiet + POP AF + JR NC,Rfm22 + JR Z,Rfm21 ;C,Z means "*": unacceptable + JR Rfm8 ;C,NZ means ESC: don't join at all +Rfm22: CALL Z,Delete ;kill hyphen if it was "Yes" + CALL Join ;join lines (whether "Yes or No") + JR RfmBg2 +; +RfmNL: CALL QuikRt ;go to next line of text + CALL NdCnt + JR NC,RfmNL0 + CALL QuikLf ;oops, none + SCF + RET +RfmNL0: CALL Right + CALL Fetch ;(may be blank) + JR NZ,RfmNL1 ;bald CR next? also give up + CALL Up + SCF + RET +RfmNL1: CP ' ' + JR Z,RfmNL2 + CALL QuikLf ;no, fine, we're here + OR A + RET +RfmNL2: CALL Right + CALL Fetch + JR NZ,RfmNL1 ;just spaces and CR? doublespacing, + CALL Right ; go on to next line + JR RfmNL1 +RfmPL: CALL QuikLf ;return to previous line of text +RfmPL0: CALL Left + CALL FetchB ;(may be blank) + CP CR + JP Z,RfmPLx ;yes, take next + CP ' ' + JR Z,RfmPL0 + JP QuikLf ;no, fine +RfmPLx: CALL Left + JP QuikLf +; +RfmSD: CALL Fetch ;delete a soft CR if present + CP ' ' + RET NZ + CALL Right + CALL Fetch + PUSH AF + CALL Left + POP AF + RET NZ + CALL EChar + JP EChar +; +; +;Center or flush a line +; +Center: LD E,1FH ;(RRA) if Center + CP 'F'-40H + JR NZ,Ctr0 + LD E,0C9H ;(RET) if Flush +Ctr0: LD A,E + LD (Flush),A + LD A,(RtMarg) + CP 1 + RET Z ;not if no margin + CALL QuikLf ;start of line +CtrL1: CALL Fetch + JR Z,CtrXit ;end? done + CALL IsBlnk + JR NZ,CtrL1F + CALL EChar ;delete spaces + JP C,Error9 + JR CtrL1 +CtrL1F: CALL QuikRt ;end of line +CtrL2: CALL Left + CALL IsBlnk + JR NZ,CtrL2F + CALL EChar ;delete spaces + JR CtrL2 +CtrL2F: CALL ColCnt ;where are we? + CALL IgnCtl ;ignore ctlchars + LD HL,CurCol + LD A,(LfMarg) + DEC A + LD B,A + LD A,(RtMarg) + ADD A,E ;(ctlchars) + SUB B + SUB (HL) + JP C,Error9 ;error + CALL Flush + JR Z,CtrXit + PUSH AF + CALL QuikLf ;start again + CALL DoLM + POP BC +CtrL3: PUSH BC ;insert spaces to center + CALL InsSpc + POP BC + DJNZ CtrL3 +CtrXit: CALL QuikLf + CALL ShoCu + CALL QuikRt ;to next line(?) + JP Right +; +Flush: RRA ;<--- goes to RET if Flush + AND 7FH ;take half the difference for Center + RET +; +; +;Fetch character at (or before) cursor +; +Fetch: LD HL,(AftCu) + LD A,(HL) + AND 7FH ;ignore any hidden space + CP CR + RET +FetchB: LD HL,(BefCu) + LD A,(HL) + BIT 7,A + RET Z ;ordinary byte + LD A,' ' + RET ;hidden space +; +;Tests on char at cursor (use only A,HL) +; +IsBlnk: LD HL,BlkTbl ;point to tbl + JR IsTest +IsPara: LD HL,ParTbl + JR IsTest +IsParB: LD HL,ParTbl + JR IsTstB +IsPunc: LD HL,PunTbl + JR IsTest +IsPunB: LD HL,PunTbl + JR IsTstB +IsEndS: LD HL,EndTbl +; +IsTest: PUSH HL + CALL Fetch + POP HL + JR IsTLp +IsTstB: PUSH HL + CALL FetchB + POP HL +IsTLp: BIT 7,(HL) + JR NZ,IsTst1 ;at end of tbl? + CP (HL) + RET Z ;Z set if match + INC HL + JR IsTLp +IsTst1: OR A ;clear Z if none + RET ;ret char in A +; +PunTbl: DB ',;:-' ;fall thru... +EndTbl: DB '.?!',0FFh ;end with 0FFh +ParTbl: DB CR ;fall thru... +BadTbl: DB 0,EOF ;characters not "part" of file text +BadLen EQU $-BadTbl ;(<--BlkChr patches in here) +BlkTbl: DB ' ',TAB,0FFh ;end with 0FFh +; +;DISK I/O +; +IOon: LD DE,DspEsc ;show Wait.... + CALL GoTo + CALL MakAlt + LD HL,IOmsg + LD B,4 + CALL BHLMsg + CALL UnAlt + RET +; +BDOSfc: LD DE,FCB +; +;Enter BDOS, but latch onto warm start for +;recovery purposes. (CP/M 2 ONLY) +; +BDOS: CALL DOSVer + JP NC,BDOSep ; just do the BDOS call for CP/M 3.0 + LD A,(DE) ; grab drive # + LD (FcbDrv+1),A ; and stuff it into code + PUSH DE + LD HL,(0001H) + INC HL ;trap warm boot vector in BIOS JP table + LD E,(HL) + INC HL + LD D,(HL) + LD (BIOSws+1),DE + LD DE,BIOSws + LD (HL),D + DEC HL + LD (HL),E + POP DE + CALL BDOSep ;DO IT + PUSH HL + LD DE,(BIOSws+1) ;Restore real warm boot + LD HL,(0001H) + INC HL + LD (HL),E + INC HL + LD (HL),D + POP HL + RET +BIOSws: LD DE,0 ;<--- Warm boot vector + LD HL,(0001H) + INC HL + LD (HL),E ;restore it + INC HL + LD (HL),D +FcbDrv: LD A,0 ;<----- + LD (FCB),A ;restore drive + LD SP,Stack ;restore stack + CALL RDlog ;and disks + CALL Error3 ;Give I/O message + JP Sk1Ed ;Continue editing +; check dos version - 22h=>CP/M2.2, 31h=>CP/M3, 'S'=>ZSDOS & "D"=> ZDDOS +; on return: (Carry set if 2.2, reset if CP/M3, ZxDOS) +DOSVer: LD A,0 ;<---- Version @ DOSVer+1 + CP 30H + RET +; +RstDrv: OR A ;CP/M 2 drive reset (A=1 etc) + JR Z,RDlog + LD HL,FixDsk + RES 6,(HL) ;(have to adjust from ASCII) + CP (HL) ;one of 2 fixed drives? ignore + RET Z + INC HL + RES 6,(HL) + CP (HL) + RET Z + PUSH AF + LD C,GDRV + CALL BDOSep + POP BC + INC A + CP B ;is it logged drive? + JR Z,RDlog + LD HL,1 ;if NOT, can be selective +RDlp: DEC B + JR Z,RDok + ADD HL,HL + JR RDlp +RDok: EX DE,HL + LD C,RSTV ;reset single drive + JR RDxit +RDlog: LD C,RSTD ;sigh, whole system +RDxit: JP BDOSep +; +; +Parse: PUSH AF ;parse FCB w/Duu: and [A/W (NO WILDCARDS) + LD A,(DFMode) + LD (FMode),A + PUSH HL ;Entry: HL=string, A=length + CALL BlkFCB ;Exit: set FCB, FCBU, FMode + POP HL ;...now checks filetypes too + LD D,H + LD E,L + POP AF + OR A + JP Z,PNODRV + LD C,A + LD B,0 ;chars there + LD A,':' + CPIR ;find drivespec? + JR NZ,PNODRV + DEC HL ;yep...NDR? + LD (HL),0 + CALL NdrChk + LD (HL),':' + JR Z,Parse1 ;not an NDR name + INC HL + LD A,B + LD (FCB),A ;store drive + LD A,C + LD (FCBU),A ;store user number + LD E,A + LD C,USRN + PUSH HL + CALL BDOSep ;set user number + POP HL + JR PNAME +Parse1: DEC HL ;yep...User number? + LD A,(HL) + CP '0' + JR C,PDRV + CP '9'+1 + JR NC,PDRV +; +PUSR: SUB '0' + LD E,A ;Got user... figure units + DEC HL + LD A,(HL) + CP '0' + JR C,ZPAR1 ;thats all? + CP '9'+1 + JR NC,ZPAR1 + SUB '0' + LD D,A ;nope, tens too + ADD A,A + ADD A,A + ADD A,A ;*8 + ADD A,D + ADD A,D + ADD A,E ;*(8+2)+units = user + LD E,A + DEC HL + CP 32 + JR NC,ZPBAD ;illegal? +ZPAR1: LD A,E + LD (FCBU),A ;set user + LD C,USRN + PUSH HL + CALL BDOSep + POP HL +; +PDRV: BIT 7,L ;now, parse FCB (start with drive) + JR Z,ZPAR2B ;(Kludge: stay above 0080h) + LD A,(HL) + CP ' ' ;oops, was it there? + JR Z,ZPAR2B +ZPAR2: SUB 'A' + JR C,ZPBAD ;make sure it's legal + LD E,A + LD A,15 + CP E + JR C,ZPBAD + DEC HL + BIT 7,L + JR Z,ZPAR2A ;kludge again (stay about 0080H) + LD A,(HL) + CP ' ' + JR NZ,ZPBAD +ZPAR2A: INC HL + LD A,E + INC A + LD (FCB),A +ZPAR2B: LD BC,4 + LD A,':' + CPIR ;skip over user, to filename + JR PNAME +PNODRV: LD A,' ' ;no du: at all + EX DE,HL + DEC HL ;find filename +PNDL: INC HL + CP (HL) + JR Z,PNDL ;(first nonblank) +; +PNAME: LD B,8 + LD DE,FCB+1 ;do filename at (HL) + EXX + LD DE,FNamBf + LD H,D + LD L,E + LD B,13 + XOR A + CALL Fill + EXX +ZPRL1: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP '.' + JR Z,ZPRL1X + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZRLP1A + CP (HL) + JR NZ,POPT + INC HL +ZRLP1A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL1 + JR ZPRL1F +ZPRL1X: LD A,' ' ;fill with " " + CALL Fill + JR PTYP +ZPBAD: CALL BlkFCB ;bad entry + SCF + RET +ZPRL1F: XOR A + ADD A,(HL) + JR Z,ZPARX + CP '.' + JR NZ,ZPRL2F ;no "."? leave type blank + INC HL +; +PTYP: LD B,3 ;fill type at (HL) + EXX + LD A,'.' + LD (HL),A + INC HL + EXX +ZPRL2: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZPRL2A + CP (HL) + JR NZ,POPT + INC HL +ZPRL2A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL2 +ZPRL2F: LD A,(HL) ;(eat spaces) + CP ' ' + JR NZ,POPT + INC HL + JR ZPRL2F +; +POPT: LD A,(HL) ;process W/A/N option + CP '/' + JR NZ,POPT1 + INC HL + LD A,(HL) ;process W/A/N option +POPT1: OR A + JR Z,ZPARX + CALL VerOpt ;verify legality + JR NZ,ZPBAD + LD (FMode),A + JR ZPARX2 ;any specification overrides defaults +; +ZPARX: LD HL,FCBt1 ;check filetype mode defaults + LD DE,FDflt1 + CALL TypDfl + LD DE,FDflt2 + CALL TypDfl + LD DE,FDflt3 + CALL TypDfl + LD DE,FDflt4 + CALL TypDfl +ZPARX2: LD A,(FCB+1) + CP ' ' + JR Z,ZPBAD + OR A ;DONE. + RET +; +ZPBADC: PUSH HL ;check bad chars + PUSH BC + LD HL,ZPBLST + LD BC,ZPBLEN + CPIR ;Z set if bad + POP BC + POP HL + RET +ZPBLST: DB ' .,;:?*=' ;illegal chars +ZPBLEN EQU $-ZPBLST +; +TypDfl: PUSH HL + LD B,3 ;Set mode from filetype if (HL),(DE) MATCH +TypDLp: LD A,(DE) + CP '?' + JR Z,TypD2 + CP (HL) + JR NZ,TypDex ;no match, quit +TypD2: INC DE + INC HL + DJNZ TypDLp + LD A,(DE) ;match, here's your mode + CALL VerOpt +TypDex: POP HL + RET NZ + LD (FMode),A + RET +; +; +VerOpt: CP 'A' ;verify mode option legal + RET Z + CP 'N' + RET Z + CP 'W' + RET +; +; +;IN: DE=string to match +;OUT: Z=0,B=drive,C=user# (if NDR match found) +; Z=1 if no NDR match +; +NdrChk: PUSH HL + PUSH DE + EX DE,HL ;string addr to HL + LD A,' ' + DEC HL +NdrSpc: INC HL ;skip over spaces + CP (HL) + JR Z,NdrSpc + LD D,H ;addr of 1st non blank to DE + LD E,L + LD B,Z3NdrM+1 ;# chars to allow before + XOR A ;we MUST see a NUL +NdrEos: CP (HL) ;find terminating NUL + JR Z,NdrNul + INC HL + DJNZ NdrEos + JR NoNdr ;more than 8 chars, not an NDR +NdrNul: LD BC,Z3NDR + CALL Z3EAdr + JR Z,NoNdr ;no NDR block + EX DE,HL ;start of string to HL + LD D,B ;NDR addr to DE + LD E,C +NxtNdr: LD A,(DE) ;end of NDRs? + OR A + JR Z,NoNdr ;yep, no match + INC DE + INC DE ;DE points to NDR string + PUSH HL ;save start of string + PUSH DE ;save NDR string addr + LD B,Z3NdrM +NdrNxC: LD A,(DE) + CP ' ' ;end of NDR name string? + JR NZ,NdrChC ;not yet + INC (HL) ;did we hit the NUL + DEC (HL) ;at the end of string + JR NdrMis ;(i.e. was it a full match?) +NdrChC: CP (HL) + JR NZ,NdrMis + INC HL ;next char in string + INC DE ;next char in NDR entry + DJNZ NdrNxC +NdrMis: POP DE ;restore start of NDR string + POP HL ;restore start of string + JR Z,NdrMtc ;all chars match, got an NDR + EX DE,HL ;start of NDR string to HL + LD BC,Z3NdrL + ADD HL,BC ;next NDR entry to HL + EX DE,HL ;and now to DE + JR NxtNdr +NdrMtc: EX DE,HL ;NDR matched + DEC HL + LD C,(HL) ;fetch user number + DEC HL + LD B,(HL) ;fetch drive + OR 0FFh ;Z=0H +NoNdr: POP DE + POP HL + RET +; +;Read in a word from the Z3ENV block. +;IN: offset in BC +;OUT: addr in BC +; Z=1 if addr is invalid +; +Z3EAdr: PUSH HL + LD HL,(Z3Env) + LD A,H + OR L + JR Z,NoZEnv ;no Z3ENV: Z=1 + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + LD A,B + OR C ;Z=1 if no address at offset +NoZEnv: POP HL + RET +; +; +;Read in the file. (HL=prev byte, BC=max size) +;Return with HL=last byte, Z=out of room, C=input error. +; +MSIn: PUSH HL ;Initialize FCBex thru FCBrc and FCBcr + PUSH BC + XOR A + LD DE,FCBex + LD B,4+16+1 + CALL Fill + LD (MSIFlg),A + CPL + LD (SftFlg),A + LD C,FOPN + CALL BDOSfc + INC A ;Not found? + JR NZ,MSIfnd +MSIerr: POP BC ;Error... + POP BC + OR 1 ;Clear Z + SCF ;Set C + RET +MSIfnd: LD DE,DMA + LD C,SDMA + CALL BDOS +; +MSIlp1: LD C,RSEQ + CALL BDOSfc + CP 1 ;No more reocrds? + JP Z,MSIefX + JR NC,MSIerr ;Other error? + LD IX,DMA + POP DE ;target count + LD B,128 ;1 record + POP HL ;target address +MSIlp2: LD A,(FMode) + CP 'W' + JR NZ,MSIlp3 + LD A,(IX) ;Wordstar: handle soft hyphens + CP 1Fh + JR NZ,MSIl2x + LD A,'-' + LD (IX),A +MSIl2x: CP 1Eh ;remove dead soft hyphens + JR Z,MSIlf + CP ' '+080H ;remove soft spaces + JR NZ,MSIl2a + LD A,(SftFlg) + OR A ;(unless at beginning of line) + JR Z,MSIlf + JR MSIlp3 +MSIl2a: XOR A + LD (SftFlg),A + LD A,(IX) ;and keep hard/soft CRs straight + CP CR+80H + JR NZ,MSIl2b + LD A,(HL) ;SCR must have space before... + CP ' ' + JR Z,MSIlp3 + SET 7,(HL) + JR NC,MSIlp3 + RES 7,(HL) ;can't set hi bit on ctlcodes + LD A,' ' + INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z + JR MSIlp3 +MSIl2b: CP CR + JR NZ,MSIlp3 +MSIl2c: RES 7,(HL) ;...and HCR must not have space + LD A,(HL) + CP ' ' + JR NZ,MSIlp3 + DEC HL + INC DE + JR MSIl2c +MSIlp3: LD A,(IX) ;take the byte + AND 7Fh ;Mask parity + CP EOF ;EOF? + JR Z,MSIeof + CP LF ;toss line feeds + JR NZ,MSIl3a + LD (SftFlg),A ;but record them + JR MSIlf +MSIl3a: LD IY,BlkChr + CP (IY) ;toss block chars + JR Z,MSIlf + CP ' ' ;take non-spaces + JR NZ,MSIok + LD A,(HL) + CP 20H ;Last one CTL? take space + JR C,MSIsp + BIT 7,(HL) ;Already hidden space? take space + JR NZ,MSIsp + SET 7,(HL) ;Hide space + JR MSIlf +; +MSIsp: LD A,' ' +MSIok: INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z +MSIlf: INC IX ;Bump input + DEC B ;Go through record + JP NZ,MSIlp2 + PUSH HL + PUSH DE + JP MSIlp1 ;Get next block +; +MSIefX: POP DE ;(for last rec bug fix) + POP HL +MSIeof: OR 1 ;clear Z/C + LD (MSIFlg),A ;Show load OK + RET +; +; +;Write out BC characters at HL to file FCB (C=error) +; +MSOut: PUSH BC + PUSH HL + ADD HL,BC ;ending address + PUSH HL + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD HL,FCB+1 ;strip attributes + LD B,11 +MSOlp0: RES 7,(HL) + INC HL + DJNZ MSOlp0 + LD B,4 + XOR A +MSOlp1: LD (HL),A ; zero out FCBex, FCBs1, FCBs2, FCBrc + INC HL + DJNZ MSOlp1 +; cpm3 and zsdos get date/time stamps differently. zsdos puts it in DMA buffer +; while cpm3 puts create or access at FCB+18h & update at FCB+1Ch +; zsdos returns A=1 for success, A=0FFh for fail +; cpm3 returns A=0-3 for success, A=0FFh for fail + ld a,(DOSVer+1) + cp 31h ;is it cpm + jr z,TS3 ;Br if CPM3 + LD DE,tStamp ; set the buffer for the + LD C,SDMA ; set file timestamp buffer as DMA buf + CALL BDOSep + LD C,GETS ; get the file timestamp + CALL BDOSfc + jr TSRD +TS3: ld c,GETS + call BDOSfc + ld hl,FCB+18h + ld de,tStamp + ld bc,8 + ldir ;copy timestamp to buffer +TSRD: LD (tsFlg),A ; A=0FFh if no stamp + LD A,(FilFlg) ; make a backup file? + OR A + JR Z,MSOdel ; no backup needed + LD HL,FCB ; copy original filename and extension + LD DE,DMA + LD BC,16 ;FCB length + LDIR ;copy it + LD BC,8+1 ;copy original filename only + LD HL,FCB + LDIR ;again + LD BC,3 ;extension of BAK + LD HL,Bak + LDIR + LD DE,DMA+16 ;delete BAKfil + LD C,FDEL + CALL BDOS + INC A + JR NZ,MSOren + OR H ;no BAK deleted, h/w error? + JP NZ,MSOer2 ;yep... +MSOren: LD DE,DMA ;rename old file to BAK + LD C,FREN + CALL BDOS + JR MSOmak +; +MSOdel: CALL DOSVer + JR C,MSOdl2 ; skip if plain CP/M + CP 'S' + JR Z,MSOdl2 ; skip if ZSDOS + CP 'D' + JR Z,MSOdl2 ; skip if ZDDOS + LD C,ERRM ; ... we get here, we're CP/M 3.0 + LD E,0FFH ; return error, no print + CALL BDOS + XOR A + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK ;make a new file + CALL BDOSfc + PUSH AF + PUSH HL + LD C,ERRM ; return error, print + LD E,0FEH + CALL BDOS + POP HL + POP AF + PUSH AF + OR A + JR Z,MSOnSt + POP AF + LD A,H + CP 8 + JR NZ,MSOmak + LD C,FTRU ; truncate file to 0 bytes (cpm3 only!) + XOR A + LD (FCBr0),A + LD (FCBr1),A + LD (FCBr2),A + CALL BDOSfc + OR A + JP NZ,MSOer2 + LD C,FOPN + CALL BDOSfc ; open the file + PUSH AF + JR MSOnSt ; --- end of CP/M3 specific open code +; +MSOdl2: LD C,FDEL ; +++ CP/M2.2, ZxDOS specific + CALL BDOSfc ; delete any old BAK file + INC A + JR NZ,MSOmak ; jump if all good + OR H ; hardware error code? + JP NZ,MSOer2 ; ...yep +; +MSOmak: XOR A ;Initialize FCB + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK + CALL BDOSfc + PUSH AF +; CP/M3 doesn't have a BDOS function to set a file's timestamp +; like ZSDOS does. So we need to use a special routine that writes +; the stamp directly into the disk's directory. + LD A,(tsFlg) ;+++ timestamp code start + inc A ;do we have a timestamp? + JR Z,MSOnSt ;no, don't update the timestamp + ld a,(DOSVer+1) ;check version + cp 31h ;is it cpm + jr nz,TSZ ;Br if ZSDOS + ld hl,tStamp ;time stamp + ld de,FCB + ld bc,dirdma ;1k dma buffer + call setds3 ;set the stamp + jr MSOnSt +TSZ: LD C,SETS ;set create timestamp of new file + CALL BDOSfc ;to the same as existing file +MSOnSt: LD C,SDMA + LD DE,DMA + CALL BDOSep + POP AF ;restore result of FMAK + POP DE ;end + POP HL ;start + POP BC ;(bytes) + INC A + JP Z,MSOerr ;make file failed + LD A,B + OR C ;any bytes? + JP Z,MSOcls + LD C,0 ;Initialize GetNx + LD B,128 ;1 record + LD IX,DMA +MSOlp2: CALL GetNx + EXX + LD HL,BadTbl ;skip illegal chars + LD BC,BadLen + CPIR + EXX + JR Z,MSOsk1 ;0 or EOF +MSOlp3: LD (IX),A ;put it out + LD A,(FMode) + CP 'W' ;Wordstar mode? + JR NZ,MSOWSx + LD A,(IX) + CP ' ' + JR NZ,MSOWSa + LD A,(IX-1) ;add microjustification bits + CP 21h + JR C,MSOWS2 + SET 7,(IX-1) + JR MSOWS2 +MSOWSa: CP CR + JR Z,MSOWS1 + CP LF + JR Z,MSOWSx +MSOWS0: XOR A + LD (SftFlg),A + JR MSOWSx +MSOWS1: LD A,(IX-1) ;soften CRs after spaces + AND 7FH + CP ' ' + JR NZ,MSOWS0 +MSOW1a: SET 7,(IX) + LD A,0FFH + LD (SftFlg),A + JR MSOWSx +MSOWS2: LD A,(SftFlg) ;and spaces after soft CRs + OR A + JR NZ,MSOW1a +MSOWSx: LD A,(IX) + INC IX ;bump pointer + DJNZ MSOsk1 ;Skip if buffer not full + PUSH BC + PUSH DE + PUSH HL + LD C,WSEQ + CALL BDOSfc + POP HL + POP DE + POP BC + OR A + JR Z,MSOook + CALL MSOcls ;output error + JR MSOerr +MSOook: LD B,128 + LD IX,DMA + LD A,(DMA+127) + LD (IX-1),A +MSOsk1: AND 7FH + CP CR ;Add LF after CR + LD A,LF + JR Z,MSOlp3 + LD A,H + XOR D ;At end yet? + JP NZ,MSOlp2 + LD A,L + XOR E + JP NZ,MSOlp2 + OR C ;Still got hidden space? + JP NZ,MSOlp2 + OR B ;need EOF? + JR Z,MSOsk2 +MSOefL: LD (IX),EOF ;yes + INC IX + DJNZ MSOefL +MSOsk2: LD C,WSEQ + CALL BDOSfc + OR A + JR Z,MSOcls + CALL MSOcls + JR MSOerr +MSOcls: LD C,FCLO ;all done, close up + CALL BDOSfc + INC A + OR A ;bug fix 2.67 + RET NZ +MSOerr: SCF + RET +MSOer2: POP HL ;discard start, + POP HL ;end, + POP HL ;(bytes) + LD C,SDMA + LD DE,DMA + CALL BDOSep ;reset DMA buffer + JR MSOerr +; +; +; +; +; DISPLAY FUNCTIONS +; +;(Re)initialize screen to begin editing +; +DoHdr: LD A,(NoHdrF) + OR A + RET NZ + LD DE,0 + CALL GoTo + LD HL,Header + CALL AltDsp + CALL ShoFnm ;Show file name + LD HL,OPoff + LD A,(FMode) + CP 'N' + JR NZ,DoHdr1 ;show "Pg " if document + LD A,(PgLen) + OR A + JR NZ,DoHdrT + LD HL,OPon ;show "OP" if ^OP in nondoc +DoHdr1: LD DE,DspOP + CALL TogSho +DoHdrT: CALL ITshow ;show toggles + CALL VTshow + CALL HYshow + CALL AIshow + CALL DblSho +MRshow: LD A,(RMSav) ;requires header display + DEC A + LD HL,MRon + JP Z,PSDisp + LD DE,DspMrg + JP TogSho +; +TogSho: LD A,(NoHdrF) + OR A + RET NZ + PUSH HL ;toggle show subroutine + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + JP UnAlt +; +; +UpLft: LD DE,0100H ;go to "top of text" + LD A,(RulFlg) + OR A + JR Z,UndrX + INC D + JR UndrX +UndrHd: LD DE,0100H ;go below header regardless +UndrX: JP GoTo +; +; +NoHdr: LD HL,NoHdrF ;toggles on/off + CALL ToggHL + OR A + JR Z,HdrOn +HdrOff: CALL AdjLns ;that's one more line + CALL IncVO + JP SetAl +HdrOn: CALL AdjLns + CALL DecVO + CALL DoHdr ;let's see it again + JP SetAl +; +; +;Show current file data in the heading +; +ShoFnm: CALL MakAlt + LD DE,DspFnm+8 ;blank out old stuff + CALL GoTo + LD B,19 + CALL BBlank + LD DE,DspFnm + CALL GoTo + LD A,(FCB) + ADD A,'A'-1 ;drive letter + CALL PutChA + LD A,(FCBU) ;user number 0-15 + LD C,A + LD B,'3' ;user 30+? + SUB 30 + JR NC,ShoFn1 + LD B,'2' ;user 20+? + LD A,C + SUB 20 + JR NC,ShoFn1 + LD B,'1' ;user 10+? + LD A,C + SUB 10 +ShoFn1: PUSH AF + LD A,B + CALL NC,PutChA + POP AF + JR NC,ShoFn2 + LD A,C +ShoFn2: ADD A,'0' ;show LSD of user number + CALL PutChA + LD BC,Z3NDR + CALL Z3EAdr + JR Z,ShoFnN ;skip if no NDR + LD H,B + LD L,C +ShFnNl: LD B,(HL) ;drive of this NDR entry + INC B + DEC B + JR Z,ShoFnN ;0 means no more entries + LD A,(FCB) + CP B ;drive match? + INC HL + JR NZ,ShFnNx + LD C,(HL) + LD A,(FCBU) + CP C ;user # match? + JR Z,ShFnNn ;yes, display NDR name +ShFnNx: LD DE,Z3NdrL+1 ;skip over NDR + ADD HL,DE + JR ShFnNl ;try next NDR +ShFnNn: LD A,'/' + CALL PutChA + LD B,8 ;show up to first 8 chars of NDR +ShFdLp: INC HL + LD A,(HL) + CP ' ' + CALL NZ,PutChA + DJNZ ShFdLp +ShoFnN: LD A,':' + CALL PutChA ;punctuate + LD HL,FCB+1 + LD B,8 ;Name +ShFnLp: LD A,(HL) + RES 7,A + CP ' ' ;Quit on blank + JR Z,ShFnLF + CALL PutChA + INC HL + DJNZ ShFnLp ;Loop for 8 +ShFnLF: LD A,'.' ;punctuate + CALL PutChA + LD HL,FCBt1 + LD B,3 ;Type +ShFnL2: LD A,(HL) + CALL PutChA + INC HL + DJNZ ShFnL2 + CALL PutSpc + LD A,'/' ;option + CALL PutChA + LD A,(FMode) + CALL PutChA + JP UnAlt +; +; +Ruler: LD HL,RulFlg ;toggle ruler on/off + CALL ToggHL + OR A + JP Z,RulOff +; +RulOn: CALL AdjLns ;readjust screen length + CALL DecVO + CALL Z,SetAl ;maybe on line 1? + JR RuShow +; +RulFix: LD A,(RulFlg) ;update ruler if on + OR A + RET Z +RuShow: LD IY,RulBuf ;build ruler here + LD A,(NSkip) ;starting column + INC A + LD C,A + LD A,(View) ;length + LD B,A +RuLp: LD E,'-' ;default char is "-" + LD A,(VTFlg) ;which tab mode? + OR A + JR Z,RuLpH + PUSH BC ;"T" if varitab stop + LD A,C + LD HL,VTList + LD BC,VTNum + CPIR + POP BC + JR Z,RuVtab + JR RuNtab +RuLpH: LD HL,TabCnt ;"I" if hardtab stop + LD A,C + DEC A + AND (HL) + JR Z,RuHtab +RuNtab: LD A,(RtMarg) ;"R" if right margin + CP C + JR Z,RuRM + JR C,RuDot ;or dot if outside + LD A,(LfMarg) + CP C + JR Z,RuLM ;or "L" if left margin + DEC A + CP C + JR NC,RuDot +RuLpF: LD (IY),E ;okay, show it + INC IY + INC C + DJNZ RuLp + LD (IY),0 + CALL UndrHd + LD HL,RulBuf + JP AltDsp +RuLM: LD E,'L' + JR RuLpF +RuRM: LD E,'R' + JR RuLpF +RuDot: LD E,'.' + JR RuLpF +RuVtab: LD E,'!' + JR RuLpF +RuHtab: LD E,'I' + JR RuLpF +; +RulOff: CALL AdjLns ;adjust screen size + CALL IncVO + LD E,A + CALL CrLft ;oops, may be near top + XOR A + ADD A,E + JP Z,ShoLn1 + JP SetAl +; +; +;Display one byte on the screen for messages rather than text. +;Hi bit set = following space. +; +DsByt: CP CR ;Is it a CR + JR Z,Sk1DB ;Yes, skip + CP X ;compressed space? + JR NC,Sk3DB +DsBy1: LD E,A ;normal character + LD HL,HPos ;room? + DEC (HL) + JP NZ,PutCh ;put it out + INC (HL) ;EOL + RET +Sk1DB: LD A,(HPos) ;Fill out spaces for CR + LD E,A ;(needed for attributes, etc) + CALL SpEOL + LD A,(AuWrap) ;does autowrap occur? + OR A + JR NZ,Sk1aDB + LD E,CR ;NO, put out a CRLF + CALL PutCh + LD E,LF + CALL PutCh +Sk1aDB: LD A,(View) + INC A + LD (HPos),A ;new line + RET +Sk3DB: AND 7FH ;compressed space + CALL DsByt +DsSpc: LD A,' ' + JR DsBy1 +; +; +;Display message pointed to by HL. 00h is end. +;80H,nn = skip count. +; +Dspla: LD A,(View) ;initialize + INC A + LD (HPos),A +DspLp: LD A,(HPos) ;or continue, here + LD E,A + LD A,(HL) ;get byte + INC HL + OR A ;All done? + RET Z + CP X ;hidden spaces? + JR NZ,Dsp10 + LD A,(HL) ;get space count + INC HL + LD B,A +Dsp01: PUSH BC + PUSH HL + CALL DsSpc + POP HL + POP BC + DJNZ Dsp01 + JR DspLp +Dsp10: PUSH HL + CALL DsByt ;Put it out + POP HL + JR DspLp ;Do next one +; +;Display message which immediatly follows the CALL +; +Dspl: POP HL + CALL Dspla + JP (HL) +DsplC: POP HL ;same, but continued + CALL DspLp + JP (HL) +; +; +;Make a text "window" at screen bottom +; +Window: LD A,(PhysLn) ;requires 16 lines or more + CP 16 + JP C,Error7 + LD HL,WinFlg ;toggles on/off + CALL ToggHL + OR A + JR Z,WinOff +; +WinOn: CALL AdjLns ;adjust counts + LD A,(PhysLn) + AND 1 + CALL NZ,ClLast ;clear odd line? + CALL TopV ;put chosen text on top + LD A,0FFh + LD (BelowF),A ;go below + CALL ShoSc ;show text + LD A,(NoHdrF) + OR A + JR NZ,WinOn2 + LD DE,0000h ;separator needed? + CALL GoTo + CALL SepLin + CALL ShoFnm ;with name +WinOn2: XOR A + LD (BelowF),A + JP SetAl +; +WinOff: CALL AdjLns + JP SetAl +; +; +AdjLns: LD A,(PhysLn) ;KEEP screen counts consistent + LD HL,WinFlg + BIT 0,(HL) + JR Z,AdjL1 + SRL A +AdjL1: LD (Lines),A ;physical window size + LD HL,NoHdrF + BIT 0,(HL) + JR NZ,AdjL2 + DEC A ;adjust for header if present +AdjL2: LD HL,RulFlg + ADD A,(HL) ;adjust for ruler if present + LD (TxtLns),A + RET +; +; +; SCREEN I/O ROUTINES +; +;Do screen control code strings (return Carry if none) +; +CtlStr: XOR A + ADD A,(HL) ;HL points to #,bytes (# may be 0) + SCF + RET Z + LD B,A + INC HL ;set up count +BHLMsg: +CtlSLp: LD E,(HL) + INC HL + PUSH BC + PUSH HL + CALL ShutUp ;do NOT filter + POP HL + POP BC + DJNZ CtlSLp + OR A + RET +; +BlkFCB: LD B,11 ;blank out FCB name,typ + LD DE,FCB+1 +BlkFil: LD A,' ' ;blank out B bytes at DE + LD (DE),A + INC DE + DJNZ BlkFil + RET +BBlank: PUSH BC ;blank out B spaces + LD E,' ' + CALL ShutUp + POP BC + DJNZ BBlank + RET +; +;Show messages and prompts +; +MsgDsp: PUSH HL ;must start at "top" + CALL UpLft + POP HL +AltDsp: PUSH HL ;display message in alt video + CALL MakAlt + POP HL + CALL Dspla + JR UnAlt +; +Prompt: PUSH HL ;Prompt: blank first line + CALL UpLft ;(with attribute) + CALL MakAlt + LD A,(View) + INC A + LD E,A + CALL SpEOL + CALL UnAlt + POP HL + JR MsgDsp ;then show prompt message +; +;Handle alternate video +; +MakAlt: LD A,(AltHdr) ;optional for messages and prompts + OR A + RET Z +AltY: LD HL,AltOn ;mandatory for ctl-chars + LD A,(AltBit) ;ram always uses hi bit + OR A + JP Z,CtlStr + LD A,X + LD (AltMsk),A + RET +UnAlt: LD A,(AltHdr) + OR A + RET Z +UnAltY: LD HL,AltOff + LD A,(AltBit) + OR A + JP Z,CtlStr + XOR A + LD (AltMsk),A + RET +; +;Character output +; +XPutCh: LD A,(Horiz) ;show character in E + LD HL,View ;UNLESS in lower rt corner + CP (HL) + JR NZ,PutCh + LD A,(Vert) + LD HL,TxtLns + CP (HL) + RET Z +PutCh: PUSH HL ;show char in E + PUSH DE + PUSH BC + LD A,(Filter) ;filtered + CP E + JR C,PutChQ ;'?' if char >= Filter (07FH) +PutCh1: LD A,(AltMsk) + OR E + CALL CONOut + POP BC + POP DE + POP HL + RET +PutChQ: LD E,'?' + JR PutCh1 +; +PutSpc: LD A,' ' +Echo: CP 20H ;echo typed char, IF nice + RET C ; (used for one-char input) +PutChA: PUSH DE ;show char in A + PUSH AF ; save it too (for Echo) + LD E,A + CALL PutCh + POP AF + POP DE + RET +; +CONOut: LD E,A +ShutUp: NOP ;<--- goes to RET for Quiet + LD C,UCON ;put byte to console (mostly ctls) + JP BDOSep +; +PosCur: LD A,(Horiz) + LD E,A + DEC E + LD A,(RulFlg) + AND 1 + LD HL,Vert + ADD A,(HL) + LD D,A +; +;Position cursor to row D column E +; +GoTo: LD A,(NoHdrF) ;lie for lack of header + AND D ;(decrement row if >0) + JR Z,GoTo01 + DEC D +GoTo01: LD A,(BelowF) ;implement window below + OR A + JR Z,GoToIt + LD A,(Lines) + ADD A,D + LD D,A +GoToIt: LD A,D + LD (CurRow),A + LD A,(PosMod) + CP 'N' + JR NZ,GoYPos + LD HL,PCu ;use Down,Right method (gaak) + CALL Go2Byt ;home first + LD A,D + OR A + JR Z,Go2RwF +Go2Row: PUSH DE ;move down to desired row + LD E,LF + CALL ShutUp + POP DE + DEC D + JR NZ,Go2Row +Go2RwF: LD A,E + OR A + RET Z +Go2Col: LD HL,PCu+2 + CALL Go2Byt ;now across to desired col + DEC E + JR NZ,Go2Col + RET +GoYPos: CP 'A' ;Okay, can be more sophisticated... + JR Z,GoANSI + LD HL,PCu ;use ESC = sequence + CALL Go2Byt ;leadin byte(s) + LD HL,PCu+2 + PUSH DE ;now coordinates + PUSH HL + LD A,(PosMod) ;which order? + CP 'R' + JR Z,GoToX ;(backwards) + LD A,D + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,E + ADD A,(HL) + CALL CONOut + JR GoToDl +GoToX: LD A,E + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,D + ADD A,(HL) + CALL CONOut +GoToDl: LD A,(PosDly) ;optional delay for some terminals + OR A + RET Z + LD B,A + LD C,0 + JP BDlyLp +GoANSI: LD HL,ANSIms+3 ;use ANSI sequence + LD A,D + INC A ;origin 1,1 + CALL GoASub + LD HL,ANSIms+6 + LD A,E + INC A + CALL GoASub + LD HL,ANSIms + CALL CtlStr + JR GoToDl +GoASub: LD (HL),'0' ;tens digit +GASl1: CP 10 + JR C,GAS2 + INC (HL) + SUB 10 + JR GASl1 +GAS2: INC HL + ADD A,'0' ;units + LD (HL),A + RET +Go2Byt: CALL Go1Byt ;show one or two bytes at HL + LD A,(HL) + OR A + RET Z +Go1Byt: PUSH DE + LD B,1 ;just do one byte + CALL CtlSLp + POP DE + RET +ANSIms: DB 8,ESC,'[00;00H' ;for use with CtlStr +; +; +IfSpLn: LD A,(AltHdr) ;draw sep line IF headers not alt + OR A + RET NZ +SepLin: CALL MakAlt ;draw separator line + LD A,(View) + LD D,A + LD E,'-' +SLDlp: PUSH DE + CALL PutCh + POP DE + DEC D + JR NZ,SLDlp + JP UnAlt +; +; +;SHOW SCREEN ROUTINES +; +; | +------------------------ +; |HELLO! | ^ +; |This is your |text file, which is seen Vert +; |on the screen| just like this._ v +; | | \ +; |<---NSkip---> <-----Horiz-----> \ +; |<-----------CurCol------------> \Cursor at (H,V) +; +;Recheck current position on screen +; +Orient: LD A,(Vert) ;Adjust Horiz and Vert + LD E,A + CALL CrLft ;Start of first screen line + JR NC,Ornt1 + CALL TopV ;At top, set Vert to 1 + JR Ornt2 +Ornt1: LD A,(Vert) ;Decrement Vert if needed + SUB E ; to avoid whitespace at top + LD (Vert),A +Ornt2: CALL ColCnt ;Update columen (in A,B,CurCol) + INC A + JR NZ,Ornt3 + LD B,0FEH +Ornt3: LD A,(Horiz) ;Compute cursor offset in line + LD C,A + LD A,B + SUB C ;CurCol-Horiz is minimum offset + JR NC,Ornt4a + XOR A ;set 0 if negative +Ornt4a: LD E,A + LD A,(NSkip) ;present offset < min? + CP E + JR C,Ornt4b ;if so, change + CP B ;bigger than CurCol-1? + JR C,Ornt4c ;if not, OK + LD A,B ;round down to small enough + DEC A + AND 0C0H ;multiple of 32 + JR Ornt4c +Ornt4b: LD A,E ;round up to big enough + OR 1FH + JR Z,Ornt4c + INC A +Ornt4c: LD (NSkip),A ;set (new?) offset + SUB B + NEG + LD (Horiz),A + LD HL,(CurLin) ;Figure line, page + LD (CurPgL),HL + LD A,(FMode) + CP 'N' + LD A,(PgLen) + JR NZ,Ornt5 + XOR A ;don't SHOW pagination for nondocs +Ornt5: LD E,A + LD D,0 + DEC HL + LD B,D + LD C,D + OR A ;not paginating? + JR Z,OrnLpF + INC BC +OrntLp: SBC HL,DE + JR C,OrnLpF + INC BC + JR OrntLp +OrnLpF: ADD HL,DE + INC HL + LD (CurPgL),HL + LD (CurPg),BC + RET +; +;Show (just) as much of the text as necessary +; +ShoTx: CALL KyStat ;check keybd + JR NZ,ShoTx1 + CALL TestSc ;check postponed screen disp + JP NZ,ShoAll ;do it! + CALL ShoPos ;quiet? update header + CALL TestCu ;check postponed line disp + JR NZ,DoPost ;do it (or more, if requested) +ShoTx1: LD A,(ShoFlg) ;busy... + OR A ;nothing (0) + RET Z + DEC A + JP Z,ShoRCu ;just one line (1,2) - can be postponed + DEC A + JP Z,ShoCu + DEC A + JP Z,ShoDn ;bottom part (3) + JP ShoSc ;or whole screen +DoPost: LD A,(ShoFlg) + CP 3 + JP C,ShoCu ;at LEAST this + JP Z,ShoDn + JP ShoSc +; +;Show position in file, no matter what +; +ShoPos: LD A,(NoHdrF) + OR A + RET NZ + CALL Force ;must see this + LD DE,DspPg ;Update header + CALL GoTo + CALL MakAlt ;C128 bug fix requires GoTo first + LD HL,(CurPg) + LD A,(FMode) + CP 'N' + CALL NZ,ShPSb1 + LD DE,DspLin + LD HL,(CurPgL) + CALL ShPoSb + LD DE,DspCol + LD A,(CurCol) + LD L,A + LD H,0 + CALL ShPoSb + CALL UnAlt + JP UForce +ShPoSb: PUSH HL ;show a number + CALL GoTo + POP HL +ShPSb1: LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + JP BHLMsg +; +;Show current line only (fast) +; +ShoCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu +ShoCu1: LD A,(Vert) + LD B,A + JP ShoLn +; +ShoRCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu + CALL FetchB + CP TAB ;can't do this with tab at left + JP Z,ShoCu + LD A,(Vert) ;special routine: only RIGHT of cursor + LD D,A ;...modeled on ShoLCu + LD A,(RulFlg) + AND 1 + ADD A,D + LD D,A ;current row + LD A,(Horiz) + DEC A + LD E,A + JP Z,ShoCu ;can't do this at left of screen + DEC E + CALL GoTo ;position to start + LD E,1 ;find start of line + CALL CrLft + PUSH HL + LD HL,Horiz + LD A,(NSkip) + ADD A,(HL) + DEC A + LD D,A + DEC A + LD B,A ;skip till just before cursor + LD A,(View) + INC A + SUB (HL) + LD E,A + INC E + POP HL + CALL ShoLSb ;do part (char!) left of cursor + INC E ;(DON'T ask me why this INC is needed) + LD D,E + DEC D + LD A,(Vert) + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShRCu3 + DEC D +ShRCu3: LD HL,(AftCu) + JP ShoLSb +; +;Display from Cursor line-1 down +; +ShoDn: CALL ConChk ;(postpone if busy!) + JP NZ,HoldSc + LD HL,CsrOff + CALL CtlStr + LD A,(DSFlg) ;(or line-2 if DS) + LD HL,Vert + ADD A,(HL) + JR Z,ShoSc0 + LD B,A + DJNZ ShScLp + JR ShoSc0 +; +;Show everything on emerging from macros etc +; +ShoAll: CALL Orient + CALL DoHdr + CALL ShoPos + JR ShoScX +; +;Display whole text screen (sigh) +; +ShoSc: CALL ConChk ;(Postpone if busy!) + JP NZ,HoldSc +ShoScX: LD HL,CsrOff + CALL CtlStr +ShoSc0: CALL RulFix + CALL SetNo ;kill any pending redisps + XOR A + LD (CuFlg),A + CPL + LD (HorFlg),A + LD B,1 ;Simple method if not memory mapped +ShScLp: PUSH BC + CALL ShoLn + POP BC + INC B + LD A,(TxtLns) + INC A + SUB B + JR NZ,ShScLp + LD HL,CurOn + CALL CtlStr + RET +; +IOoff1: LD DE,DspEsc ;header: blank prompt + CALL GoTo + CALL MakAlt + LD B,4+1 ;(cursor) + CALL BBlank + JP UnAlt +; +IOoff: LD A,(NoHdrF) ;headerless? redo top line + OR A + JR Z,IOoff1 + LD A,(RulFlg) + OR A + JP NZ,RuShow +; +;Show line 1 (to wipe out msgs) +; +ShoLn1: LD B,1 ;fall thru... +; +;Show line number B (=1...TxtLns) +; +ShoLn: LD A,(ShutUp) + OR A + RET NZ + PUSH BC + CALL KyStat ;(helps buffering for slow keyboards) + POP BC + LD A,(RulFlg) + AND 1 + ADD A,B + LD D,A ;position cursor on screen + LD E,0 + PUSH BC + CALL GoTo + POP BC + LD A,(Vert) ;is line before or after cursor? + SUB B + JR Z,ShoLCu ;ouch, it's cursor line + JR C,ShoLAf +ShoLBf: LD E,A ;okay, before + INC E + CALL CrLft + LD A,(View) + INC A + LD E,A + LD A,(NSkip) + LD B,A + LD D,255 + JR ShoLSb +ShoLAf: NEG ;okay, after + PUSH BC ;save line# + LD E,A + CALL CrRit + POP BC + PUSH AF + LD A,(View) + LD D,A + INC A + LD E,A + LD A,(TxtLns) + CP B ;last line? avoid last column + JR NZ,ShLAf0 + DEC D +ShLAf0: POP AF + JR C,ShLAf1 + JR Z,ShLAf2 +ShLAf1: JP ClEOL ;no line! +ShLAf2: LD A,(NSkip) + LD B,A + ADD A,D + LD D,A + JR ShoLSb +ShoLCu: LD E,1 ;hmm, right on cursor + PUSH BC ;save line# + CALL CrLft + LD A,(NSkip) + LD B,A + LD A,(CurCol) ;do part to left + DEC A + LD D,A + LD A,(View) + INC A + LD E,A + CALL ShoLSb + LD D,E + DEC D + POP AF ;line# + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShLCu1 + DEC D +ShLCu1: LD HL,(AftCu) +; +ShoLSb: LD A,D ;Show up to column D of text starting at HL + OR A ;E=room+1, B=Cols to skip (if any) + RET Z + XOR A + EXX + LD B,A ;B',C' keep track of previous chars + LD C,A + LD E,A ;E' is count skipped + EXX + LD C,A ;initialize GetNx + ADD A,B + JR Z,ShLSL2 +ShLSL1: CALL GetNx ;eat skipped columns + JP Z,ClEOL ;end of line? + CP TAB + JR Z,ShLS1T + EXX + INC E ;E' + EXX + DEC D + DJNZ ShLSL1 + CALL ShSvCh + INC D + DEC D + RET Z + JR ShLSL2 +ShLS1T: EXX ;count for tabs + LD A,E + LD HL,TabCnt + AND (HL) + XOR (HL) ;extra spaces + INC A ;plus usual one + PUSH AF + ADD A,E + LD E,A + POP AF + EXX + PUSH AF + SUB D + NEG + LD D,A + POP AF + SUB B + NEG + LD B,A + JR NZ,ShLSL1 + LD A,TAB + CALL ShSvCh + INC D + DEC D + RET Z +ShLSL2: CALL GetNx ;show the rest + EXX + LD C,B + LD B,A + EXX + JR Z,ShLSCr ;take care of CR,TAB + CP ' ' + JR C,ShCtl + PUSH DE + LD E,A + CALL PutCh + POP DE +ShLSL3: DEC E + DEC D + RET Z + LD A,E + DEC A + RET Z + JR ShLSL2 +ShCtl: PUSH HL + PUSH BC + PUSH DE + CP TAB + JR Z,ShLSTb + ADD A,40H ;other ctls are hili letters + EX AF,AF' + CALL AltY ;(mandatory) + EX AF,AF' + CALL PutChA + CALL UnAltY + JR ShLRet +ShLSCr: PUSH HL + PUSH BC + PUSH DE + EXX + LD A,C ;last char + EXX + CP ' ' + JR Z,ShLCrF ;SCR doesn't show + LD A,(HCRFlg) + OR A + JR Z,ShLCrF ;HCRs also MAY not... + LD E,'<' + CALL PutCh + POP DE + DEC D + DEC E + PUSH DE + LD A,E ;don't ClEOL if now in last col + CP 2 +ShLCrF: CALL NC,ClEOL + POP DE ;end of line + POP BC + POP HL + RET +ShLSTb: LD A,(View) ;hit a tab... + INC A + SUB E ;column + LD HL,TabCnt + AND (HL) + XOR (HL) ;figure extra spaces + LD B,A + JR Z,ShLTLF +ShLTbL: CALL PutSpc ;do them + POP DE + DEC E + DEC D + PUSH DE + JR Z,ShLRet + DJNZ ShLTbL ;then one last +ShLTLF: CALL PutSpc +ShLRet: POP DE + POP BC + POP HL + JR ShLSL3 +ShSvCh: EXX ;keep track of prev chars + LD C,B + LD B,A + EXX + RET +; +; +ClEOL: LD HL,CIL ;clear to EOL (quickly if possible) + CALL CtlStr + RET NC +SpEOL: DEC E ;this always SPACES (for attributes) + RET Z +ClELp: LD A,(CurRow) + INC A + LD HL,PhysLn + CP (HL) + JR NZ,ClEL3 + DEC E ;avoid last char on last line + RET Z +ClEL3: CALL PutSpc + DEC E + JR NZ,ClEL3 + RET +; +ClLast: LD A,(PhysLn) ;clear last line on screen + DEC A + LD D,A + LD E,0 + CALL GoToIt + LD A,(View) + LD E,A ;do NOT INC this, it's last line + JR ClEOL +; +; +;Set level of display required +; +SetAl: LD A,0FFH ;routines to set it + JR Set1 ;(must preserve ALL REGS and FLAGS) +SetDn: LD A,3 + JR Set1 +SetCu: LD A,2 + JR Set1 +SetRCu: LD A,1 + JR Set1 +SetNo: XOR A ;this one WILL shut it up... + JR Set2 +Set1: PUSH AF ;...otherwise, do not DEcrease previous requests + EX (SP),HL + LD A,(ShoFlg) + CP H + EX (SP),HL + JR NC,Set3 + POP AF +Set2: LD (ShoFlg),A + RET +Set3: POP AF + RET +; +SmlDly: LD A,(Timer) + LD B,A + LD C,1 + JP BDlyLp +; +ScrUDx: LD A,0C9H ;(RET) + LD (UpLft),A + CALL ScrlUD + CALL NC,SmlDly ; delay if scrolled + LD A,11H ;(LD DE,nnnn) + LD (UpLft),A + RET +; +ScrlU2: LD HL,DelL + CALL ScrlUD + JR C,SetAl ; no scroll + JR SetCu +; +ScrlU: LD HL,DelL + JR ScrlX +; +EdgeU: LD A,(Vert) + DEC A ;first line: scroll + RET NZ +ScrlD: LD HL,InsL +ScrlX: CALL ScrlUD + JR C,SetAl ; no scroll + CALL SmlDly + JR SetCu +ScrlUD: PUSH HL ;[common sbr, used in one-liners too] + CALL TestCu + CALL NZ,ShoCu1 + LD A,(NoHdrF) ;canNOT do this if header is suppressed + LD HL,OddDel ; and ins/del specific to ln 1. + AND (HL) + LD HL,WinFlg ; or if Windowing (in any event) + OR (HL) + POP HL + JR NZ,NoScrl + PUSH HL + CALL UpLft + POP HL + CALL CtlStr ;do it + RET C ;(maybe couldn't) + LD A,(OddDel) + OR A + CALL NZ,RulFix + RET +NoScrl: SCF ; didn't scroll + RET +; +; Set flag for redisplay due to arrow keys +; +EdgeL: LD A,(Vert) + DEC A + RET NZ + LD A,(CurCol) + DEC A + RET NZ + JR ScrlD ;scroll if at top left +EdgeR: CALL Fetch + JR Z,ER01 + LD A,(Horiz) ;not CR: if off right edge, scroll + LD HL,View + CP (HL) + JR Z,HorScl + RET +ER01: LD A,(Vert) ;CR: if at bot right, scroll + LD HL,TxtLns + CP (HL) + JP Z,ScrlU +EdgeD: LD A,(Vert) + LD HL,TxtLns + CP (HL) + JP Z,ScrlU ;last line: scroll + RET +; +;Watch for horizontal scroll +; +IfScl: LD A,(NSkip) ;request scroll if already scrolled + OR A + RET Z +HorScl: CALL SetCu ;request scroll + XOR A + LD (HorFlg),A + RET +; +;Postpone display for speed +; +HoldCu: LD A,0FFH ;save if busy + LD (CuFlg),A + RET +HoldSc: LD A,0FFH + LD (ScFlg),A + RET +TestSc: LD HL,ScFlg ;test & reset postponement + JR TestX +TestCu: LD HL,CuFlg +TestX: XOR A ;(ret with Z if none) + ADD A,(HL) + LD (HL),0 + RET +; +; Position cursor for input +; +Cursr: CALL PosCur ;turn on cursor + CALL Fetch + RET NZ + LD A,(HCRFlg) ;oops, on a CR + OR A ;HCRs showing? + RET Z + CALL FetchB ;got to fix HCR flag + LD E,' ' ;kludge to " " or "<" + CP E + JR Z,Csr01 + CALL NdCnt + JR C,Csr01 + LD E,'<' +Csr01: CALL XPutCh + LD E,BS + JP PutCh +; +; +; Module: SETDS3 +; Version: 1.1 +; Author: Carson Wilson, modifed by Lars Nelson for use with +; ZDE (Dec 3, 2022). +; Date: February 11, 1990 +; +; SETDS3 -- Set file datestamp in CP/M Plus. +; +; Entry: DE = address of file's FCB +; HL = address of datestamp buffer +; BC = address of 1024-byte DMA buffer +; Exit: A = 0, zero flag set (Z), if stamp set +; A = error, zero flag reset (NZ), if error or not CP/M Plus: +; FF = file not found +; 06 = not CP/M Plus +; 05 = no stamps on disk +; 04 = BIOS sector size greater than 1024 bytes +; 03 = drive invalid +; 02 = BIOS read error +; 01 = BIOS write error +; Uses: AF +; Notes: The datestamp buffer should be filled on entry with a valid, eight +; byte CP/M Plus datestamp. It is assumed that the create stamp +; rather than the access stamp is being used. The file +; whose stamp is to be set must either be on the current drive or +; at the drive specified by FCB byte 0. Only files at the current +; user number will be matched. No wildcards allowed. To allow a +; reasonable interface standard, this routine will NOT work under +; systems configured with BIOS sectors larger than 1k. No systems +; exceeding this size have yet been encountered, but BIOS sectors +; of 2k and 4k are technically legal under CP/M Plus. +; +SETDS3: + ld (SAVEIX),ix ; save registers + ld (DMAPTR),bc + ld (FCBPTR),de + ld (STPPTR),hl + xor a + ld (CHGFLAG),a ; Say no changes + ld (SECTOR),a +; +; Set BIOS DMA to ours, get DPH address from BIOS +; + push de ; Save FCB pointer + ld (BCREG),bc + ld a,12 ; Set BIOS DMA to our buffer + ld (FUNC),a + call CALLBIOS + ld c,GDRV ; Get current BDOS disk + call BDOSep + ld (BDOSDRV),a + pop hl ; FCB pointer + ld a,(hl) + or a ; Disk specified? + jr nz,DSKPR1 + ld a,(BDOSDRV) + inc a +DSKPR1: dec a + ld (DRVCOD),a ; Save code for reset later + ld c,a ; Disk number + ld e,0 ; Flag initial select + ld (BCREG),bc ; BIOS select disk function + ld (DEREG),de + ld hl,0 + ld (HLREG),hl ; Required by Morrow BIOS (bug?) + ld a,9 ; 'SELDSK' + ld (FUNC),a + call CALLBIOS + ld a,h + or l ; Check for drive error + jp z,DRVER ; Quit if so + ld e,(hl) ; Get DPH address + inc hl + ld d,(hl) + ld (XLTADD),de ; Save address of XLT + ld bc,11 + add hl,bc ; HL --> .DPB + ld e,(hl) + inc hl + ld d,(hl) ; DE --> DPB + ex de,hl + ld e,(hl) ; Get logical SPT + inc hl + ld d,(hl) + ld (SPT),de + ld de,3 ; Offset to EXM (# of extents/entries-1) + add hl,de ; Add offset + ld a,(hl) ; Get EXM + ld (EXM),a + ld de,3 ; Offset to DRM (# of directory entries) + add hl,de ; Add offset + ld e,(hl) ; Get DRM + inc hl + ld d,(hl) + push de ; Save DRM + push hl ; Save .highDRM + ld de,7 ; Point to PSH + add hl,de + ld a,(hl) ; Get it + ld (PSH),a ; Save it + pop de ; Get .highDRM + pop hl ; Get DRM + inc hl ; Add 1 for total directory entries + ld a,(PSH) + cp 4 + jp nc,PHYSER ; Physical sector size > 1024 + inc a + inc a + ld b,a + call DIVHLB + ld (DVD),a + ld a,l ; Save # of directory sectors + ld (DIRSEC),a + ld hl,(SPT) ; Logical sectors per track + ld a,(PSH) + ld b,a + call DIVHLB + ld a,l ; PHSPT = SPT for 128 byte sectors + ld (PHSPT),a ; Physical sectors per track + ld hl,5 ; Add offset to # of reserved tracks + add hl,de + ld e,(hl) ; Get number of reserved tracks + inc hl + ld d,(hl) + ld (RESTKS),de ; Save reserved tracks for later + ld c,USRN ;set or get user function # + ld e,0FFh ; Get + call BDOSep ;get user # in A + ld hl,(FCBPTR) + ld (hl),a ; Stuff to match dir. entry +; +; Now copy Caller's stamp to STPBUF + ld hl,(STPPTR) ; Caller's stamp + ld de,STPBUF ; Put it here + ld bc,8 ; Move 8 bytes only + ldir +; +; GETDIR - Read a physical sector of the directory to our buffer +; +GETDIR: ld a,(DIRSEC) ; Get # of directory sectors remaining + or a + jp z,EXIT3 ; Return if none + call PHSECTRK ; Compute cur. physical sector and track + ld bc,(RESTKS) ; Get number of reserved tracks in BC + ld h,0 ; Get physical track number in HL + ld a,(PHTRK) + ld l,a + add hl,bc ; Directory track in HL + ld (BCREG),hl ; Set track to directory + ld a,10 ; SETTRK + ld (FUNC),a + call CALLBIOS + ld a,(PHSECT) ; Get current physical sector + ld c,a + call TRNSEC ; Translate sector if necessary + ld b,0 + ld (BCREG),bc ; Point to current sector + ld a,11 ; SETSEC + ld (FUNC),a + call CALLBIOS + ld a,13 ; Read sector of directory + ld (FUNC),a + call CALLBIOS + or a + jp nz,RDERR ; Read error +; +; Check entries for match. Modify and write back if match found. +; + xor a ; Zero flag + ld (RECFLG),a + ld (OFFST),a ; Offset of entry in directory record + ld a,(DVD) ; Get number of dir. entries per sector + ld b,a + ld hl,(DMAPTR) +CKNXT: push bc + ld de,(FCBPTR) + call COMP12 ; Match? + jp nz,GETNXT ; No +; HL points to buffer location of our entry + push hl + push bc + ld a,(OFFST) + add a,a + add a,a + add a,a + add a,a + add a,a ; x32 + ld b,0 + ld c,a + sbc hl,bc ; HL --> start of record + ld bc,60h + add hl,bc ; Now find stamp in record + ld a,(OFFST) + add a,a + ld b,a + add a,a + add a,a + add a,b ; *10 + inc a ; +1 + ld b,0 + ld c,a + add hl,bc ; HL --> our file's stamp + ld de,STPBUF + ex de,hl + ld bc,8 + ldir ; Copy STPBUF --> SECTOR + pop bc + pop hl + ld a,1 ; Set changed flag + ld (RECFLG),a + ld (CHGFLAG),a +GETNXT: ld a,(OFFST) + inc a +GETNX1: ld (OFFST),a + ld de,32 ; Advance to next entry + add hl,de + ld a,(hl) + cp '!' ; Stamp? + jr nz,GETNX2 ; No + pop bc ; Yes, skip + dec b ; Decrement entry count + jr z,GETNX3 ; Stop if done + push bc + xor a ; Reset OFFSET + jr GETNX1 +; +GETNX2: pop bc + ld a,(OFFST) + cp 3 + jp nc,NOSTER ; No stamps if 4 consecutive entries lack '!' + djnz CKNXT ; Decrement counter +GETNX3: ld a,(RECFLG) ; Check for changed entry + or a ; Write? + jr nz,WRTSEC ; Yes, finish up + ld a,(DIRSEC) ; Nope, decrement physical directory sectors + dec a + ld (DIRSEC),a + ld a,(SECTOR) ; Increment sector + inc a + ld (SECTOR),a + jp GETDIR ; Back for another +; +; Write sector back to disk and quit +; +WRTSEC: ld bc,1 ; Non-deferred write + ld (BCREG),bc + ld a,14 ; Write + ld (FUNC),a + call CALLBIOS ; Update directory + or a ; Check for write error + jp nz,WRTER + ld a,(DRVCOD) ; Reset drive (0..15) + ld hl,1 + and a ; Ready if drive A + jr z,RESETT + ld b,a +ADDHL: add hl,hl ; Else calculate vector + djnz ADDHL +RESETT: ex de,hl + ld c,37 ; Tell BDOS to log out drive + call BDOSep + jr EXIT3 ; Return to caller +; +; EXIT ROUTINES +; +NOSTER: ld a,6 ; No stamps + jr EXIT1 +; +PHYSER: ld a,5 ; Sector size > 1024 + jr EXIT1 +; +DRVER: ld a,4 ; Drive invalid + jr EXIT1 +; +RDERR: ld a,3 ; BIOS read error + jr EXIT1 +; +WRTER: ld a,2 ; BIOS write error + jr EXIT1 +; +EXIT3: ld a,(CHGFLAG) +EXIT1: dec a ; (NZ) means error + push af +; restore drive in fcb + ld a,(DRVCOD) ; 0-15 + inc a ; make it 1-16 + ld hl,(FCBPTR) ; point to fcb + ld (hl),a ; restore drive + ld a,(BDOSDRV) ; Re-synchronize BIOS w/BDOS + ld c,a ; Disk number + ld e,1 ; Not initial select + ld (BCREG),bc ; BIOS select disk function + ld (DEREG),de + ld hl,0 + ld (HLREG),hl ; Required by Morrow BIOS (bug?) + ld a,9 ; 'SELDSK' + ld (FUNC),a + call CALLBIOS + pop af ; Restore result code + ld bc,(DMAPTR) ; restore all registers + ld de,(FCBPTR) + ld hl,(STPPTR) + ld ix,(SAVEIX) + ret ; Return to caller +; +; SUBROUTINES +; +COMP12: ; Compare 12 bytes directory entry @HL + push de ; ..with FCB @DE + push hl + push bc + ld b,12 +COMP12A: + ld a,(de) + sub (hl) + and 01111111b ; Ignore high bits + jr nz,COMPX ; Unequal + inc hl + inc de + djnz COMP12A ; RETURN (Z) if match + ld a,(EXM) ; Make sure we're at first entry + cp (hl) + ld a,0 + jr nc,COMP12B ; At first if <= EXM + ld a,0FFh ; Otherwise no match +COMP12B: + or a +COMPX: pop bc + pop hl + pop de + ret +; +; Divide HL by 2^B, A = 2^B on exit +; +DIVHLB: ld a,1 +DIVHL1: add a,a ; Double A, zero (C) + rr h + rr l + djnz DIVHL1 + ret +; +PHSECTRK: + ld c,0 ; Set 'PHTRK' to 0 + ld a,(PHSPT) + ld b,a ; Phys SPT in 'B' + ld a,(SECTOR) ; Logical directory sector +CKPHTRK: + cp b ; Compute PHSECT = sectors mod PHSPT + jr c,STSECTRK ; And PHTRK = (sectors - PHSECT)/PHSPT + sub b + inc c + jr CKPHTRK +STSECTRK: + ld (PHSECT),a + ld a,c + ld (PHTRK),a + ret +; +TRNSEC: ld hl,(XLTADD) ; Get translate table address + ld (DEREG),hl + ld (BCREG),bc + ld a,16 ; SECTRAN + ld (FUNC),a + call CALLBIOS + ld c,l + ret +; +CALLBIOS: ; CP/M v3.0 direct BIOS call + ld c,GOBIOS + ld de,FUN50 + call BDOSep + ret +; +; MESSAGES +; +ErrTab: DW 0,MSG1,MSG2,MSG3,MSG4,MSG4,MSG7,MSG7,MSG8,MSG9 +; +MSG1: DB 'Ou','t'+X,'o','f'+X,'Memory',0 +MSG2: DB 'Invali','d'+X,'Key',0 +MSG3: DB 'I/','O'+X ;(fall through to 7) +MSG7: DB 'Error',0 +MSG4: DB 'No','t'+X,'Found',0 +MSG8: DB 'Synta','x'+X,'Error',0 ;(note 5,6 not used) +MSG9: DB 'Canno','t'+X,'Reformat',0 ;(note error 10 has no MSG) +; +NameQ: DB 'Name',':'+X,0 +ReadQ: DB 'Read',':'+X,0 +WritQ: DB 'Write',':'+X,0 +EraQ: DB 'Erase',':'+X,0 +LoadQ: DB 'Load',':'+X,0 +FindQ: DB 'Find',':'+X,0 +ChgQ: DB 'Chang','e'+X,'to',':'+X,0 +DirQ: DB 'Dir',':'+X,0 +PrtQ: DB 'Options',':'+X,0 +PgLnQ: DB 'Length',':'+X,0 +ColQ: DB 'Column',':'+X,0 +PageQ: DB 'Page',':'+X,0 +LineQ: DB 'Line',':'+X,0 +MacroQ: DB 'Macro',':'+X,0 +RptcQ: DB 'Repea','t'+X,'coun','t'+X,'([Q],0-9/*)',':'+X,0 +KeyQ: DB 'Ke','y'+X,'numbe','r'+X,'([N/Q],0-9)',':'+X,0 +QuitQ: DB 'Abando','n'+X,'changes','?'+X,'(Y/N)',':'+X,0 +UnchgQ: DB 'Unchanged',';'+X,'save','?'+X,'(Y/N)',':'+X,0 +; +; Changed: Q File size: NNNNN Memory used: NNNNN Free: NNNNN +InfMsg: DB CR + DB ' '+X,'Changed',':'+X +ModQQQ: DB 'Q',X,7,'Fil','e'+X,'size',':'+X +SizNNN: DB 'NNNNN',X,5,'Memor','y'+X,'used',':'+X +UsdNNN: DB 'NNNNN',X,5,'Free',':'+X +FreNNN: DB 'NNNNN',CR,0 +; +; [Menus disabled; see VDE.DOC or .QRF] +; [See VDE.DOC and .QRF for help] +; +HlpMsg: DB X,26,'[Menu','s'+X,'disabled',';'+X,'se','e'+X + DB 'Manual]',CR,0 +; +;A4/DOC:FILENAME.TYP /A Pg 1 Ln 1 Cl 51 INS vt by AO DS scr top ^QY del to EOL ^QF Find +; ^QP to Place mk ^Q scr bot ^QDel " to BOL ^QA replAce +; ^QR goto TOF ^Q ln start ^QT del to char ^QP to last cursor +; ^QC goto EOF ^Q ln end ^QU UNdel line ^QI goto pg/ln +; ^QQ goto ZCPR queue line +; +QMenu: DB X,4,'^Q','B'+X,'got','o'+X,'Block',X,4,'^Q'+X,'sc','r'+X,'top' + DB X,5,'^Q','Y'+X,'de','l'+X,'t','o'+X,'EOL',X,4,'^Q','F'+X,'Find',CR + DB X,4,'^Q','Z'+X,'t','o'+X,'plac','e'+X,'mk',X,3,'^Q'+X,'sc' + DB 'r'+X,'bot',X,5,'^QDe','l'+X,'"'+X,'t','o'+X,'BOL',X,4,'^Q','A'+X + DB 'replAce',CR + DB X,4,'^Q','R'+X,'got','o'+X,'TOF',X,6,'^Q'+X,'l','n'+X,'start' + DB X,4,'^Q','T'+X,'de','l'+X,'t','o'+X,'char',X,3,'^Q','P'+X,'t','o'+X + DB 'las','t'+X,'cursor',CR + DB X,4,'^Q','C'+X,'got','o'+X,'EOF',X,6,'^Q'+X,'l','n'+X,'end' + DB X,6,'^Q','U'+X,'UNde','l'+X,'line',X,4,'^Q','I'+X,'got','o'+X + DB 'Pg/Ln',CR + DB X,'(^Q','Q'+X,'got','o'+X,'ZCP','R'+X,'queu','e'+X,'line',CR,0 +; +;^OL,R marg set ^OI tab set ^OP Page length ^O make top ln ^OA Auto-in +; ^OX marg rel ^ON tab clr ^OS dbl Spacing ^OW Window ^OQ Quiet +; ^OC Center ^OV Vari tabs ^OH Hyphenation ^OJ proportional +; ^OF Flush rt ^OT ruler ^OD Display CRs ^OZ Zap screen +; +OMenu: DB '^OL,','R'+X,'mar','g'+X,'set',X,2,'^O','I'+X,'ta','b'+X,'set' + DB X,4,'^O','P'+X,'Pag','e'+X,'length',X,2 + DB '^O'+X,'mak','e'+X,'to','p'+X,'ln',X,2,'^O','A'+X,'Auto-in',CR + DB X,2,'^O','X'+X,'mar','g'+X,'rel',X,2,'^O','N'+X,'ta','b'+X,'clr' + DB X,4,'^O','S'+X,'db','l'+X,'Spacing',X,4,'^O','W'+X,'Window',X,7 + DB '^O','Q'+X,'Quiet',CR + DB X,2,'^O','C'+X,'Center',X,4,'^O','V'+X,'Var','i'+X,'tabs' + DB X,2,'^O','H'+X,'Hyphenation',X,4,'^O','J'+X,'proportional',CR + DB X,2,'^O','F'+X,'Flus','h'+X,'rt',X,2,'^O','T'+X,'ruler' + DB X,6,'^O','D'+X,'Displa','y'+X,'CRs' + DB X,4,'^O','Z'+X,'Za','p'+X,'screen',CR,' ',CR,0 +; + DS 4 +MnuEnd: ;menus end here, text can begin + END + \ No newline at end of file diff --git a/Source/Apps/ZDE/zde19.z80 b/Source/Apps/ZDE/zde19.z80 new file mode 100644 index 00000000..492317e5 --- /dev/null +++ b/Source/Apps/ZDE/zde19.z80 @@ -0,0 +1,8598 @@ + ;Assembles with Al Hawley's ZMAC and loads with MLOAD + ; ZMAC ZDE18 /H + ; MLOAD ZDE18.COM=ZDE18.HEX + ;Assembles with SLR's Z80ASM directly to COM file + ; Z80ASM zde18 + ;Assembles with ZASM (Cromemco ASMB) & loads with MLOAD +; .Z80 ;Uncomment these two lines and rename +; ASEG ;to ZDE18.MAC for M80 + ;(use RELHEX to convert ZDE18.REL to ZDE18.HEX) + ;then generate ZDE18.COM with MLOAD. +; +;*** ZDE assembly sequence +; +CR EQU 0DH ;ASCII stuff +LF EQU 0AH +FF EQU 0CH +BS EQU 08H +TAB EQU 09H +ESC EQU 1BH +DEL EQU 7FH +BEL EQU 07H +EOF EQU 1AH +X EQU 80H ;hibit +; +BDOSep EQU 0005h ;BDOS stuff +FCB EQU 005Ch +FCBt1 EQU FCB+9 +FCBex EQU FCB+12 +FCBs1 EQU FCB+13 +FCBd0 EQU FCB+16 +FCBcr EQU FCB+32 +FCBr0 EQU FCB+33 +FCBr1 EQU FCB+34 +FCBr2 EQU FCB+35 +DMA EQU 0080h +; +LSTO EQU 5 +UCON EQU 6 +CPMV EQU 12 ;return version number +RSTD EQU 13 ;reset drives +SELD EQU 14 ;select drive +FOPN EQU 15 ;open file +FCLO EQU 16 ;close file +SRCH EQU 17 ;search for first +SRCN EQU 18 ;search for next +FDEL EQU 19 ;delete file +RSEQ EQU 20 ;read next record +WSEQ EQU 21 ;write next record +FMAK EQU 22 ;create file +FREN EQU 23 ;rename file +GDRV EQU 25 ;get current drive +SDMA EQU 26 ;set dma address +USRN EQU 32 ;get/set user number +RSTV EQU 37 ;selectively reset drives +ERRM EQU 45 ;set error mode +DOSV EQU 48 ;return extended version +GOBIOS EQU 50 ;CP/M3 BIOS call +FTRU EQU 99 ;set time(ZSDOS)?or truncate file (CP/M#)? +GETF EQU 100 ;get flags +SETF EQU 101 ;set flags +GETS EQU 102 ;get stamp +SETS EQU 103 ;set stamp +; +Z3NdrL EQU 16 ; length of NDR dir/pwdstring +Z3NdrM EQU 8 ; length of NDR name to match +Z3NDR EQU 0015H ; offset to NDR address in Z3ENV +Z3MSG EQU 0022H +MsgUsr EQU 64 ; User area offset in message buffer +MsgNmU EQU 16 ; # of user registers +TPAful EQU 12 ; Z33 TPA full error code +ErrBit EQU 00000010B +EcpBit EQU 00000100B +ExtBit EQU 00001000B +; +;ErrSta is the value to be returned in the Z33 Message Buffer command +;status to inform the command processor that an error has occurred in +;an external program and that the error handler should be invoked. +; +ErrSta EQU ErrBit+EcpBit+ExtBit +; +;*** ZDE.ASM - Z-System Display Editor +;*** Universal Version - (c)1988 Eric Meyer +;*** Z-System Version - (c)1989 Carson Wilson +; ------------------- +; VDE,VDE-2 - 9-12/84 - Enhanced VDO, added functions +; VDE-OS,OX - 7/85-1/86 - Small additions and fixes +; VDE-PX - 7-9/85 - Epson Geneva terminal version +; VDE 1.2-3 - 9/85-1/86 - Generic terminal version +; VDE/M 2.0 - 4/86 - Generic memory map version; CP/M+ support; additions +; 2.1 - 6/86 - New Keys 0-9; window; undo; directory; new pagination, +; compression, block marker, scroll; etc. +; 2.2 - 8/86 - WS-like commands; left mrgn, hyphenation; macros +; 2.3 - 9/86 - VINSTALL; Print options; word fns; real ^QA; RstDrv +; 2.4 - 1/87 - vidRAM/window redone; "W" mode; ^OZ,^QP; block print +; 2.5 - 3/87 - User#s; "N" mode; ^OS, ^OV/+/-; new block fns; hard-CRs +; 2.6 - 7/87 - Allow blank filename; ^U abort; new toggles; ruler; +; ^O; AltBit fixes; works w/o curpos; key buffer; faster +; scrolling; case insensitive searches; no fake "VIDRAM" +; 2.61 - 8/87 - Bug fixes (incl FastFi), improved hyphenation +; 2.62 - 11/87 - ^JKL synonyms; ^W prefix; ^OH; several small fixes +; 2.63 - 1/88 - ^KV; WS style ^W/^Z; chgs to ^OP, ^OI/N, word fns +; 2.64 - 3/88 - ^OQ,^QT,^QI; ^KD; ^QA fixes; dbl spc; top margin; +; backward find; ShoRCu +; 2.65 - 4/88 - ^OI/N args; Esc-TAB; ^OA; menu removal; minor fixes +; 2.66 - 6/24/88 - Printer margins; Minor fixes. LAST RELEASE! +; 2.67b - 10/14/88 - Minor fixes +; ZDE 1.0 - 3/10/89 - Z-System Display Editor +; 1.3 - 8/26/89 +; 1.6 - 6/2/90 +; 1.6 - 11/19/20 - ZDE 1.6 source reconstituted using VDE 2.67 +; source as a guide - MECPARTS +; 1.7 - 11/21/20 - Incorporated Al Hawley's timestamp fixes - MECPARTS +; 1.8 - 12/03/22 - Added ability to retain file create datestamp +; on CP/M+ systems. - Lars Nelson +; 1.9 - 03/27/25 - Added support for ANSI PgUp, PgDn, Home, & End +; Support ANSI F1 key for menu/error escape +; - Peter Onion +; ------------------- +; + ORG 0100H +; + JP Start ;Entry and exit vectors + DB 'Z3ENV' + DB 1 +Z3Env: DW 0 +Boot: JP 0 + DW 0 +; +;Following VINSTALL data MUST be at 0110-0121 +; + DW 1006H ;Version compatibility + DW UsrPat + DB UPatL + DW PSTbl + DB PsL + DW MnuSt + DW KMnuSt + DW EMnuSt + DW OMnuSt + DW QMnuSt + ;version message (28 chars, used in menu) +; [----5----10---15---20---25--] +VersID: DB 'ZDE 1.9, Copr. 1990 C.Wilson',0 +; +; +;USER PATCHABLE VALUES +; + ORG 0140H +BAKFlg: DB 0FFH ;0140H - create BAK files (y/n) +DFMode: DB 'A' ;default file modem W/A/N +FDflt1: DB 'Z80N' ;1st default override +FDflt2: DB 'WS W' ;2nd +FDflt3: DB 'CMDN' ;3rd +FDflt4: DB 'LIBN' ;4th +InsFlg: DB 0FFH ;defulat insert on (y/n) +RulFlg: DB 0FFH ;default rules on (y/n) +HCDflt: DB 0FFH ;default HCR disp on (y/n) +HypFlg: DB 0FFH ;enable hyphenation (y/n) +PSFlg: DB 0 ;default proportional flag (y/n) +PSokFl: DB 0FFH ;default allow proportional flag (y/n) +DfltLM: DB 1 ;left margin column (1=OFF) +DfltRM: DB 65 ;right margin column (1=OFF) +Ovlap: DB 2 ;scroll overlap (0=none) +DirSys: DB 0 ;include SYS files (y/n) +FixDsk: DB '@@' ;fixed drives +Ring: DB 0FFH ;error ring bell (y/n) +Help: DB 0FFH ;use help menus (y/n) +AltHdr: DB 0FFH ;use alt video in header (y/n) +NoHdrF: DB 0 ;suppress header +MHz: DB 40H ;clock speed (40h=4MHz) +Timer: DB 38H ;horiz scroll delay (01..FF) +TabCnt: DB 7 ;hard tab cols -1 (1/3/7/15) +VTList: DB 6,11,16,21 ;variable tab columns (8) + DB 0,0,0,0 +VTNum EQU $-VTList +WildCd: DB EOF ;wildcard character +BlkChr: DB 0 ;block characters (^@) +TogTbl: DB 02H,04H,13H,19H ;toggles ^B,^D[^T],^S,^Y +NTgTbl: DB 11H,17H,5,12H ;switches ^Q,^W,^E,^R (last 015C) +; +;INSTALLATION +; + ORG 180H +Z3tcap: DB 'Generic CRT ' ;ID + ORG 190H +View: DB 80 ;viewable columns (max 128) +AuWrap: DB 0FFH ;does autowrap cursor +Lines: DB 24 ;lines +UsrKys: DB 0FFH ;DEL key + DB 0FFH ;arrow up + DB 0FFH ;arrow down + DB 0FFH ;arrow right + DB 0FFH ;arrow left + DB 0 +CIL: DB 0,0,0,0,0,0,0 ;clear to end of line, 6 bytes +TInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal init, 7 bytes +TUInit: DB 1,'Z'-40H,0,0,0,0,0,0 ;terminal uninit +AltOn: DB 0,0,0,0,0,0,0 ;alt video on, 6 bytes +AltOff: DB 0,0,0,0,0,0,0 ;alt video off +AltBit: DB 0 ;high bit gives alt video? +Filter: DB 7FH ;highest ASCII to send to screen +PosMod: DB 'N' ;curpos mode (Std/Rev/ANSI/None) +PCu: DB 1EH,0,0CH,0 ;position cursor to (0,0) +PosDly: DB 0 ;delay after curpos (00-FF) +InsL: DB 0,0,0,0,0,0,0 ;insert line [1], 6 bytes +DelL: DB 0,0,0,0,0,0,0 ;delete line [1], 6 byts +OddDel: DB 0 ;ins/del line specific? +CsrOff: DB 0,0,0,0,0,0,0 ;cursor off +CurOn: DB 0,0,0,0,0,0,0 ;cursor on +; + ORG 01F0H ;Printer codes + DB 'Teletype ' ;ID + ORG 0200H +UseLF: DB 0FFH ;use LF after CR in print? +FormL: DB 54 ;form length (0=no pag) +PTMarg: DB 0 ;top margin skip +DotPO: DB 0 ;left margin skip +PInit: ;printer init, 19 bytes + ORG 0218H +PUInit: ;printer uninit, 7 bytes + ORG 0220H +PCodes: DB 0,0,0,0,0,0,0,0 ;^B toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^T [^D] toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^S toggle on + DB 0,0,0,0,0,0,0,0 ;...and off + DB 0,0,0,0,0,0,0,0 ;^Y toggle on + DB 0,0,0,0,0,0,0,0 ;...and off +UCodes: DB 0,0,0,0,0,0,0,0 ;sw 1 (^Q) + DB 0,0,0,0,0,0,0,0 ;sw 2 (^W) + DB 0,0,0,0,0,0,0,0 ;sw 3 (^E) + DB 0,0,0,0,0,0,0,0 ;sw 4 (^R) +; + ORG 0280H +UsrPat: ;0280-02AFH - User Patch Area +;(Can extend back into UCodes section if fewer switches used) +; + ORG 02B0H ;02B0-030EH - Proportinal table +UPatL EQU $-UsrPat +PSTbl: DB 0,-12, 0, 0, 0, 6, 6,-12 ;" "-";" + DB -6, -6, 0, 0,-12, 0,-12, 0 ;"("-"/" + DB 0, 0, 0, 0, 0, 0, 0, 0 ;"0"-"7" + DB 0, 0,-12,-12, 0, 0, 0, 0 ;"8"-"?" + DB 6, 6, 6, 6, 6, 6, 6, 6 ;"@"-"G" + DB 6, -6, 0, 6, 6, 12, 6, 6 ;"H"-"O" + DB 6, 6, 6, 6, 6, 12, 6, 12 ;"P"-"W" + DB 6, 6, 0, -6, 0, -6, 0, 0 ;"X"-"_" + DB -12, 0, 6, 0, 6, 0, -6, 6 ;"'"-"g" + DB 6,-12, -6, 6,-12, 12, 6, 0 ;"h"-"o" + DB 6, 6, 0, 0, -6, 6, 6, 12 ;"p"-"w" + DB 0, 6, 0, -6,-12, -6, 0 ;"x"-"~" +PsL EQU $-PSTbl +; + ORG 0310H ;0310-04AFH - Macro keys +Keys: DS 2 ;free count (VDE does this) + DS 510 +KT: +; +; +;----- EXECUTION BEGINS HERE ------- +; + ORG 0510H +; +Start: SUB A ;check for Z80 + RET PE + LD SP,Stack + LD HL,Data ;zero out data area + LD DE,Data+1 + LD BC,DataLn-1 + LD (HL),0 + LDIR + LD C,CPMV ;get cp/m version in A + CALL BDOSep + LD (DOSVer+1),A ;save CP/M version + CP 30H + JR NC,ItsCP3 + LD C,DOSV ; get extended dos version + CALL BDOSep ; what kind of enhanced BDOS + LD A,H + CP 'S' + JR Z,ZxDOS + CP 'D' + JR NZ,ItsCP3 +ZxDOS: LD (DOSVer+1),A ; store ZS/ZDDOS version + LD C,GETF ; get ZSDOS flags + CALL BDOSep + LD (ZDflgs+1),HL + EX DE,HL + RES 1,E ; public files are R/O + LD C,SETF + CALL BDOSep ; set ZSDOS flags +ItsCP3: CALL DOSVer + LD C,ERRM ; set action on hardware error + LD E,0FEH ; return error code to program + CALL NC,BDOSep ; for anything other than CP/M 2.2 + LD C,GDRV + CALL BDOSep ;save logged drive + LD (CurDsk),A + INC A + LD (FCB),A ; store A=1..P=16 in FCB->drive + LD C,USRN ;and user + LD E,0FFH + CALL BDOSep + LD (CurUsr),A + LD (FCBU),A + LD A,(Lines) + LD (PhysLn),A + CALL AdjLns + LD A,(FormL) + LD (PgLen),A + LD HL,(DfltLM) + LD (LfMarg),HL + LD A,(BlkChr) + LD (BadTbl),A + LD A,(UseLF) + CPL + OR LF + LD (LFChr),A + LD HL,MacStr + DEC (HL) ;make a FF terminator + XOR A ;a bad load will exit and invoke Z33's + LD (BadLdX+1),A ;error handler +; + LD HL,DMA + LD A,(HL) + INC HL + CALL Parse ;parse command line +; + CALL VerKey ;verify keys + LD HL,TInit + CALL CtlStr ;Clear and home cursor + JR Edit ;start editing. +; +;Clear it all out and start over. +; +Restrt: LD A,1 ;a bad load will not exit and invoke + LD (BadLdX+1),A ;Z33's error handler + LD HL,LoadQ + CALL NewNam + LD A,(EdErr) ;bad name? + OR A + JR NZ,BadLdX +; +;Start editing a File +; +Edit: CALL IniRAM ;initialize memory + CALL DfltM ;adjust defaults + CALL DoHdr ;show header + CALL Top ;Start at TOF + CALL Error0 ;No errors + LD A,(FCB+1) + CP ' ' ;Filename blank? + JR Z,Edit1 + CALL SavNam ;save it for LoadIt kludge + CALL LoadIt ;Get input file + LD A,(EdErr) + CP 1 ;is it too big? + JR NZ,Edit1 +BadLdX: LD A,0 ;a non-zero value will set up Z33's message + OR A ;buffer to have the Z33 error handler handle + JR NZ,BadLd ;the 'TPA full' condition when we exit + LD BC,Z3MSG + CALL Z3EAdr + JR Z,BadLd + LD H,B + LD L,C + LD (HL),TPAful ; Z3MSG error byte: file too big + INC HL + INC HL + INC HL ; point HL at Z3MSG command status byte + LD (HL),ErrSta ; error, ECP running, external invocation + JP QuitY +BadLd: CALL DoErr ;Too big, or bad name + CALL BlkFCB ;(Other error means new file) + JR Edit +Edit1: LD A,(MSIFlg) ;set up BAKflag + LD HL,BAKFlg + AND (HL) + LD (FilFlg),A + XOR A + LD (Modify),A +; +Reset: LD SP,Stack ;recover from ^U prompt abort + CALL ShoLn1 +; +; +;MAIN LOOP: SHOW TEXT, GET KEY +; +Ready: CALL Orient ;Get bearings + LD HL,(OldLin) ; ### + LD (SavLin),HL ; ### + LD A,(OldCol) ; ### + LD (SavCol),A ; ### + LD A,(MacFlg) ; ### + OR A ; ### + JR NZ,RdyMac ; ### + LD HL,(CurLin) ; ### + LD (OldLin),HL ; ### + LD A,(CurCol) ; ### + LD (OldCol),A ; ### +RdyMac: CALL ShoTx ; then show text as needed + CALL Cursr ;position cursor + CALL TRptKy ;Get input + PUSH AF + CALL Error0 ;Clear error indicator + CALL SetNo ;default NO redisp + POP AF + CALL AdjKey ;translate arrows/DEL +; +DoKey: CALL Case ;try to match control code? + DB MnuLn/3 + DW IChar ;Default : Insert character +MnuSt EQU $ + DB 0 ;(internal use: null key) + DW CKCan + DB 80H ;DEL + DW Delete + DB 81H ;Up arrow + DW Up + DB 82H ;Down + DW Down + DB 83H ;Right + DW Right + DB 84H ;Left + DW Left + DB ESC + DW Escape + DB '^'-40H + DW UpLow + DB '\'-40H + DW Repeat ;Synonym for ^L + DB 'A'-40H + DW WordLf + DB 'B'-40H + DW Reform + DB 'C'-40H + DW PageF + DB 'F'-40H + DW WordRt + DB 'G'-40H + DW EChar + DB 'I'-40H + DW TabKey + DB 'J'-40H + DW DoMnu + DB 'K'-40H + DW CKKey + DB 'L'-40H + DW Repeat + DB 'M'-40H + DW ICR + DB 'N'-40H + DW ICRA + DB 'O'-40H + DW Onscrn + DB 'P'-40H + DW CtlP + DB 'Q'-40H + DW Quick + DB 'R'-40H + DW PageB + DB 'T'-40H + DW WordDl + DB 'U'-40H + DW Undel + DB 'V'-40H + DW IToggl + DB 'W'-40H + DW Scr1LU + DB 'Y'-40H + DW Eline + DB 'Z'-40H + DW Scr1LD +MnuLn EQU $-MnuSt +; +Sk1Ed: LD A,(EdErr) ;Check for error, repeat main loop + OR A + CALL NZ,DoErr + JP Ready +; +;Block commands: ^K toggle is on +; +CKKey: LD HL,CKTog + CALL Prefix +CKSyn: CALL XCase ;Entry for ESC synonyms + CALL Case + DB KMnuLn/3 + DW Error2 ;complain if unknown +KMnuSt EQU $ + DB 'B'-40h + DW Block + DB 'C'-40h + DW Copy + DB 'D'-40h + DW Done + DB 'E'-40h + DW Era + DB 'F'-40h + DW Dir + DB 'H'-40h + DW DoMnu + DB 'I'-40h + DW Info + DB 'K'-40h + DW Termin + DB 'L'-40h + DW Load + DB 'N'-40h + DW ChgNam + DB 'P'-40h + DW Print + DB 'Q'-40h + DW Quit + DB 'R'-40h + DW Read + DB 'S'-40h + DW Save + DB 'U'-40h + DW Unmark + DB 'V'-40h + DW MovBlk + DB 'W'-40h + DW Write + DB 'X'-40h + DW Exit + DB 'Y'-40h + DW EBlock + DB ESC + DW CKCan + DB ' ' + DW CKCan +KMnuLn EQU $-KMnuSt +CKCan: RET +; +;ESC commands: ESC toggle is on. +; +Escape: LD HL,ESCTog + CALL Prefix + CALL AdjKey + CALL UCase + CP '0' + JR C,Esc01 ;macro Keys: special case + CP '9'+1 + JP C,UseKey +Esc01: CALL Case + DB EMnuLn/3 + DW CKSyn ;default: ^K synonym +EMnuSt EQU $ + DB 81H ;Up arrow + DW ShftU + DB 82H ;Down + DW ShftD + DB 83H ;Right + DW ShftR + DB 84H ;Left + DW ShftL + DB '[' ;ANSI cursor sequences + DW ANSIcu + DB TAB + DW TaBack + DB 'M' + DW DoMac + DB '#' + DW MacKey + DB '!' ;macro prog stmts + DW MacJmp + DB '=' + DW MacTst + DB '~' + DW MacTsX + DB '+' + DW ChainK + DB ';' + DW Wait +EMnuLn EQU $-EMnuSt + RET +; +;Onscreen commands. ^O toggle is on. +; +Onscrn: LD HL,COTog + CALL Prefix + CALL XCase ;force to ctl + CALL AdjKUp ;adjust UP ARROW ONLY + CALL Case ;What function? + DB OMnuLn/3 + DW Error2 ;complain if unknown +OMnuSt EQU $ + DB 81H ;up + DW MakTop + DB 'A'-40h + DW AITog + DB 'C'-40h + DW Center + DB 'D'-40h + DW HCRTog + DB 'F'-40h + DW Center ;same fn as 'C' + DB 'H'-40h + DW HypTog + DB 'I'-40h + DW VTSet + DB 'J'-40h + DW PSTog + DB 'L'-40h + DW SetLM + DB 'N'-40h + DW VTClr + DB 'P'-40h + DW PgSet + DB 'Q'-40h + DW NoHdr + DB 'R'-40h + DW SetRM + DB 'S'-40h + DW DblTog + DB 'T'-40h + DW Ruler + DB 'V'-40h + DW VTTog + DB 'W'-40h + DW Window + DB 'X'-40h + DW RelM + DB 'Z'-40h + DW Blank + DB ESC + DW COCan + DB ' ' + DW COCan +OMnuLn EQU $-OMnuSt +COCan: RET +; +;Quick commands. ^Q toggle is on. +; +Quick: LD HL,CQTog + CALL Prefix + CALL XCase + CALL AdjKey ;translate arrow/DEL + CALL Case ;What function? + DB QMnuLn/3 + DW Error2 ;complain if unknown +QMnuSt EQU $ + DB 80H ;DEL + DW EBLine + DB 81H ;Up arrow + DW QuikUp + DB 82H ;Down + DW QuikDn + DB 83H ;Right + DW QuikRt + DB 84H ;Left + DW QuikLf + DB 'A'-40h + DW Rplace + DB 'B'-40h + DW QikBlk + DB 'C'-40h + DW Bottom + DB 'F'-40h + DW Find + DB 'Q'-40h + DW Queue + DB 'I'-40h + DW ZipTo + DB 'P'-40h + DW QuikLc + DB 'R'-40h + DW Top + DB 'T'-40h + DW E2Char + DB 'U'-40h + DW UndlLn + DB 'Y'-40h + DW EOLine + DB 'Z'-40h + DW QuikMk + DB ESC + DW CQCan + DB ' ' + DW CQCan +QMnuLn EQU $-QMnuSt +CQCan: RET +; +; +; +Prefix: PUSH HL ;show prefix, get suffix + LD DE,DspEsc + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + LD B,1 + CALL BBlank + LD DE,DspEsQ ;position cursor + CALL GoTo + CALL RptKey ;get suffix + PUSH AF + LD A,(NoHdrF) + OR A + JR NZ,PrefNH + LD DE,DspEsc + CALL GoTo + LD B,4 ;clean up + CALL BBlank + CALL UnAlt + POP AF + RET +PrefNH: CALL UnAlt ;(if no header) + CALL ShoLn1 + CALL RulFix + POP AF + RET +; +; +;Return to CP/M ... With or without saving +; +Exit: CALL Save ;Save the file + LD A,(EdErr) ;Was it ok? + OR A + RET NZ ;No, do not quit + JR QuitY1 +; +Done: CALL Save ;Save, and load new + LD A,(EdErr) + OR A + RET NZ + JP Restrt +; +Quit: LD A,(Modify) ;Quit to CP/M + OR A + JR Z,QuitY1 + LD HL,QuitQ + CALL Prompt + CALL Confrm ;warn if file changed... + JP NZ,ShoLn1 +QuitY1: XOR A ;### + LD (WinFlg),A ;### + CALL AdjLns ;### + LD BC,Z3MSG ;### + CALL Z3EAdr ;### + JR Z,QuitY ;### + LD HL,MsgUsr ;### offset to user area in message buffers + ADD HL,BC ;### + LD DE,CurLin ;### store the current line# in the Z3 + EX DE,HL ;### + LD BC,2 ;### + LDIR ;### +QuitY: LD HL,TUInit ;Clear screen + CALL CtlStr + LD A,(CurDsk) ;restore logged disk + LD E,A + LD C,SELD + CALL BDOS + LD A,(CurUsr) ;and user + LD E,A + LD C,USRN + CALL BDOSep + CALL DOSVer + JP C,Boot ;### restart if CP/M 2.2 + CP 'S' ;### + JR Z,ZSErrR ;### + CP 'D' ;### + JR NZ,CPM3xt ;### +ZSErrR: LD C,SETF ;### restore ZxDOS flags +ZDflgs: LD DE,0 ;### + CALL BDOSep ;### +CPM3xt: LD C,ERRM ;### reset ZxDOS, CP/M 3 error mode + LD E,0 ;### + CALL BDOSep ;### + JP Boot ;### and restart +; +;Error handler +; +DoErr: CALL Loud ;Show error message, wait for ESC + CALL SetNo + LD A,(MacFlg) + OR A ;### + CALL NZ,RstI1x ;### + XOR A ;### + LD (MacFlg),A ;### kill any running macro + LD A,(EdErr) + CP 10 + JP NC,SetAl ;error 10 does NOT show + LD A,(Ring) + OR A + LD E,BEL + CALL NZ,ShutUp ; ring bell + CALL MakAlt + CALL UpLft + CALL Dspl + DB X,31,'[[','['+X,0 + LD A,(EdErr) + ADD A,A ;Double the code + LD L,A + LD H,0 + LD DE,ErrTab + ADD HL,DE + LD E,(HL) ;Get msg addr from table + INC HL + LD D,(HL) + EX DE,HL + CALL DspLp ;show it + CALL DsplC + DB ' ]]]',CR,0 + CALL UnAlt + CALL ESCLp + LD A,(EdErr) + CP 1 + JR Z,DoErr2 + CP 5 + JR Z,DoErr2 + CP 9 + JP C,ShoLn1 ;(errors 2-8 need no redisp) +DoErr2: JP SetAl +ESCLp: CALL RptKey ;await ESC from console + CP ESC + RET Z + CP ' ' + JR NZ,ESCLp + RET +; +Error0: LD A,0 ;clear error (don't change flags) + JR ErrSet +Error1: LD A,1 ;error set fns + JR ErrSet +Error2: LD A,2 + JR ErrSet +Error3: LD A,3 + JR ErrSet +Error4: LD A,4 + JR ErrSet +Error5: LD A,5 ;6 currently not used + JR ErrSet +Error7: LD A,7 + JR ErrSet +Error8: LD A,8 + JR ErrSet +Error9: LD A,9 + JR ErrSet +Eror10: LD A,10 +ErrSet: LD (EdErr),A + RET +; +; +;INPUT ROUTINES +; +KeyIn: LD HL,(Timer) ;Get key, regardless + LD H,0 + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL + INC HL +KyIn1: PUSH HL + CALL KyStat + POP HL + DEC HL + JR NZ,Keybd ;read key if got one + LD A,(HorFlg) + LD E,A + LD A,(KeyFlg) + OR E + OR H + OR L ;allow redisp for horizontal scroll? + JR NZ,KyIn1 + CPL + LD (HorFlg),A ;yep (just once) + CALL ShoAll + CALL Cursr + JR KyIn1 +; +Keybd: CALL KyStat ;Get key, or 0 if none + RET Z + LD HL,ConBuf + DEC (HL) ;uncount it + INC HL + LD A,(HL) ;here it is + LD D,H + LD E,L + INC HL + LD BC,ConBufL-1 + LDIR ;remove it + AND 7FH ;strip parity + RET +; +KyStat: CALL CONSt ;Console status with buffering + JR Z,ConChk ;all quiet + LD HL,ConBuf ;got key + INC (HL) ;ok, count it + LD E,(HL) + LD D,0 + ADD HL,DE ;point there + LD (HL),A ;put it in + LD A,E + CP ConBufL ;buffer full? + JR C,ConChk +ConBsy: LD A,0C9H ;(RET) + LD (Plug),A ;plug up the console until buffer empty +ConChk: LD A,(ConBuf) ;check buffer (FAST) + OR A + RET NZ + LD (Plug),A ;buffer empty, unplug console + RET +; +CONSt: XOR A +Plug: NOP ;<--- RET plugs up console + LD E,0FFH ;console status/input + LD C,UCON + CALL BDOSep + OR A ;test for null + RET +; +KyPeek: CALL KyStat ;key available? + RET Z ;no + LD A,(ConBuf+1) ;return 1st char in buffer + AND 7FH ;strip parity + RET +; +; +Confrm: CALL RptKey ;get a Y/N answer + CALL UCase + CP 'Y' ;return Z if confirmed + RET Z + CP 'U'-40h + JR Z,IsCtlU + CP ESC ;allow this too +IsCtlU: JP Z,Reset + CP 'N' + JR NZ,Confrm +CnfNo: OR A + RET +; +;Translate four arrow keys and BS,DEL +; +AdjKey: CP BS ;First handle ^H (special case) + JR NZ,AdjK0 + LD C,80h ;make it DEL + LD HL,UsrKys + CP (HL) ;Is it installed as DEL? + JR Z,AKret + LD C,84h ;no, then it's Left arrow + CP A + JR AKret +AdjK0: LD B,5 ;Not ^H, try the rest + JR AdjK1 +AdjKUp: LD B,2 ;only do (DEL and) UP arrow +AdjK1: LD HL,UsrKys + LD DE,WSKys + LD C,7FH ;encode 80h=DEL, 81h=up, etc. +AKlp: INC C + CP (HL) + JR Z,AKret + EX DE,HL + INC DE + CP (HL) + JR Z,AKret + INC HL + DJNZ AKlp + CP C + LD C,A ;NO match: return NZ, char in A and C +AKret: LD B,A ;MATCH: return Z, code in A, char in C + LD A,C + LD C,B + RET +WSKys: DB DEL,'E'-40H,'X'-40H,'D'-40H,'S'-40H +; +; +ANSIcu: CALL RptKey ;Handle ANSI cursor keys ESC-[... + SUB '1' + JR Z,ANSIhome ; 1 + DEC A ; 2 Insert not used + DEC A + JR Z,ANSIdel ; 3 + DEC A + JR Z,ANSIend ; 4 + DEC A + JR Z,ANSIpu ; 5 + DEC A + JR Z,ANSIpd ; 6 + DEC A + JR Z,ANSIhome ; 7 + DEC A + JR Z,ANSIend ; 8 + + + SUB 'A' - '8' + JP Z,Up + DEC A + JP Z,Down + DEC A + JP Z,Right + DEC A + JP Z,Left + JP Error2 +ANSIpu: CALL RptKey ; Swallow the trailing ~ + JP PageB +ANSIpd: CALL RptKey ; Swallow the trailing ~ + JP PageF +ANSIdel:CALL RptKey ; Swallow the trailing ~ + JP EChar +ANSIhome:CALL RptKey ; Swallow the trailing ~ + JP Top +ANSIend:CALL RptKey ; Swallow the trailing ~ + JP Bottom + +; +;Get string input +; +GetStr: LD A,LinLen+1 ;string length +1 +GSEnt: LD (GSlen+1),A ;(entry for GetNum and NewNam) + LD HL,DMA ;*** MUST be 0080h *** +Lp1GSx: EXX + POP HL ;word after call + PUSH HL + LD E,(HL) ;storage/recall buffer address + INC HL + LD D,(HL) + LD (GSbufA),DE + EXX +Lp1GSy: XOR A + LD (RclFlg),A +Lp1GS: LD A,L + SUB DMA ;length +GSlen: CP 0 ;<---- max length pastes in here + JR NC,GSBS ;full? + LD A,(RclFlg) + OR A + JR NZ,GSrcl + PUSH HL + CALL RptKey ;Get next input + CALL AdjKey ;translate key + POP HL + CP 80H ;corrections? DEL, + JR Z,GSBS + CP 84H ;left + JR Z,GSBS + CP 83H ;right + JR Z,GSrcl ;recall a char + CP CR ;CR ends + JR Z,GSCR + CP 'U'-40H ;^U aborts operation + JP Z,Reset + CP 'P'-40H ;^P for ctlcode + JR Z,GSctl + LD A,C ;restore orig char + CP 'X'-40H ;wipeout + JR Z,GSwipe + CP 'R'-40H + JR Z,GSrcl ;recall the last string +; +Sk1GS: LD (HL),A ;Store byte + INC HL ;Move along + CP 20H ; ctl char? + PUSH HL + JR NC,Sk2GS ;no, just a normal char + ADD A,40H ;ctls are hili letters + PUSH AF + CALL AltY + POP AF + CALL PutChA + CALL UnAltY + JR Sk3GS +Sk2GS: CALL PutChA ;show byte +Sk3GS: POP HL + JR Lp1GS +; +GSBS: CALL GSBSsb + JR Lp1GSy +GSwipe: CALL GSBSsb + JR NZ,GSwipe + JR Lp1GSx +GSBSsb: LD A,DMA ;Are we at start + CP L + RET Z ;return Z if so + DEC HL ;back up pointer + LD E,BS ;wipe out char + CALL PutCh + LD E,' ' + CALL PutCh + LD E,BS + CALL PutCh + OR 1 ;clear flags + RET +; +GSrcl: EX AF,AF' ;save original char + EXX ;save HL + LD HL,(GSbufA) ;recall buffer ptr + LD A,H + OR L + EXX ;restore HL + JP Z,Lp1GS ;no recall buffer + EXX ;recall buffer ptr in HL + LD A,(HL) ;fetch char from recall buffer + EXX ;restore HL + OR A ;any char? + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + CP 0FFH + JP Z,Lp1GSx ;no, we're done, reset the ptr addr + EXX ;recall buffer pre in HL + INC HL ;point to next char + LD (GSbufA),HL ;update recall buffer ptr + EXX ;restore HL + EX AF,AF' ;restore original char + CP 'R'-40h ;^R? (whole string) + JR NZ,GSrclX ;no, just a single char + LD (RclFlg),A +GSrclX: EX AF,AF' ;restore char from recall buffer + JR Sk1GS ;store char +; +GSCR: LD (HL),0 ;terminator + LD A,L + SUB DMA ;Compute input length (Z=zero) + POP DE ;skip over buffer address + INC DE + INC DE + PUSH DE + RET ;HL points past end of string +; +GSctl: PUSH HL + CALL RptKey + CALL XCase + POP HL + JP Sk1GS +; +;Get numeric input (0-65535 decimal), return C if bad +; +GetNbr: PUSH BC ;BC = default if no input + LD A,5+1 + CALL GSEnt ;get up to 3 digits + DW 0 + POP DE + JR NZ,GNyes + LD B,D + LD C,E + LD A,B ;no entry, use default + OR C + RET +GNyes: LD DE,DMA ;fall thru to GetNNN +; +GetNNN: PUSH HL ;gets decimal # pointed by DE + LD H,D + LD L,E + LD B,0 +GNL: LD A,(HL) + CP '0' + JR C,GotN ;terminated by any nondigit. + CP '9'+1 + JR NC,GotN + INC HL + INC B + LD A,B + CP 5+1 + JR NC,GNErr ;5 digits max. + JR GNL +GotN: LD A,B ;okay, do them + LD BC,0 + OR A ;digits? + JR Z,GNErr + CP 2 + JR Z,Got2 + JR C,Got1 + CP 4 + JR Z,Got4 + JR C,Got3 + CP 5 + JR NZ,GNErr +Got5: LD HL,10000 + CALL GNNdig + JR C,GNErr +Got4: LD HL,1000 + CALL GNNdig + JR C,GNErr +Got3: LD HL,100 + CALL GNNdig + JR C,GNErr +Got2: LD HL,10 + CALL GNNdig + JR C,GNErr +Got1: LD HL,1 + CALL GNNdig + JR C,GNErr + POP HL + LD A,B + OR C + RET +GNErr: POP HL + SCF ;error + RET +; +GNNdig: LD A,(DE) ;do a digit: HL=power of 10 + INC DE +GNNLp: CP '0' + RET Z + DEC A + PUSH HL + ADD HL,BC + LD B,H + LD C,L + POP HL + RET C ;overflow + JR GNNLp +; +;Versions of above for 0...255 only: GetNum, GetNN take # in A +; +GetNum: LD C,A + LD B,0 + CALL GetNbr + JR GetNN1 +GetNN: CALL GetNNN +GetNN1: RET C + XOR A + OR B + JR NZ,GetNNX + OR C ;result in A, OK + RET +GetNNX: SCF ;oops, too big + RET +; +; +;Convert 16-bit number in HL to a one to five +;digit decimal number in the area pointed to by DE +; +BCDCon: LD IX,P10Tab ;Point at table + PUSH DE ;Save output pointer +BCDlp1: LD B,(IX+1) + LD C,(IX) + LD A,C ;low byte + CP 1 ;Clear carry flag + JR Z,BCDend + SBC HL,BC ;Subtract from input + JR NC,BCDok ;Got one in range + ADD HL,BC ;Restore it + INC IX + INC IX + JR BCDlp1 ;Try next one +; +BCDok: LD A,'1' + LD (DE),A ;Set initial digit +BCDlp2: SBC HL,BC ;Subtract again + JR C,BCDsk1 ;Went negative + EX DE,HL + INC (HL) ;Increment digit + EX DE,HL + JR BCDlp2 +; +BCDsk1: ADD HL,BC ;Restore it + INC DE ;Bump output + INC IX + INC IX + LD C,(IX) + LD B,(IX+1) + LD A,C + CP 1 ;Is this last entry + JR Z,BCDend + LD A,'0' + LD (DE),A + JR BCDlp2 +; +BCDend: LD A,L + OR '0' + LD (DE),A + INC DE + EX DE,HL + POP BC + SBC HL,BC ;Number filled + LD A,5 ; needed + SUB L ; to do + RET Z + ADD HL,BC ;Restore pointer +BCDlp3: LD (HL),' ' ;Clear field + INC HL + DEC A + JR NZ,BCDlp3 + RET +; +P10Tab: DW 10000,1000,100,10,1 +; +; +; +;PRINT text from memory +; +Print: LD HL,PgLen ;set defaults + XOR A + CP (HL) + JR NZ,Pr00 + INC A ;bit 0 set if no pagn +Pr00: LD (POByt),A + XOR A + LD (HdrLen),A + LD (POff),A + CPL + LD (PNum),A + LD (PrFlg),A + LD A,1 + LD (Copies),A + LD (PBeg),A + LD A,(DotPO) + LD (PrLMrg),A + LD A,(PTMarg) + LD (PrTMrg),A + LD HL,PrtQ ;options? + CALL Prompt + CALL GetStr ;get string into 80 + DW 0 +PO1st: LD DE,DMA ;point to option string +PrOlp: LD A,(DE) + INC DE + LD HL,POByt ;set up bit flags + LD BC,PrOlp + PUSH BC ;(return) + CALL UCase + CP ' ' ;eat spaces + RET Z + CP 'B' + JR Z,POBlk + CP 'D' + JR Z,PODblS + CP 'P' + JR Z,POPau + CP 'L' + JR Z,POLMrg + CP 'T' + JR Z,POTMrg + CP '*' + JR Z,POCpy + CP '^' + JR Z,POCtl + CP '@' + JR Z,POBeg + CP '#' + JR Z,PONum + CP '=' + JP Z,POPgS + CP '"' + JP Z,POHdrT + POP BC ;kill return + OR A + JP NZ,Error7 ;unexpected char + LD A,(PrFlg) + LD B,A + XOR A ;zero PrFlg + LD (PrFlg),A + OR B + JR NZ,PO1st + JP PORdy +; +PrFlg: DB 0 +; +POCpy: CALL GetNN ;"*" sets copy count + JP C,POBad + LD (Copies),A + RET +POLMrg: CALL GetNN ;"Lnn" sets left margin + JP C,POBad + LD (PrLMrg),A + RET +POTMrg: CALL GetNN ;"Tnn" sets top margin + JR C,POBad + LD (PrTMrg),A + RET +POPau: SET 4,(HL) ;bit 4 is for "P" + RET +PODblS: SET 3,(HL) ;bit 3 is for "D" + RET +POCtl: SET 2,(HL) ;bit 2 is for "^" + RET +POBlk: LD A,(HL) + AND 11000010B ;bits 1,6,7 must be clear + JR NZ,POBad + SET 5,(HL) ;set bit 5 (BLOCK) + RET +POBeg: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"@" page beginning + JR C,POBad + OR A + JR Z,POBad + LD (PBeg),A + SET 6,(HL) ;bit 6 is for "@" (suppresses output) + SET 7,(HL) ;so is bit 7 (multicopy) + INC A + NEG ;255-@ is most # can be + LD B,A + LD A,(PNum) + CP B + RET C ;okay, less + LD A,B + LD (PNum),A + RET +PONum: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"#" page count + JR C,POBad + OR A + JR Z,POBad + LD B,A + LD A,(PBeg) + ADD A,B ;@ + # cannot exceed 255 + JR C,POBad + LD A,B + LD (PNum),A + RET +POPgS: BIT 0,(HL) ;must be paginating + JR NZ,POBad + CALL GetNN ;"=" starting pagination + JR C,POBad + OR A + JR Z,POBad + LD (POff),A ;offset beginning page + RET +POHdrT: BIT 0,(HL) ;must be paginating + JR NZ,POBad + SET 1,(HL) ;bit 1 requests header + LD (HdrPtr),DE ;point to header text + LD B,50 ;and figure its length +POHlp: LD A,(DE) + INC DE + CP '"' + JR Z,POHlpF + DJNZ POHlp + JR POBad ;too long +POHlpF: LD A,50 + SUB B ;length + LD (HdrLen),A + RET +POBad: POP HL ;eat return + JP Error7 +; +PORdy: CALL IOon ;say Wait + LD HL,PInit ;init string? + LD B,(HL) + INC HL + CALL LSTStr + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;move to top of file + LD A,(POff) + OR A + JR NZ,PORdy0 + LD A,(PBeg) +PORdy0: LD HL,PBeg + SUB (HL) ;adjust starting page offset + LD (POff),A + LD HL,POByt + BIT 5,(HL) + JR Z,PORdy1 + CALL IsBlk ;block print requested + BIT 1,A ; must be marked + JP Z,PrOops + INC DE + PUSH HL + SBC HL,DE + POP HL + RET Z ;block empty + DEC HL + EX DE,HL + JR PORdy2 +PORdy1: CALL NdCnt ;print whole file + JP C,PrDone ;file empty + LD HL,(AftCu) + LD DE,(EndTx) +PORdy2: LD (StPrt),HL + LD (EndPr),DE + CALL PCR ;### +; +RePrt: LD HL,POByt ;[reprint reentry] + BIT 7,(HL) + JR Z,PRP0 + SET 6,(HL) ;remember if "@" was used +PRP0: XOR A + LD (PageN),A + INC A + LD (IgnFlg),A ;TOF is start of line (DotChk) + LD A,(PgLen) ;start first page + LD B,A + OR A + PUSH AF ;### + CALL Z,DoPOf ;### + POP AF ;### + CALL NZ,PgBrk + JR C,Sk4Pr + LD HL,(StPrt) ;Point at first one + LD C,0 ;Initialize GetNx +Lp1Pr: CALL GetNx ;Get a character + CALL DotChk ;(maybe ignore dot command lines) + CP CR + JR NZ,Sk2Pr + CALL PrOut ;It's a CR + PUSH BC + PUSH HL + CALL Keybd + CP ESC ;Abort request? + POP HL + POP BC + JR Z,Sk1Pr + LD A,(POByt) + BIT 3,A ;doublespacing? do extra CR(LFCR)LF + JR Z,Sk0Pr + CALL PLF + CALL PCR + LD A,B ;count it (if paginating) + OR A + JR Z,Sk0Pr + DEC B + JR Z,Sk01Pr +Sk0Pr: LD A,B + OR A ;Not paginating? B is and stays 0 + LD A,(LFChr) ;Add usual line feed + JR Z,Sk2Pr + DJNZ Sk2Pr +Sk01Pr: CALL PgBrk ;time for NEW PAGE + JR C,Sk4Pr ;done? + JR Sk2aPr +Sk1Pr: LD A,1 ;abort + LD (Copies),A + JR Sk3Pr +Sk2Pr: CALL ChekC ;Check for masking + CALL PrOut ;Output char + XOR A + CP C ;Hidden space waiting? + JR NZ,Lp1Pr +Sk2aPr: LD DE,(EndPr) ;At end? + LD A,E + SUB L + LD A,D + SBC A,H + JR NC,Lp1Pr ;Loop if more to go +Sk3Pr: CALL PCR ;last CRLF for some matrix printers + LD A,(LFChr) + LD C,A + LD A,(PgLen) + OR A ;Finish page? + JR Z,Sk3aPr + LD C,FF +Sk3aPr: LD A,C + CALL PrOut +Sk4Pr: LD HL,PCodes ;undo toggles if on + LD DE,16 + LD B,4 +Lp2Pr: BIT 7,(HL) + JR Z,Lp2PrF + RES 7,(HL) + PUSH BC + PUSH DE + PUSH HL + LD DE,8 + ADD HL,DE + LD B,(HL) + INC HL + CALL LSTStr + POP HL + POP DE + POP BC +Lp2PrF: ADD HL,DE + DJNZ Lp2Pr + LD HL,Copies ;more copies? + DEC (HL) + JP NZ,RePrt + LD HL,PUInit ;uninit string? + LD B,(HL) + INC HL + CALL LSTStr + JR PrDone +PrOops: CALL Error7 +PrDone: LD HL,(LastCu) ;all finished + DEC HL + CALL MoveR ;go back to position + CALL IOoff + JP ShoLn1 +; +PgBrk: PUSH BC ;call this for new page (returns C for EOP) + PUSH HL + LD A,(PageN) + OR A + LD A,FF ;start new sheet IF not 1 + CALL NZ,PrOut + LD A,(POByt) + BIT 4,A ;pause requested? + JR Z,NP00 + CALL IOoff ;do it + LD HL,RdyQ + CALL Prefix + CP ESC + JP Z,NPquit + CALL IOon +NP00: LD HL,PageN + INC (HL) + JP Z,NPquit ;255 page limit. + LD C,(HL) ;check "#" limit? + LD A,(PBeg) + LD E,A + LD A,(PNum) ;Pnum+Pbeg-1 = Lastpage# + DEC A + ADD A,E + JP C,NPquit ;255 page limit + CP C + JP C,NPquit ;"#" pages printed... quit. + LD A,(PBeg) + LD C,A + LD A,(PageN) + CP C + LD HL,POByt + JR C,NP10 ;are we "@" yet? + RES 6,(HL) ;yes (start) printing + LD A,0C9H ;begin with margin offset + LD (DoPOf),A +NP10: LD A,(PrTMrg) + OR A + JR Z,NP20 + LD B,A +NP11Lp: CALL PCRLF ;top margin? + DJNZ NP11Lp +NP20: LD HL,POByt + BIT 1,(HL) + JR Z,NPnoh ;want header? + LD A,(HdrLen) + ADD A,6 + LD B,A + LD A,(RtMarg) ;column for page no. + SUB B + JR NC,NPlp + LD A,70 ;default if margin unusable + SUB B +NPlp: PUSH AF ;space over to right justify header + CALL PrSpc + POP AF + DEC A + JR NZ,NPlp + LD HL,(HdrPtr) ;put out header + LD A,(HdrLen) + LD B,A + CALL POStr + CALL PrSpc + LD A,(PageN) ;put out page + LD HL,POff + ADD A,(HL) ;adjust for "=" option + LD L,A + LD H,0 + LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + CALL POStr + CALL PCRLF + CALL PCRLF ;two blank lines + CALL PCRLF +NPnoh: XOR A + LD (DoPOf),A + CALL DoPOf + POP HL + POP BC + LD A,(PgLen) ;reset TOP + LD B,A + OR A + RET +NPquit: POP HL + POP BC + SCF + RET +PNBuf: DB 'nnnnn',0 ;(also used elsewhere) +; +DotChk: CP CR ;may ignore dot commands + JR Z,DotCCR + CP '.' + JR Z,DotCDt +DtC01: EX AF,AF' ;ordinary char + LD A,(IgnFlg) + CP 0FFh ;ignoring chars? + RET Z ;(returns 0FFh, nonprinting) + XOR A + LD (IgnFlg),A ;nope, clear dot search +DtCRet: EX AF,AF' ;no action, accept char + RET ;leave it 0FFh (ignore) +DotCCR: CALL DtC01 + EX AF,AF' + LD A,1 ;1 = ready to ignore if next char dot + LD (IgnFlg),A + EX AF,AF' + RET +DotCDt: EX AF,AF' + LD A,(FMode) ;Only ignore dotcmds in "W" mode + CP 'W' + JR NZ,DtCRet + LD A,(IgnFlg) + OR A + JR Z,DtCRet + LD A,0FFh ;FF = dot seen, ignore + LD (IgnFlg),A + RET +; +ChekC: CP ' ' ;may mask ctl chars + RET NC + CP CR ;exceptions: CR,LF,BadTbl + RET Z + CP LF + RET Z + PUSH HL + PUSH BC + LD HL,BadTbl + LD BC,BadLen + CPIR + POP BC + POP HL + RET Z + PUSH AF + LD A,(POByt) + BIT 2,A + JR NZ,CMask + POP AF + RET +CMask: LD A,'^' ;mask: print "^", + CALL PrOut + POP AF + OR 40H ;turn ^A into A, etc. + RET +; +PCR: LD A,CR + JR PrOut +PrSpc: LD A,' ' +PrOut: CP 0FFH ;(FF=dummy code, ignore) + RET Z + PUSH BC ;Print byte + PUSH DE + PUSH HL + LD HL,POByt ;printing yet? + BIT 6,(HL) + JR NZ,Sk2PO + CP ' ' + JR NC,Sk1PO ;non-ctl + LD HL,BadTbl + LD BC,BadLen + CPIR + JR Z,Sk2PO ;ILLEGAL + LD HL,TogTbl + LD BC,4 + CPIR ;toggle? + JR Z,Sk3PO + LD BC,4 + CPIR ;switch? + JR NZ,Sk1PO ;arbitrary ctl-code + LD A,4-1 + SUB C ;nontog# (0..n) + ADD A,A + ADD A,A + ADD A,A ;*8 + LD E,A + LD D,0 + LD HL,UCodes + ADD HL,DE +Sk00PO: LD B,(HL) + INC HL ;string to send +Sk0PO: CALL LSTStr + JR Sk2PO +Sk3PO: LD A,4-1 + SUB C ;tog# (0..n) + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;*16 + LD E,A + LD D,0 + LD HL,PCodes + ADD HL,DE + BIT 7,(HL) ;toggle status? + JR NZ,Sk3aPO + LD B,(HL) ;off, turn on + SET 7,(HL) + INC HL + JR Sk0PO +Sk3aPO: RES 7,(HL) ;on, turn off + LD DE,8 + ADD HL,DE + JR Sk00PO +Sk1PO: LD E,A ;byte to send + PUSH AF + CALL LSTOut + POP AF + LD HL,LFChr + CP (HL) + CALL Z,DoPOf ;LF? need margin skip +Sk2PO: POP HL + POP DE + POP BC + RET +; +DoPOf: NOP + LD A,(PrLMrg) ;do printer margin offset + OR A + RET Z + LD B,A +DoPOfL: CALL PrSpc + DJNZ DoPOfL + RET +; +PCRLF: CALL PCR ;do CR(LF?) +PLF: LD A,(LFChr) + JP PrOut +; +POStr: LD A,B ;send B chars at (HL) to PrOut + OR A + RET Z + LD A,(HL) + CALL PrOut + INC HL + DJNZ POStr + RET +; +LSTStr: LD A,B ;send B chars at (HL) to LST directly + OR A + RET Z + LD E,(HL) + PUSH BC + PUSH HL + CALL LSTOut + POP HL + POP BC + INC HL + DJNZ LSTStr + RET +; +LSTOut: LD C,LSTO ;print char in E + JP BDOSep +; +; +; +; ASSORTED SUPPORT ROUTINES +; +;RAM initialization functions +; +IniRAM: LD HL,MnuEnd ;Figure what used to be TxtOrg + LD A,(Help) ;help menus disabled? + OR A + JR NZ,IniR02 + LD HL,HelpY ;yes, use that memory for editing +IniR02: LD (BegTx),HL + LD HL,(BDOSep+1) ;BDOS origin (xx06) + LD L,-4 ;a few bytes room + DEC H ;back a page + LD (EndTx),HL + XOR A ;initialize screen + LD (NSkip),A + INC A + LD (Horiz),A + LD (Vert),A + LD (CurCol),A + LD (OldCol),A ;### + LD HL,1 + LD (CurPg),HL + LD (CurPgL),HL + LD (CurLin),HL + LD (OldLin),HL ;### + LD HL,(BegTx) ;set up cursor gap, mark CRs at ends + DEC HL + LD (BefCu),HL + LD (HL),CR + LD HL,(EndTx) + INC HL + LD (AftCu),HL + LD (HL),CR + RET +; +;Case selection subroutine +; CALL Case +; DB # of entries in list +; DW Default subroutine if no match +; DB value1 +; DW subroutine1.... +; +; +Case: POP HL + LD B,(HL) ;entries + INC HL + LD E,(HL) ;DE=default sbr + INC HL + LD D,(HL) + INC HL +Lp1Ca: CP (HL) ;Value matches? + INC HL + JR NZ,Sk2Ca + LD E,(HL) ;yes, get address + INC HL + LD D,(HL) + JR Sk3Ca ;finish up +; +Sk2Ca: INC HL ;No match, skip ahead +Sk3Ca: INC HL + DJNZ Lp1Ca ;Try again + EX DE,HL ;Swap sbr and return + PUSH DE ;Store return (end of list) + JP (HL) ;Go do sbr (LAST match) +; +; +XCase: CALL UCase ;force A to ctl-codes + CP '@' + RET C + CP '_'+1 + RET NC + AND 1FH + RET +UXCase: CP ESC ;uppercase A if letter OR ctl-code + JR NC,UCase + ADD A,40H + RET +UCase: CP 'a' + RET C ;uppercase A if letter + CP 'z'+1 + RET NC + AND 5FH + RET +; +; +Wait: LD A,(MacFlg) ;Macro Pause function + OR A + JP Z,Error2 + LD A,3 ;Wait about 3/2 sec + JR Dly0 +; +Delay: LD B,A ;Delay about A/2 sec + LD A,(MacFlg) ;but NOT if Macro going + OR A + RET NZ + LD A,B +Dly0: ADD A,A + ADD A,A +Dly1: PUSH AF + CALL BDly + POP AF + DEC A + JR NZ,Dly1 + RET +BDly: LD A,(MHz) + LD B,A + LD C,0 +BDlyLp: DEC BC + LD A,B + OR C + JR NZ,BDlyLp + RET +; +; +; UR-ROUTINES +; +Fill: LD (DE),A ;fill B bytes at DE with A + INC DE + DJNZ Fill + RET +; +GpCnt: LD BC,(BefCu) ;Count cursor gap size + LD HL,(AftCu) + DEC HL + DEC HL +SubDP: PUSH HL ;Double precision subtract + OR A ;BC = HL - BC + 1 + SBC HL,BC + LD B,H + LD C,L + INC BC + POP HL + RET +; +BgCnt: LD HL,(BegTx) ;Count bytes before cursor +LCnt: LD B,H + LD C,L + PUSH HL + LD HL,(BefCu) + CALL SubDP + POP HL + RET +NdCnt: LD HL,(EndTx) ;Count bytes after cursor +RCnt: LD BC,(AftCu) + JR SubDP +; +;Move bytes across cursor gap so the gap moves left. +;HL points to what will become BefCu. +; +MoveL: CALL LCnt ;bytes to move + RET C + LD DE,(AftCu) + DEC DE + LD HL,(BefCu) + LDDR + LD (BefCu),HL + INC DE + LD (AftCu),DE + RET +; +;MoveR - Moves gap right. HL will become BefCu. +; +MoveR: CALL RCnt + RET C + LD DE,(BefCu) + INC DE + LD HL,(AftCu) + LDIR + LD (AftCu),HL + DEC DE + LD (BefCu),DE + RET +; +;CrLft - Find CRs to left of cursor (up to E) +; +CrLft: CALL BgCnt + JR NC,Sk1Lf + XOR A ;no bytes, return with C and no Z + SUB 1 + RET +Sk1Lf: CALL FetchB + CP CR ;Is cursor on a CR + JR NZ,Sk2Lf + LD A,1 + CP E + JR NZ,Sk2Lf + SCF ;Asked for 1, and already there: ret C and Z + RET +Sk2Lf: LD A,CR +Lp3Lf: CPDR ;find a CR + JP PO,Sk4Lf ;count exhausted? + DEC E + JR NZ,Lp3Lf ;Do more? + INC HL ;Back up to before CR + INC HL + XOR A ;Found AOK, ret Z and no C + RET +Sk4Lf: INC HL ;Back to first byte + SCF + CCF ;Clear C + JR Z,Sk5Lf ;Was first byte CR + DEC E ;No, reduce count + RET +Sk5Lf: INC HL ;Back after CR + DEC E ;the one we wanted? + RET Z + DEC HL ;No, back in front of it + DEC E + RET +; +;CrRit - same, to right. +; +CrRit: CALL NdCnt + JR NC,Sk1Ri + XOR A + SUB 1 ;no bytes, return C and no Z + RET +Sk1Ri: LD D,E + LD A,CR + LD HL,(AftCu) +Lp2Ri: CPIR + JP PO,Sk3Ri + DEC E + JR NZ,Lp2Ri + SCF + CCF ;found AOK, ret Z and no C + RET +Sk3Ri: LD A,D + CP E + JR NZ,Sk4Ri + SCF ;none found, return C and Z + RET +Sk4Ri: LD HL,(EndTx) + DEC HL + LD A,CR + LD BC,0FFFFh + CPDR + INC HL + INC HL + OR 1 ;some but not enough, ret no C and no Z + RET +; +;cursor positioning subroutines +; +TopV: LD A,1 + JR LoadV +MidV: LD A,(TxtLns) + SRL A + JR LoadV +DecV: EXX + LD HL,(CurLin) + DEC HL + LD (CurLin),HL + EXX +DecVO: LD A,(Vert) ;returns Z if cannot Dec + CP 1 + JR Z,LoadV + DEC A + JR LoadV +IncV: EXX + LD HL,(CurLin) + INC HL + LD (CurLin),HL + EXX +IncVO: LD A,(Vert) ;returns Z if cannot Inc + EXX + LD HL,TxtLns + CP (HL) + EXX + JR Z,LoadV + INC A + JR LoadV +BotV: LD A,(TxtLns) +LoadV: LD (Vert),A + RET +LftH: LD A,1 + JR LoadH +LTabH: LD A,(Horiz) + DEC A + JR Z,RitH + CALL WhatC ;ouch, got to calculate + LD HL,NSkip ;Horiz = CurCol-NSkip + SUB (HL) + JR C,RitH + JR LoadH +DecH: LD A,(Horiz) + DEC A + RET Z + JR LoadH +TabH: LD A,(Horiz) + DEC A + EXX + LD HL,TabCnt + OR (HL) + EXX + INC A + JR IncT +IncH: LD A,(Horiz) +IncT: EXX + LD HL,View + CP (HL) + EXX + RET NC + INC A + JR LoadH +RitH: LD A,(View) +LoadH: EX AF,AF' ;### + LD A,(CurCol) ;### + INC A ;### + JR NZ,LoadH2 ;### + EX AF,AF' ;### + RET ;### +LoadH2: EX AF,AF' ;### + LD (Horiz),A + RET +; +; +;Get next text character from memory +;(HL and C keep track across repeated calls) +; +GetNx: XOR A + CP C ;Have we a hidden space? + JR NZ,Sk1Gt + LD A,(HL) ;No, get next byte + INC HL + CP 80H ;Does it have hidden space? + JR NC,Sk2Gt ;Yes, note and remove + CP CR + RET +Sk1Gt: DEC C ;Fetch hidden space + LD A,' ' + CP CR ;Set Z flag if CR + RET +Sk2Gt: AND 7FH + INC C + CP CR ;Set Z flag if CR + RET +; +;Hide any hideable spaces. (NEW ALGORITHM) +; +Cmprs: CALL BgCnt ;bytes to left + JR C,Sk2Cm ;none? + LD D,H + LD E,L + DEC DE +Lp1Cm: LD A,(HL) ;Get a byte + CP ' ' ;Nonspace? fine + JR NZ,Sk1Cm + LD A,(DE) ;Last byte CTL? fine + CP 20H + LD A,' ' + JR C,Sk1Cm + LD A,(DE) ;Hidden space already? fine + BIT 7,A + LD A,' ' + JR NZ,Sk1Cm + LD A,(DE) + OR 80h ;Got to hide the space. + DEC DE +Sk1Cm: INC DE ;Store byte + LD (DE),A + INC HL ;Bump input + DEC BC + LD A,B + OR C ;more to do? + JR NZ,Lp1Cm + LD (BefCu),DE ;This is now BefCu +; +Sk2Cm: CALL NdCnt ;How many after cursor? + RET C + LD HL,(EndTx) ;work back from end + LD D,H + LD E,L + INC DE +Lp3Cm: LD A,(DE) + CP ' ' ;Last byte space? + JR NZ,Sk3Cm + LD A,1FH ;This byte CTL? + CP (HL) + JR NC,Sk3Cm + BIT 7,(HL) ;This byte already hiding? + JR NZ,Sk3Cm + SET 7,(HL) ;Got to hide that space + INC DE +Sk3Cm: DEC DE + LDD ;Store byte, Bump input + INC DE + JP PE,Lp3Cm ;more to do? + LD (AftCu),DE ;This is now AftCu + RET +; +;Set BC to gap size (make room if needed, or set EdErr) +; +Space: LD L,A ;Save A + PUSH HL + CALL GpCnt ;Count gap size + CALL C,Cmprs ;No room? Hide spaces + CALL GpCnt ;Room now? + CALL C,Error1 ;out of memory + POP HL + LD A,L + RET +; +InsSpc: LD A,' ' +; +;Put ordinary byte in A into text at cursor. +; +Insrt: CALL Space ;Insert Before cursor + RET C + CP EOF + JR Z,Insrt1 + LD HL,BlkChr + CP (HL) + JR Z,Insrt1 + LD HL,Modify + LD (HL),0FFh +Insrt1: LD HL,(BefCu) ;Bump pointer + INC HL + LD (HL),A ;Store byte + LD (BefCu),HL + OR A ;Clear flags + RET +InsrtA: CALL Space ;same, but After cursor + RET C + LD HL,Modify + LD (HL),0FFh +InsrA1: LD HL,(AftCu) + DEC HL + LD (HL),A + LD (AftCu),HL + OR A + RET +; +;Compute absolute line number +; +CountS: LD HL,1 ;Hard way: from start + LD (CurLin),HL + CALL BgCnt + JR Sk0CL +CountL: LD HL,(LastCu) ;same but faster, using LastCu + INC HL + CALL LCnt +Sk0CL: RET C ;(At start, or have not moved) + LD DE,0 + LD A,CR + LD HL,(BefCu) +Lp1CL: CPDR + JR NZ,Sk1CL + INC DE + JP PE,Lp1CL +Sk1CL: LD HL,(CurLin) + ADD HL,DE + LD (CurLin),HL + RET +CountR: LD HL,(LastCu) ;same, but for backward move + DEC HL + CALL RCnt + RET C ;(have not moved) + LD DE,0 + LD A,CR + LD HL,(AftCu) +Lp1CR: CPIR + JR NZ,Sk1CR ;(have not moved) + INC DE + JP PE,Lp1CR +Sk1CR: LD HL,(CurLin) + OR A + SBC HL,DE + LD (CurLin),HL + RET +; +; +;MACRO functions +; +MacKey: LD HL,KeyQ + CALL Prompt + CALL RptKey ;which key? + CALL UCase + LD (MKsav),A + CP 'N' ;no-rpt request? + JR Z,MK0 + CP 'Q' ;no-rpt & macro request? + JR NZ,MK00 +MK0: CALL Echo ;show N or Q, get next + CALL RptKey +MK00: SUB '0' + JP C,Error7 + CP 10 + JP NC,Error7 + LD D,A ;save key + LD A,0FFH + LD HL,MacStr + LD BC,StrSiz+1 ;find end + CPIR + LD A,StrSiz + SUB C ;figure length + LD E,A ;save it + LD HL,Keys+2 + LD A,D + OR A + JR Z,MKlp1F +MKlp1: LD C,(HL) + LD B,0 ;find key in list + ADD HL,BC + INC HL + DEC A + JR NZ,MKlp1 +MKlp1F: LD A,(HL) ;old length + OR A + JR Z,MK1 + PUSH DE + PUSH HL ;delete old one + LD E,(HL) + LD D,0 + LD (HL),0 + INC HL + EX DE,HL + ADD HL,DE + LD B,H + LD C,L + PUSH HL + LD HL,Keys+200H + OR A + SBC HL,BC ;bytes to move + LD B,H + LD C,L + POP HL + LDIR + CALL VerKey + POP HL + POP DE +MK1: LD A,E ;anything to add? + OR A + JR Z,MKDone + LD A,(Keys+1) ;will it fit + OR A + JR NZ,MK1a + LD A,(Keys) + SUB E + JP C,Error1 ;out of memory +MK1a: LD (HL),E ;yes + INC HL + LD C,E + LD B,0 + PUSH HL + LD HL,Keys+200H-1 + LD D,H + LD E,L + OR A + SBC HL,BC ;from here + POP BC + PUSH HL + SBC HL,BC ;bytes to move + LD B,H + LD C,L + INC BC ;inclusive + POP HL + LDDR ;make room + LD C,(HL) + LD B,0 + INC HL + EX DE,HL + LD HL,MacStr + PUSH DE + LDIR ;insert new one + POP HL + LD A,(MKsav) + CP 'N' ;take care of N/Q request + JR Z,MK2 + CP 'Q' + JR NZ,MKDone + DEC HL + LD A,(HL) ;Q only works if length >1 + CP 2 + INC HL + JR C,MK2 + INC HL + SET 7,(HL) ;indicate quiet + DEC HL +MK2: SET 7,(HL) ;indicate no-rpt +MKDone: CALL VerKey + JP ShoLn1 +; +; +VerKey: LD B,10 ;verify key area + LD HL,200H-12 + LD D,0 + LD IX,Keys+2 +VKlp: LD A,StrSiz ;check size + CP (IX) + JR C,VKwipe + LD E,(IX) + SBC HL,DE ;decrement + JR C,VKwipe + ADD IX,DE ;move to next + INC IX + DJNZ VKlp + LD (Keys),HL ;free bytes + LD A,H + OR L + RET Z ;full? +VKlp2: LD (IX),0 + INC IX ;zero fill + DEC HL + LD A,H + OR L + JR NZ,VKlp2 + RET +VKwipe: LD HL,200H-12 ;oops, bad + LD (Keys),HL + LD IX,Keys+2 + LD HL,200H-2 + JR VKlp2 +; +ChainK: LD HL,MacFlg ;chain to new macro + BIT 0,(HL) ;(used only if macro going) + RET Z + CALL RstI1x ;reset INS to saved state + CALL RptKey ;get key # + CP '0' + JP C,Error8 + CP '9'+1 + JP NC,Error8 + PUSH AF + CALL Loud + XOR A + LD (MacFlg),A + POP AF + JR UK0 +; +UseKey: LD HL,MacFlg ;macro going already? + BIT 0,(HL) + RET NZ ;YES, this is just a label +UK0: SUB '0' ;NO, retrieve key 0-9 + LD B,A + LD HL,Keys+2 + JR Z,UKlp1F +UKlp1: LD E,(HL) + LD D,0 ;find it + ADD HL,DE + INC HL + DJNZ UKlp1 +UKlp1F: LD A,(HL) ;length + INC HL + OR A + JP Z,Error7 ;none? + LD C,A + LD B,0 + PUSH BC ;on stack for Mac00 entry + LD DE,DMA + PUSH DE + LDIR ;fetch it in + POP HL ;point to it + BIT 7,(HL) + RES 7,(HL) + JR Z,Mac00 ;not no-rpt? go ask, etc. + INC HL + BIT 7,(HL) + RES 7,(HL) + CALL NZ,Quiet ;quiet? + LD A,'1' + JR Mac0 ;go do just once +; +DoMac: LD HL,MacroQ ;get Macro defn + CALL Prompt + CALL GetStr + DW MacStr ;### + OR A + JR Z,MacDel ;none? delete + LD C,A ;save count + LD B,0 + PUSH BC +Mac00: LD HL,RptcQ ;(entry for normal Key) + CALL Prompt + CALL RptKey + CALL UCase + CP 'Q' + JR NZ,Mac0 + CALL Echo + CALL Quiet ;Q? do quiet, get rpt cnt + CALL RptKey +Mac0: POP BC ;string cnt (entry for no-rpt Key) + PUSH AF ;save rpt cnt + LD A,C + OR A ;null string? + JR Z,Mac1 + LD HL,DMA ;move in string + LD DE,MacStr + LDIR + EX DE,HL + LD (HL),0FFh ;terminator +Mac1: CALL ShoLn1 + POP AF + LD B,255 + CP '*' ;figure rpt cnt + JR Z,Mac2 ;(* is maximal) + LD B,0 ;(0 is default) + SUB '0' + JR C,Mac2 + CP 9+1 + JR NC,Mac2 + LD B,A +Mac2: LD A,B ;set rpt cnt + LD (RptCnt),A + OR A + JP Z,Loud ;oops, rpt=0 +Mac3: LD HL,MacStr ;Point to it + LD (CmdPtr),HL + LD A,0FFH ;Okay, here goes + LD (MacFlg),A + LD HL,InsFlg ;save INSERT toggle + LD A,(HL) + LD (SavIns),A ;turn INSERT off if on + BIT 7,(HL) + CALL NZ,ToggHL + RET +MacDel: LD A,0FFH + LD (MacStr),A + JP ShoLn1 +; +;"Macro Programming Language" +; +MacJmp: LD A,(MacFlg) ;jump to a label + OR A + JP Z,Error8 ;macro must be going + LD (JmpFlg),A ;say Jump in progress + CALL RptKey + LD HL,JmpFlg + LD (HL),0 + CP '[' ;TOF/EOF? + JR Z,MJtop + CP ']' + JR Z,MJend + CP '>' ;move/loops? + JR Z,MJRt + CP '<' + JR Z,MJLf + LD E,A ;key to find + LD HL,MacStr + LD B,StrSiz +MJlp: LD A,(HL) ;search along + INC HL + CP 0FFH + JP Z,Error8 + CP ESC + JR Z,MJlp01 + DJNZ MJlp + JP Error8 +MJlp01: LD A,E ;found ESC... right one? + CP (HL) + JR NZ,MJlp + INC HL ;yep + LD (CmdPtr),HL + RET +; +MJtop: LD HL,MacStr ;redo it from the top + LD (CmdPtr),HL + RET +MJend: XOR A ;quit + LD (MacFlg),A + LD E,A + CALL RstI1x + JP Loud +MJRt: CALL NdCnt ;right/left jump loops + JP C,Error7 ;stop at EOF + CALL Right + JR MJredo +MJLf: CALL BgCnt + JP C,Error7 + CALL Left +MJredo: LD HL,(CmdPtr) + DEC HL ;back up to the ESC to repeat + DEC HL + DEC HL + DEC HL + LD (CmdPtr),HL + RET +; +MacTst: LD A,0CAH ;(JP Z) + JR MacT1 +MacTsX: LD A,0C2H ;(JP NZ) +MacT1: LD (MacT),A + LD A,(MacFlg) + OR A ;macro must be going + JP Z,Error8 + CALL RptKey ;get char to match + LD E,A + CALL Fetch ;char at cursor + CP E +MacT: JP Z,MacJmp ;yes? jump <--- can be JP NZ too + JP RptKey ;no, just eat label +; +;Get the next key stroke (check Macro first.) +; +TRptKy: XOR A ;enable redisp Timer + JR RK0 +RptKey: LD A,0FFH +RK0: LD (KeyFlg),A + LD A,(MacFlg) + OR A ;macro waiting? + JP Z,KeyIn ;no. +MacIn: CALL Keybd ;YES, check keyboard for abort + CP ESC + JR NZ,MacIn1 + LD HL,(CmdPtr) ;abort, make this last char + LD E,(HL) + LD HL,MacFF+1 ;### + LD (CmdPtr),HL ;### + JR MacIn3 +MacIn1: LD HL,(CmdPtr) ;OK, take waiting char + LD A,(HL) + INC HL ;bump pointer + LD (CmdPtr),HL +MacFF: CP 0FFH ;### + JR Z,MacFFx ;### + LD E,A ;### + LD A,(HL) ;end of macro now? (FF) + INC A + JR NZ,MacIn2 ;NO, return char + LD A,(JmpFlg) ;jump in progress? + OR A + JR NZ,MacIn2 + LD HL,RptCnt ;need to repeat? + LD A,(HL) + INC A + JR Z,McIn1a + DEC (HL) + JR Z,MacIn3 +McIn1a: LD HL,MacStr ;repeat: reset pointer + LD (CmdPtr),HL + JR MacIn2 +MacIn3: CALL Loud +MacIn2: LD A,E + AND 7FH ;strip parity, return char + RET +MacFFx: XOR A ;NO, stop macro execution + LD (MacFlg),A + CALL RstI1x ;restore saved INS state + JP KeyIn +; +; +;Unconditional Q/L for Macros +; +Quiet: LD HL,ShutUp + LD (HL),0C9H ;(RET) + RET +Loud: LD HL,ShutUp + XOR A ;(NOP) + CP (HL) + RET Z + LD (HL),A + JP HoldSc ;gotta see... +; +RstI1x: LD A,(SavIns) + LD HL,InsFlg + CP (HL) + CALL NZ,ToggHL ;switch INS to match the saved state + RET +; +;Conditional Q/L for formatting etc. +; +; +XQuiet: LD HL,ShutUp + LD A,(HL) + LD (HL),0C9H ;(RET) + LD (SavQ),A + RET +XLoud: LD A,(SavQ) + OR A ;(NOP) + RET NZ + LD (ShutUp),A + RET ;do NOT need redisp here +; +;Force loud for header display +; +Force: LD HL,ShutUp + LD A,(HL) + LD (HL),00H ;(NOP) + LD (SavQ2),A + RET +UForce: LD A,(SavQ2) + CP 0C9H ;(RET) + RET NZ + LD (ShutUp),A + RET +; +; +; VDE EDITING FUNCTIONS +; +; +;Show information +; +Info: CALL MakAlt ;show this first for entertainment + CALL UndrHd + CALL Dspl + DB X,26,0 + LD HL,VersID + CALL DspLp + CALL Cmprs ;pack spaces + CALL GpCnt ;count gap size + PUSH BC + LD H,B + LD L,C + LD DE,FreNNN ;show it as "free space" + CALL BCDCon + LD HL,(EndTx) + INC HL + LD DE,(BegTx) + OR A + SBC HL,DE + POP BC + SBC HL,BC ;memory used + LD DE,UsdNNN + CALL BCDCon ;show it as "used" + LD HL,(BegTx) + LD DE,(BefCu) + CALL FSzSbr ;figure actual disk file size + PUSH BC + LD HL,(AftCu) + LD DE,(EndTx) + CALL FSzSbr + POP HL + ADD HL,BC + LD DE,SizNNN ;show it as "file size" + CALL BCDCon + LD A,(Modify) + OR A ;file changed? + LD A,'Y' + JR NZ,Info2 + LD A,'N' +Info2: LD (ModQQQ),A + LD HL,InfMsg ;now display the data + CALL DspLp + CALL UnAlt + CALL ESCLp + JP SetAl +; +FSzSbr: LD BC,0 ;count a block +FSzLp: LD A,E ;done? + SUB L + LD A,D + SBC A,H + RET C + LD A,(HL) + INC HL + INC BC ;count character + CP CR + JR Z,FSz1 ;and (missing) LF? + CP X + JR C,FSzLp ;and (hidden) space? +FSz1: INC BC + JR FSzLp +; +; +; Blank the screen +; +Blank: LD A,(WinFlg) ;window off first (will lose text) + OR A + CALL NZ,Window + LD HL,CsrOff ;### + CALL CtlStr ;### + LD HL,TInit + CALL CtlStr + CALL ESCLp + CALL DoHdr + JP SetAl +; +; +;Move cursor to the beginning of text +; +Top: LD HL,(BegTx) + CALL MoveL ;Move + CALL TopV ;Adjust cursor + CALL LftH + LD HL,1 + LD (CurLin),HL + JP SetAl +; +; +;Move cursor to the last character of text +; +Bottom: LD HL,(BefCu) ;for CountL + LD (LastCu),HL + LD HL,(EndTx) + CALL MoveR ;Move + CALL BotV ;Adjust cursor + CALL RitH + CALL CountL + JP SetAl +; +; +; Queue: move to next line in ZCPR queue +; +Queue: LD BC,Z3MSG + CALL Z3EAdr + JP Z,Error7 ; no Z3 message buffers + LD D,B ; addr of Z3MSG to DE + LD E,C + LD HL,RegNum+1 ; current register addr + LD A,(HL) + CP MsgUsr-2+MsgNmU ; time to wrap around? + JR NZ,QueNxt +QueWrp: LD A,MsgUsr-2 ; yes + LD (HL),A ; update it +QueNxt: INC (HL) ; next register + INC (HL) +RegNum: LD HL,MsgUsr-2 + ADD HL,DE ; point to next line # + LD C,(HL) + INC HL + LD B,(HL) ; line # to BC + LD A,B + OR C + JP NZ,ZipTo2 ; go to it + LD HL,RegNum+1 ; is first register empty? + LD A,(HL) + CP MsgUsr + JP Z,Error7 ; yes, error + JR QueWrp ; no, wrap around +; +; +;QUICK cursor movements +; +QuikMk: CALL NdCnt ;look for next place marker + JR C,QkMk1 + LD HL,(AftCu) + LD A,EOF ;marker + CPIR + JP Z,QikB1 ;found? rest same as ^QB +QkMk1: CALL BgCnt ;not? try from top + JR C,QkMk2 + LD HL,(BegTx) + LD A,EOF + CPIR + JP Z,QikB0 ;found? rest same as ^QB +QkMk2: JP Error7 ;not? error. +; +QuikLf: LD E,1 ;move left to start of line + CALL CrLft + RET C + LD A,1 + LD (CurCol),A ;(useful for format subroutines) + CALL MoveL + CALL LftH + JP IfScl +; +QuikRt: CALL NdCnt ;move right to end of line + JP C,ColCnt + CALL Fetch + JP Z,ColCnt + CALL Right + RET C + JR QuikRt +; +QuikUp: LD A,(Vert) ;move up to top of screen + DEC A + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QUlp: PUSH BC + CALL Up + POP BC + DJNZ QUlp + CALL SetNo + POP AF ;restore col + JP SkQUD +; +QuikDn: LD A,(TxtLns) ;move down to end of screen + LD HL,Vert + SUB (HL) + RET Z + LD B,A + LD A,(CurCol) + PUSH AF +QDlp: PUSH BC + CALL Down + POP BC + DJNZ QDlp + CALL SetNo + POP AF + JP SkQUD +; +ZipTo: LD HL,PageQ ;zip to given page + LD A,(PgLen) + OR A + JR Z,ZipTo0 + LD A,(FMode) + CP 'N' + JR NZ,ZipTo1 +ZipTo0: LD HL,LineQ ;or line, in N mode +ZipTo1: CALL Prompt + LD BC,1 + CALL GetNbr + JP C,Error7 + JP Z,Error7 + LD A,(FMode) + CP 'N' + JR Z,ZipTo2 + LD A,(PgLen) ;(calculate line) + OR A + JR Z,ZipTo2 + LD D,0 + LD E,A + LD L,D + LD H,D + DEC BC +ZipMul: LD A,B + OR C + JR Z,ZipMF + ADD HL,DE + DEC BC + JR ZipMul +ZipMF: INC HL +ZipMF2: LD B,H + LD C,L +ZipTo2: PUSH BC + CALL Top + POP DE ;desired line + LD A,D + OR E + JR Z,ZipXit + DEC DE ;lines to move down + XOR A + OR D + JR Z,ZipLpF +ZipLp: PUSH DE ;do multiples of 256 + LD E,0 ;(256) + CALL CrRit + DEC HL + CALL MoveR + POP DE + DEC D + JR NZ,ZipLp +ZipLpF: XOR A + OR E + JR Z,ZipTo3 + CALL CrRit ;do remainder + DEC HL + CALL MoveR +ZipTo3: CALL MidV + CALL RitH + CALL CountS +ZipXit: JP SetAl +; +; +;Move cursor up. +; +Up: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,2 ;start of last line + CALL CrLft + RET NZ ;TOF? quit + PUSH HL + CALL EdgeU + CALL DecV + POP HL + CALL MoveL +SkUpDn: LD A,(CurCol) ;where we were +SkQUD: CALL GoCol + RET Z ;exact? + JP IfScl ;may need to scroll +; +; +;Move cursor down. +; +Down: CALL TestCu ;no delays here + CALL NZ,ShoCu1 + LD E,1 ;start of next line + CALL CrRit + DEC HL + JR NC,Sk1Dn ;was there one? + RET NZ ;EOF? quit + LD HL,(EndTx) + LD A,(HL) ;Get that last byte + CP CR + RET NZ ;no next line +Sk1Dn: PUSH HL + CALL EdgeD + CALL IncV + POP HL + CALL MoveR + JR SkUpDn +; +QuikLc: LD HL,(SavLin) + CALL ZipMF2 + LD A,(SavCol) +; +; +GoCol: DEC A ;restore cursor to column A + RET Z + LD HL,(HorFlg) ;don't change show status + PUSH HL + PUSH AF + CALL ColCnt ;where are we? + LD IY,CurCol + JR GRCent +GRCLp: CALL NdCnt + JR C,GRCF ;stop at EOF + CALL Fetch + JR Z,GRCF ;stop at CR + CP TAB ;tabs are special + JR NZ,GRC1 + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A +GRC1: INC (IY) ;Keep CurCol updated + CALL Right +GRCent: POP AF + PUSH AF + CP (IY) ;there yet? + JR NC,GRCLp +GRCF: POP AF + POP HL + LD (HorFlg),HL + INC A + SUB (IY) ;set Z if exact + RET +; +; +;Move cursor one to the left (C=cannot) +; +Left: CALL Space ;Any space left? + RET C + CALL BgCnt ;Are we at front? + RET C + CALL EdgeL + LD HL,(BefCu) ;Look back + LD A,(HL) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1Lt ;No, just move + RES 7,(HL) ;Yes, unhide it + LD A,' ' + INC HL +Sk1Lt: DEC HL ;Back up + LD (BefCu),HL + CALL InsrA1 ;store byte ahead + CP TAB ;Was a TAB moved + JR Z,LftTab + CP CR ;Was a CR moved? + JR Z,LftCR + CALL DecH ;no + OR A + RET NZ + JP IfScl ;at left mgn...scroll? +; +LftCR: CALL RitH ;special cases - scrolling + CALL DecV + CALL ColCnt + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl + OR A + RET +LftTab: LD A,(Horiz) + DEC A + CALL Z,HorScl ;need to scroll if at left + CALL LTabH + OR A + RET +; +; +;Move cursor one to the right +;(return C if can't, char passed in A) +; +Right: CALL Space ;Any room left? + RET C + CALL NdCnt ;Already at end? + RET C + CALL EdgeR + CALL Fetch + JR NZ,Sk0Rt + PUSH HL + CALL TestCu ;change of line: no delays + CALL NZ,ShoCu1 + POP HL +Sk0Rt: LD A,(HL) + BIT 7,A ;Hidden space? + JR Z,Sk1Rt ;No, just move + LD (HL),' ' ;Yes, unhide it + AND 7FH + DEC HL +Sk1Rt: INC HL ;Bump pointer + LD (AftCu),HL + CALL Insrt1 ;put byte in behind + OR A ;and return it + PUSH AF + CP TAB ;TAB and CR are special + JR Z,RtTab + CP CR + JR Z,RtCR + CALL IncH ;no, just move + POP AF + RET +; +RtCR: CALL IfScl ;may have to scroll + CALL IncV ;adjust + CALL LftH + LD A,1 + LD (CurCol),A + POP AF + RET +; +RtTab: LD A,(View) + DEC A + LD HL,TabCnt + SUB (HL) + LD HL,Horiz + SUB (HL) + CALL C,HorScl ;at right, need to scroll + CALL TabH + POP AF + RET +; +; +;Word tab, delete +; +WdMxCh EQU 255 ;max chars to loop +; +WordRt: CALL Fetch ;Word tab right + JP Z,Right ;at EOL? special case + CALL IsBlnk ;on break? just find nonbreak + JR Z,WRlpF + LD B,WdMxCh +WRlp: CALL WRfBrk + JR Z,WRlpF + CP CR ;quit at CR + RET Z + DJNZ WRlp +WRlpF: LD B,WdMxCh +WRlp2: CALL WRfBrk + RET NZ + DJNZ WRlp2 + RET +WRfBrk: PUSH BC + CALL Right + JR C,WRfBrX + CALL IsBlnk ;then nonbreak + CALL NZ,IsPunc + PUSH BC +WRfBrX: POP BC + POP BC + RET +; +WordLf: CALL FetchB ;Word tab left + CP CR ;at BOL? Special case + JP Z,Left + LD B,WdMxCh +WLlp: CALL IsParB ;find a nonbreak + CALL NZ,IsPunB + JR NZ,WLlpF + CP CR ;quit at CR + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp +WLlpF: CALL Left + LD B,WdMxCh +WLlp2: CALL IsParB ;then a break + CALL NZ,IsPunB + RET Z + PUSH BC + CALL Left + POP BC + RET C + DJNZ WLlp2 + RET +; +WordDl: CALL Fetch ;Word Delete + JP Z,EChar ;at BOL? special case + CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNB ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNB: LD B,WdMxCh +WDlp2: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak + CP CR ;but quit at CR + RET Z + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2 + RET +WDlB: LD B,WdMxCh +WDlp: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET Z ;delete till reak + PUSH BC + CALL EChar + POP BC + DJNZ WDlp + RET +; +Join: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + JR Z,WDlNBx ;on break? delete till nonbreak + CALL IsParB + CALL NZ,IsPunB + PUSH AF + CALL WDlB ;nonbreak? delete till break + POP AF + RET NZ ;BOW? delete till nonbreak too +WDlNBx: LD B,WdMxCh +WDlp2x: CALL IsPaPu ;combined CALL IsPara/CALL NZ,IsPunc + RET NZ ;delete till nonbreak (including CRs) + PUSH BC + CALL EChar + POP BC + DJNZ WDlp2x + RET +; +IsPaPu: CALL IsPara + CALL NZ,IsPunc + RET +; +; +;Move cursor ahead one page +; +PageF: CALL SetAl + LD A,(TxtLns) + DEC A + LD E,A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgF1 + INC A + LD E,A +PgF1: CALL CrRit ;Point that many CRs down + DEC HL ;Back off one byte + JP C,Bottom + JP NZ,Bottom + LD DE,(BefCu) ;Prepare Count + LD (LastCu),DE + CALL MoveR ;Move cursor gap + CALL CountL + JR LDaGoC ;relocate cursor +; +; +;Move cursor back one page +; +PageB: CALL SetAl + LD A,(TxtLns) + LD E,A + DEC A ;default scroll + LD HL,Ovlap + SUB (HL) + JR C,PgB1 + ADD A,2 + LD E,A +PgB1: CALL CrLft ;Point that many CRs back + JP C,Top + JP NZ,Top + LD DE,(AftCu) ;Prepare Count + LD (LastCu),DE + CALL MoveL ;Move cursor gap + CALL CountR +LDaGoC: LD A,(CurCol) + JP GoCol ;relocate cursor +; +; +;Scroll screen 1/4 vertically +; +ShftD: LD A,(TxtLns) ;Down + SRL A + SRL A + INC A + LD B,A +LDLp: PUSH BC + CALL DecVO + JR NZ,LDLpF + CALL Down ;oops, cursor already on top + CALL DecVO +LDLpF: POP BC + DJNZ LDLp + JP SetAl +; +ShftU: LD A,(TxtLns) ;same, up + SRL A + SRL A + INC A + LD B,A +LULp: PUSH BC + CALL IncVO + JR NZ,LULpF + CALL Up ;oops, cursr already on bottom + CALL IncVO +LULpF: POP BC + DJNZ LULp + JP SetAl +; +Scr1LD: CALL DecVO ;FAST one-line scrolls + JR NZ,ScLD1 + CALL Down ;oops, already on top + CALL DecVO +ScLD1: LD HL,DelL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + LD A,(TxtLns) + LD B,A + JP ShoLn ;re-show last line +; +Scr1LU: LD HL,(CurLin) + LD DE,(Vert) + LD D,0 + OR A + SBC HL,DE + RET Z ;oops, nowhere to go + CALL IncVO + JR NZ,ScLU1 + CALL Up ;oops, already on bottom + CALL IncVO +ScLU1: LD HL,InsL + CALL ScrlUD + JP C,SetAl ; no scroll + CALL SmlDly + JP ShoLn1 +; +;Scroll screen 32 cols horizontally +; +ShftR: LD HL,Horiz ;INcrease screen scroll (right) + LD A,(HL) + SUB 32+1 + RET C + INC A + LD (HL),A + LD HL,NSkip + LD A,(HL) + ADD A,32 + JR ShftX +; +ShftL: LD A,(Horiz) ;DEcrease scroll (left) + ADD A,32 + LD HL,View + CP (HL) + RET NC + LD (Horiz),A + LD HL,NSkip + LD A,(HL) + SUB 32 + RET C +; +;Make current line top +; +ShftX: LD (HL),A + JP SetAl +; +MakTop: CALL TopV ;gee boss, that was easy, huh? + JP SetAl +; +; +;FIND/REPLACE +; +;Find next occurance of a given string. +; +Find: CALL FndSub + JP C,Error7 + CALL ShoLn1 +; + LD A,(FGlobl) + OR A + JR Z,RpFind + LD A,(FBackw) ;global search: backwards? + OR A + JR Z,FndBck + CALL Bottom ;...yes, goto bottom of file + JR RpFind +FndBck: CALL Top ;...no, goto top of file +RpFind: LD A,(FndStr) ;length + OR A + RET Z ;no string, quit + LD A,(FBackw) + OR A ;backward? + JR NZ,RpF5 + CALL NdCnt ;number to scan + JP C,Err4x + LD HL,(EndTx) + LD DE,(FndStr) ;string length + XOR A + LD D,A ;extend to 16 bits + SBC HL,DE +RpSsLp: INC HL + BIT 7,(HL) ;soft space? + JR Z,RpSsNo ;nope + INC A ;count soft spaces? +RpSsNo: DEC E ;decrement string length + JR NZ,RpSsLp + ADC A,C + LD C,A + LD A,B + ADC A,0 + LD B,A + LD HL,FndStr + LD A,C + SUB (HL) + LD C,A ;less string length + LD A,B + SBC A,0 + LD B,A + JR C,Err4x + INC BC ;in case last + LD HL,(BefCu) + LD (LastCu),HL ;Mark position + LD HL,(AftCu) + LD A,(ChgFlg) ;was last operation change? + OR A + JR NZ,RpF1 + INC HL ;NO, start at next byte + DEC BC ;YES, start at this byte +RpF1: LD A,B + OR C + JR Z,Err4x ;gotta have bytes + LD A,(FUCase) + CP 0C3H ;ucase? (groan) + JR Z,SlowFi + LD A,(FndStr) ;only one char? (groan) + DEC A + JR Z,SlowFi + LD DE,(FndStr+1) ;space in char 1 or 2? (groan) + LD A,' ' + CP D + JR Z,SlowFi + CP E + JR Z,SlowFi + JR FastFi +; +Err4x: LD A,(FGlobl) + OR A + JP Z,Error4 ;not found + LD HL,(OldLin) + CALL ZipMF2 + LD A,(OldCol) + CALL GoCol + JP Error5 +; +RpF5: CALL BgCnt ;backward: number to scan + JR C,Err4x ;EOF? + LD HL,(AftCu) + LD (LastCu),HL ;Mark position + LD HL,(BefCu) + JR BackFi +; +FastFi: LD A,B ;find lead char FAST with CPIR + OR C + JR Z,Err4x + LD A,(FndStr+1) + CPIR + JP PE,FstFi1 ;jump if P/V=1 (BC-1 is not 0) + JR NZ,Err4x ;NOT found +FstFi1: PUSH BC + PUSH HL + LD C,0 ;no hidden spaces involved + CALL FndChk ;rest of string? + POP HL + POP BC + JR NZ,FastFi ;no match, keep going + LD C,0 + JP Found +; +SlowFi: LD A,(FndStr+1) ;find lead char the slow way + LD (LdChar+1),A ;(spaces or upcase involved) + LD D,H + LD E,L + ADD HL,BC + EX DE,HL + LD C,0 +Lp1Fi: LD (FindSv),BC ;save hidden space status + CALL GetNx + CALL FUCase +LdChar: CP 0 ;<---- + JR Z,Lp1Fi1 ;got one +Lp1Fi0: LD A,H + XOR D + JR NZ,Lp1Fi + LD A,L + XOR E + JR NZ,Lp1Fi + JR Err4x +Lp1Fi1: PUSH BC + PUSH DE + PUSH HL + CALL FndChk ;rest of string? + POP HL + POP DE + POP BC + JR NZ,Lp1Fi0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR Found +; +BackFi: LD A,(FndStr+1) ;find lead char backwards + LD (LdChr2+1),A + PUSH HL + OR A + SBC HL,BC + PUSH HL + POP DE + POP HL + INC HL + INC HL ;adjust for kludge below + LD C,0 +Lp1BF: LD A,C + LD (FindSv),A ;clear hidden space status + OR A + JR Z,Lp1BFa + DEC C + LD A,' ' + JR Lp1BFb +Lp1BFa: DEC HL ;back up + DEC HL + LD A,(HL) + INC HL ;simulate GetNx in reverse + BIT 7,A + JR Z,Lp1BFb + INC C +Lp1BFb: AND 7Fh + CALL FUCase +LdChr2: CP 0 ;<----- + JR Z,Lp1BF1 ;got one +Lp1BF0: LD A,H + XOR D + JR NZ,Lp1BF + LD A,L + XOR E + JR NZ,Lp1BF + JP Err4x +Lp1BF1: PUSH HL + PUSH DE + PUSH BC + CALL FndChk ;rest of string? + POP BC + POP DE + POP HL + JR NZ,Lp1BF0 ;no, keep trying + LD BC,(FindSv) ;YES, indicate whether lead is hidden + JR FoundB +; +FndChk: LD A,(FndStr) ;is (HL) a hit? + DEC A + RET Z ;just one char: already matched + LD B,A + LD DE,FndStr+2 ;start at char2 +Lp1FC: CALL GetNx + CALL FUCase + EX DE,HL + CP (HL) + EX DE,HL + JR Z,Sk1FC + LD A,(DE) ;hmm, no match + PUSH HL + LD HL,WildCd ;consider wildcard + CP (HL) + POP HL + RET NZ ;NOPE. +Sk1FC: INC DE ;match, keep on + DJNZ Lp1FC + RET ;YES. +; +; +Found: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back to char1 + DEC HL ;put cursor BEFORE char1 + CALL MoveR + LD HL,(AftCu) ;Hidden space there? + BIT 7,(HL) + JR Z,Found1 + OR A ;need to be on it? + JR Z,Found1 + LD A,(HL) + AND 7FH ;Yep, unhide it + LD (HL),' ' + CALL Insrt1 +Found1: CALL MidV ;Center on screen +Chged0: CALL CountL ;Adjust line number +Chged: CALL RitH ;Adjust cursor + LD HL,ChgFlg + BIT 0,(HL) + JP Z,SetAl ;find? redisplay + LD HL,FndStr + XOR A + ADD A,(HL) + JR Z,Chgd1 + LD C,A ;change: CR involved? + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl ;yes +Chgd1: LD HL,ChgStr + XOR A + ADD A,(HL) + JP Z,SetCu ;no + LD C,A + LD B,0 + INC HL + LD A,CR + CPIR + JP Z,SetAl + JP SetCu +; +FoundB: LD A,C ;(note C=1 if began with hidden space) + DEC HL ;point back before char1 + CALL MoveL ;Move to found string + LD HL,(AftCu) ;hidden space there? + BIT 7,(HL) + JR Z,FounB1 + OR A ;yes, need to be on it? + JR Z,FounB1 + LD A,(HL) ;Yes, unhide it + AND 7Fh + LD (HL),' ' + CALL Insrt1 +FounB1: CALL MidV ;Center on screen + CALL RitH ;Adjust cursor + CALL CountR ;Adjust line number + JP SetAl +; +FndSub: LD HL,FindQ ;Get Find string + CALL Prompt + CALL GetStr ;Put string in 80 + DW FndStr+1 + LD DE,FndStr + LD (DE),A + RET Z ;no string + INC DE + XOR A + LD (ChgFlg),A ;find, not change + LD (FBackw),A ;not (yet) backwards + LD (FGlobl),A ;not (yet) global + LD A,0C3H ;(JP) + LD (FUCase),A ;ignore case + LD HL,DMA + LD A,(HL) + CP '/' + JR NZ,FndSb2 + INC HL +FndSL1: LD A,(HL) + INC HL + OR A + RET Z + CP '/' ;do /options/ + JR Z,FndSb2 + CALL UCase + CP 'C' + JR Z,FOptC + CP 'B' + JR Z,FOptB + CP 'G' + JR Z,FOptG + SCF + RET +FOptC: LD A,0C9H ;(RET) respect case + LD (FUCase),A + JR FndSL1 +FOptB: LD (FBackw),A ;backward + JR FndSL1 +FOptG: LD A,0FFH + LD (FGlobl),A + JR FndSL1 +FndSb2: LD B,0 +FndSL2: LD A,(HL) ;move string in + INC HL + CALL FUCase + OR A + LD (DE),A + JR Z,FndSLF + INC DE + INC B + JR FndSL2 +FndSLF: LD A,B ;count + LD (FndStr),A + RET +; +FUCase: JP UCase ;<--- becomes RET +; +;Change found string [this entry NOT currently in use] +; +;Change: CALL ChgSub ;get string +; +RepChg: LD HL,(BefCu) ;mark position + LD (LastCu),HL + LD A,(FndStr) + OR A + JR Z,RpCh1F ;no string + LD B,A ;count to erase +RpCh1: PUSH BC + CALL EChar + POP BC + JP C,Error7 + DJNZ RpCh1 +RpCh1F: LD HL,ChgStr ;point to string + LD A,(HL) ;count to replace + OR A + JR Z,RpCh3 ;quit if no new string + LD B,A + PUSH BC +RpCh2: INC HL + PUSH BC + PUSH HL + LD A,(HL) + CALL Insrt + POP HL + POP BC + CALL C,Error1 ;out of memory + DJNZ RpCh2 + POP BC + LD A,(FBackw) + OR A +RpCh3: JP Z,Chged0 +RpCh4l: PUSH BC + CALL Left + POP BC + RET C + DJNZ RpCh4l + CALL CountR + JP Chged +; +ChgSub: LD A,0FFH ;say we've done a change + LD (ChgFlg),A + LD HL,ChgQ + CALL Prompt + CALL GetStr ;Put string in 80 + DW ChgStr+1 + PUSH AF + CALL ShoLn1 ;may need this later + POP AF + LD DE,ChgStr + LD (DE),A + RET Z ;do not LDIR with B=0 + INC DE + LD C,A + LD B,0 + LD HL,DMA + LDIR ;Move string in + XOR A + LD (DE),A ;zero terminate it + RET +; +;Global replace +; +Rplace: LD A,0FFH + LD (YNFlg),A + CALL FndSub + JP C,Error7 + LD A,(FndStr) + OR A + JP Z,ShoLn1 ;no string? + LD A,(FGlobl) ;global replace? + OR A + JR Z,RplcGo + LD A,(FBackw) ;backward? + OR A + JR Z,RplTop + CALL Bottom ;goto end + JR RplcGo +RplTop: CALL Top ;goto start +RplcGo: LD A,(MacFlg) + PUSH AF ;(got to do this before Chg Input) + CALL ChgSub + POP AF + OR A + CALL NZ,Global ;within Macro: force Global + CALL RepFCh ;do first one + JR C,RplLpQ ;none found? +RplLp: CALL Keybd + CP ESC ;abort? + JR Z,RplLpX + XOR A + LD (FGlobl),A ;turn off global + CALL RepFCh + JR NC,RplLp +RplLpX: LD A,(EdErr) + CP 4 ;suppress "not found" error + CALL Z,Error0 +RplLpQ: CALL XLoud ;turn CONOut back on + JP SetAl +; +;Repeat last find/replace +; +Repeat: LD A,0FFH + LD (YNFlg),A + CALL RepFCh + LD A,(YNFlg) + OR A + JR Z,RplLp + RET +; +RepFCh: CALL RpFind ;[entry from Replace] + LD A,(EdErr) ;return Carry if not found or error + OR A + SCF + RET NZ ;not found + LD A,(ChgFlg) + OR A + RET Z ;find only, all done + CALL ShoAll ;replace, gotta show it + CALL YesNo ;..and ask + JR C,RepFC0 + JR Z,RepFC1 + LD A,(FBackw) ;NC,NZ = No + OR A + LD A,(FndStr) + CALL Z,GoRtA ;skip ahead + OR A + RET +RepFC0: RET NZ ;C,NZ means Esc: abort +RepFC1: CALL RepChg ;Z (C or NC) means Yes + LD A,(EdErr) + CP 1 ;error? set carry + CCF + RET +; +YesNo: LD A,(YNFlg) ;return C=abort, Z=yes + OR A + SCF + RET Z ;"*" mode? Z,C = yes,global + CALL Loud ;MUST see this +YesNo1: LD DE,DspEsc ;entry for hyphenation Y/N + CALL GoTo + CALL MakAlt + LD HL,YNMsg ;say "Y/N/*" + LD B,4 + CALL BHLMsg + CALL UnAlt + CALL Cursr + CALL KeyIn ;MUST come from keyboard + PUSH AF + LD DE,DspEsc ;clean up + CALL GoTo + LD A,(NoHdrF) + OR A + CALL Z,MakAlt + LD B,4 + CALL BBlank + CALL UnAlt + POP AF + CP ESC ;abort? + JR NZ,YN1 + OR A + SCF ;C, NZ = yes + RET +YN1: CP '*' + JR NZ,YN2 +Global: CALL XQuiet + XOR A + LD (YNFlg),A ;set global flag + SCF + RET ;Z,C = yes,globally +YN2: AND 5FH ; upper case + CP 'Y' + RET Z ;Z,NC = yes,once + CP 'N' + JR NZ,YesNo1 + OR A + RET ;NZ,NC = no +; +; +;Variable Tabs. +;"VTList" is a list of settings, increasing order, zero fill +; +VTTog: LD HL,VTFlg ;toggle variable on/off + CALL ToggHL + CALL RulFix +VTshow: LD A,(VTFlg) ;requires header display + OR A + LD HL,VTon + JR NZ,VTsho1 + LD HL,TogOff +VTsho1: LD DE,DspTab + JP TogSho +; +; +VarTab: CALL ColCnt ;advance to next VT setting + LD B,VTNum + LD HL,VTList +VTlp1: CP (HL) ;find it + JR C,VTb2 + INC HL + DJNZ VTlp1 + RET ;none, no action. +VTb2: LD A,(HL) + PUSH HL + DEC A + LD HL,View + CP (HL) + CALL NC,HorScl ;may need to scroll + POP HL + LD A,(InsFlg) + OR A ;is insert on? + LD A,(HL) ;column to move to + JP Z,MvCol + JP MvColI ;move by inserting spaces +; +TaBack: CALL ColCnt ;retreat to last tab setting + DEC B + RET Z + LD A,(VTFlg) + OR A + JR Z,BThard + LD C,B + XOR A + LD B,VTNum + LD HL,VTList+VTNum-1 +BTlp1: CP (HL) ;skip 0s + JR NZ,BTb1 + DEC HL + DJNZ BTlp1 + RET ;no tabs at all, no action +BTb1: LD A,C +BTlp2: CP (HL) ;find it + JR NC,BTb2 + DEC HL + DJNZ BTlp2 + JP QuikLf ;no more left, go to col 1 +BTb2: LD A,(HL) ;that's it + JR BTabX +BThard: LD A,(TabCnt) ;back to last multiple + CPL + DEC B + AND B + INC A +BTabX: PUSH AF + CALL QuikLf ;go all the way back + POP AF + JP MvCol ;then go there +; +; +VTSet: LD HL,ColQ ;Set tab(s) + CALL Prompt + CALL GetStr + DW 0 + LD A,(CurCol) ;default is Here + JR Z,VTSt01 ;nothing entered? + LD HL,DMA + LD A,(HL) + CP '@' + JR Z,VTSInt ;interval specified? + CP '#' + JR Z,VTSGrp ;group? + EX DE,HL + CALL GetNN ;nope, single tab set + JR Z,VTErr +VTSt01: CALL VTStCl + JR C,VTErr + JR VTStX +VTStCl: LD E,A ;[sbr: set VT here] + LD A,(VTList+VTNum-1) + OR A + SCF + RET NZ ;must be room in list + LD BC,VTNum + LD HL,VTList +VTSlp1: LD A,(HL) ;find it + OR A + JR Z,VTSt1 + CP E + RET Z ;(quit if already set) + JR NC,VTSt2 + INC HL + DEC C + JR NZ,VTSlp1 + DEC HL ;last place +VTSt1: LD (HL),E ;add at end + OR A + RET +VTSt2: LD A,E + LD HL,VTList+VTNum-2 ;make room here + LD DE,VTList+VTNum-1 + DEC BC + LDDR + LD (DE),A ;put it in + OR A + RET +VTErr: JP Error7 +; +VTSInt: LD DE,VTList ;"@" interval specified + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL + INC DE + CALL GetNN + OR A + JR Z,VTStX + LD C,A + INC A ;"@n" means n+1, 2n+1 etc + LD DE,VTList + LD B,VTNum +VTSlp2: LD (DE),A + INC DE + ADD A,C + JR C,VTStX + DJNZ VTSlp2 + JR VTStX +VTSGrp: LD DE,VTList ;'#' group specivied + LD B,VTNum + XOR A + CALL Fill ;clear all existing tabs + EX DE,HL +VTGlp: INC DE + CALL GetNN ;get one from list + OR A + PUSH DE + CALL NZ,VTStCl ;set it? + POP DE + JR C,VTErr + LD A,(DE) + OR A + JR NZ,VTGlp +VTClX: +VTStX: CALL ShoLn1 ;all done + JP RulFix +; +; +VTClr: LD HL,ColQ ;clear a tab + CALL Prompt + LD A,(CurCol) ;default is Here + CALL GetNum + JR C,VTErr + JR Z,VTErr + LD B,VTNum + LD HL,VTList +VTClp1: CP (HL) ;find it + JR Z,VTCl2 + INC HL + DJNZ VTClp1 + JR VTErr ;wasn't set +VTCl2: LD (HL),0 + DEC B + JR Z,VTClX ;was last, all done + LD D,H + LD E,L + INC HL + LD C,B + LD B,0 + LDIR ;delete it + XOR A + LD (DE),A ;zero fill + JR VTClX +; +; +; INSERTION FUNCTIONS +; +;Store a ctl-code in text +; +CtlP: LD HL,CPTog ;say "^P-_", get key + CALL Prefix + CALL XCase + CP DEL + JR Z,CtlP1 + CP ' ' ;error if not now ctl-char + RET Z ;(space cancels) + JP NC,Error2 ;invalid key +CtlP1: LD HL,BlkChr + CP (HL) ;don't allow block char + JP Z,Error2 ;invalid key + CP TAB ;tabs are special + JR Z,ITab + CP CR ;so are CRs + JP Z,ICRB1 + JR Sk2IC +; +IChar: CP ' ' ;Main menu entry: no control codes allowed + RET C +Sk2IC: PUSH AF + CALL ChkLM ;Check for left margin + JR NC,Sk2aIC + CALL UpToLM + CALL SetCu +Sk2aIC: POP AF + LD E,A + CP 7FH ;redo line if DEL/ctl + CCF + JR C,Sk3IC + CP ' ' +Sk3IC: CALL C,SetRCu + PUSH DE + CALL NC,XPutCh ;just show nice chars + POP DE + PUSH DE + LD A,E + CALL Insrt ;Put byte in + POP DE + RET C ;Full? + PUSH DE + LD A,(Horiz) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if at edge + CALL IncH ;Move cursor + CALL ChkIns ;adjust for insert mode + POP DE + LD A,E + CP ' ' + RET Z ;if not space + CP EOF + RET Z + LD HL,BlkChr + CP (HL) + RET Z + JP WdWrap ;check wordwrap +; +TabKey: LD A,(VTFlg) + OR A + JP NZ,VarTab ;maybe variable tabbing +ITab: LD A,TAB + CALL Insrt + RET C + CALL SetCu + CALL ChkIns + LD A,(Horiz) + LD HL,TabCnt + ADD A,(HL) + LD HL,View + CP (HL) + CALL NC,HorScl ;scroll if needed + JP TabH +; +;Do a carriage return +; +ICR: LD A,(DSFlg) + OR A + CALL NZ,ICR1 +ICR1: LD A,(InsFlg) + BIT 7,A ;Is insert flag on? + JR NZ,ICRB1 + CALL QuikRt ;noo... + LD A,(FMode) + CP 'N' + JR Z,ICR01 +ICR00: CALL FetchB ; in Document: make HCR + CP ' ' + JR NZ,ICR01 + CALL Delete + JR ICR00 +ICR01: CALL Cursr ;may need to show new HCR + CALL NdCnt ;Are we at end? + JR C,ICRB1 ;Yes, add a new line + CALL IfScl ;no, just move cursor + CALL Right + JP ChkAI +ICRB: CALL ICRB1 +ICRB0: LD A,(DSFlg) + OR A + RET Z + CALL InsSpc ;doublespace? add soft CRLF +ICRB1: XOR A + LD (NumTab),A + CALL IfScl + LD A,CR + CALL Insrt ;Put it in + RET C + LD A,(Vert) + LD HL,TxtLns + CP (HL) + CALL Z,ScrlU2 ;end of screen? scroll + CALL SetDn + CALL IncV ;Move cursor down + CALL LftH ;Move to start of line + JR ChkAI +ICRA: CALL ICRA1 + LD A,(DSFlg) + OR A + RET Z + LD A,' ' ;doublespace? add soft CRLF + CALL InsrtA +ICRA1: LD A,CR ;Used as ^N routine only + CALL InsrtA + RET C + CALL FetchB + CP CR + JR NZ,ICRAx + LD HL,InsL + CALL ScrUDx + RET NC +ICRAx: JP SetDn +; +; +;Check for insert mode +; +ChkIns: LD A,(InsFlg) + OR A ;INSERT on? + JP NZ,SetRCu ;Yes, all done + LD HL,(BefCu) + LD A,(HL) + CP EOF + JP Z,SetRCu + LD HL,BlkChr + CP (HL) + JP Z,SetRCu + LD HL,(AftCu) ;No, Look at the character + LD A,CR + CP (HL) ;Is it a CR? + RET Z ;Yes, leave it + LD A,TAB + CP (HL) ;TAB? redo line + CALL Z,SetCu + LD A,(ShoFlg) + PUSH AF + CALL EChar ;overwrite character + POP AF + LD (ShoFlg),A + RET +; +;Check for auto indent mode +; +ChkAI: LD A,(AIFlg) ;AI on? + OR A + RET Z + LD A,(DSFlg) + OR A + RET NZ ;done if doublespacing + CALL NdCnt ;add text at cmd? + JR C,ChkAll + LD A,(InsFlg) ;insert on? + OR A + JR Z,ChkALp +ChkAll: CALL QuikLf ;#inline version of IndPL + CALL BgCnt ;# / + RET C ;# / + CALL Up ;#/ + CALL CntSpc ;get indentation + PUSH BC ;back to this line + CALL QuikRt ;#inline version of IndNL + CALL Right ;#these are just like RfmNL/PL, + POP BC ;#except they DON'T skip over blank lines + LD A,B + CP TAB + LD A,(NumTab) + JR Z,ChkAtb + INC A + JP MvColI ;do it +ChkALp: CALL Fetch ;NO, just move to first nonspace + CP ' ' + JR Z,ChkAI1 + CP TAB + RET NZ +ChkAI1: CALL Right + JR ChkALp +ChkAtb: OR A + RET Z + DEC A + PUSH AF + CALL ITab + POP AF + JR ChkAtb +; +; +; DELETION FUNCTIONS +; +;UNdelete a character +; +Undel: CALL GpCnt ;Anything to undelete? + RET C + CALL ELret2 + LD HL,(AftCu) + DEC HL ;here goes + LD (AftCu),HL + LD A,(HL) + CP CR ;was it a CR? + JP Z,SetDn + JP SetRCu +; +UndlLn: CALL GpCnt ;Do a whole line + RET C + CALL ELret2 + LD A,B + OR A ;max 256 chars + JR Z,UdLn1 + LD BC,256 +UdLn1: LD HL,(AftCu) + DEC HL + DEC HL + LD A,CR + CPDR ;look for CR + RET NZ + INC HL + INC HL ;start of line + LD (AftCu),HL + JP SetDn +; +; +;Erase character to left of cursor (C=error) +; +Delete: CALL Left + RET C ;Fall through to EChar +; +; +;Erase character to right of cursor (C=error) +; +EChar: CALL NdCnt ;Anything to erase? + RET C + CALL ELret2 + CALL SetRCu + LD HL,(AftCu) + BIT 7,(HL) ;Hidden space? + JR Z,Sk1EC + CALL GpShft ;unhide it + LD HL,(AftCu) + LD A,(HL) + LD (HL),' ' + AND 7FH + DEC HL + LD (HL),A + RET +Sk1EC: LD A,(HL) + INC HL ;Move up, past character + LD (AftCu),HL ;Store updated value + CP CR + CALL Z,SetDn ;ate a CR? + OR A + RET +; +GpShft: CALL GpCnt ;Shift gap contents left (for Undel sake) + RET C + DEC BC + LD A,B + OR C + SCF + RET Z + LD HL,(BefCu) + INC HL + LD A,B + SUB 08H ;Maximum 2k worth + JR C,GpS1 + LD B,08H + ADD A,H + LD H,A +GpS1: LD D,H + LD E,L + INC HL + LDIR + OR A + RET +GpCR: CALL GpShft ;mark BOL for ^QU + RET C + LD A,CR + LD (DE),A + RET +; +; +;Line erase functions +; +Eline: LD HL,(AftCu) ;first left end + PUSH HL + CALL QuikLf + POP HL + LD (AftCu),HL + LD E,1 ;now right end + CALL CrRit + JR NC,Eline1 ;found CR? good + JR NZ,Eline2 ;EOF? return + LD HL,(EndTx) ;Cursor is in last line + INC HL +Eline1: LD (AftCu),HL +Eline2: CALL ELret2 + LD HL,DelL + CALL ScrUDx + JP C,SetDn + LD A,(TxtLns) + LD B,A + JP ShoLn +; +EOLine: LD E,1 ;Erase to EOL + CALL CrRit + JR NC,Sk1EO ;Found CR? good + RET NZ ;EOF? return + LD HL,(EndTx) ;cursor is in last line + LD A,(HL) + CP CR ;Is last byte a CR? + INC HL + JR NZ,Sk2EO ;No +Sk1EO: DEC HL ;Point at trailing CR +Sk2EO: PUSH HL + JR EBLret ;delete to there +; +EBLine: LD HL,(AftCu) ;Erase to BOL + PUSH HL + CALL QuikLf +EBLret: CALL GpCR ;delete to there + POP HL + CALL SetRCu +ELret: LD (AftCu),HL +ELret2: LD A,0FFh + LD (Modify),A + RET +; +E2Char: LD HL,CQTTog ;Erase to character + CALL Prefix + CP ESC + RET Z + CP 'U'-40h ;^U? + RET Z + LD (PrevCh),A +E2CLp: CALL EChar ;always eat first char + CALL NdCnt + RET C + CALL Keybd + CP ESC + RET Z + CALL Fetch + LD HL,PrevCh + CP (HL) + JR Z,E2CLpF + LD (PrvCh2),A + JR E2CLp +E2CLpF: CP CR + RET NZ + LD A,(FMode) + CP 'N' + RET Z + LD HL,PrvCh2 ;CR means HARD CR in Doc modes + LD A,(HL) + CP ' ' + RET NZ + LD (HL),CR + JR E2CLp +; +; +; BLOCK FUNCTIONS +; +;MARK Block start and termination +; +Block: CALL UnBlAb ;Remove any markers above + CALL UnBlB1 ;Remove all but last marker below +Blk01: LD A,(BlkChr) ;mark it now + JP Sk2IC +; +Termin: CALL UnBlA1 ;Remove all but first marker above + CALL UnBlBl ;Remove any markers below + JR Blk01 +; +Unmark: CALL UnBlAb ;Remove all block markers + CALL UnBlBl + RET +; +;Move cursor to block start +; +QikBlk: CALL IsBlk + EX DE,HL + INC HL + BIT 0,A + JP Z,Error7 ;must be marked + BIT 6,A + JR NZ,QikB1 +QikB0: CALL MoveL ;before cursor (entries from QuikMk) + JR QikB2 +QikB1: DEC HL ;after cursor + CALL MoveR +QikB2: CALL CountS ;Adjust count + CALL RitH ;Adjust cursor + CALL MidV + JP SetAl +; +;Basic query returns: +; A= {bit 7=gap in block; 6=start after gap; 1=block marked; 0=start marked} +; DE,HL= start, end (if marked) +; +IsBlk: LD IX,IsBVal + LD (IX),0 ;result byte + CALL BgCnt + JR C,IsB1 + LD A,(BlkChr) ;look before cursor + CPIR + JR NZ,IsB1 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + JP PO,IsB0 + CPIR + JR NZ,IsB0 + SET 1,(IX) ;found end + DEC HL +IsB5: LD A,(IX) ;exit + RET +IsB0: SET 7,(IX) ;straddle + JR IsB1a +IsB1: SET 6,(IX) ;block after cursor +IsB1a: CALL NdCnt ;now look after cursor + JR C,IsB5 + LD HL,(AftCu) +IsB3: LD A,(BlkChr) ;search loop + CPIR + JR NZ,IsB5 + BIT 0,(IX) + JR NZ,IsB2 + SET 0,(IX) ;found start + LD D,H + LD E,L + DEC DE + LD A,B + OR C + JR Z,IsB5 + JR IsB3 +IsB2: SET 1,(IX) ;found end + DEC HL + JR IsB5 +; +; +UnBlA1: CALL BgCnt ;undo all but 1st marker above + RET C + LD A,(BlkChr) + CPIR + JP PE,UnBA01 ;one? leave and look for more + RET ;no more, finished +UnBlAb: CALL BgCnt ;undo all markers above + RET C +UnBA01: LD A,(BlkChr) + CPIR + RET NZ ;none, finished + CALL SetAl + PUSH BC + PUSH HL + LD D,H + LD E,L + DEC DE + CALL LCnt + JR C,UnBA02 + LDIR ;remove it +UnBA02: DEC DE + LD (BefCu),DE + POP HL + DEC HL + POP BC + LD A,B + OR C + JR NZ,UnBA01 + RET +; +UnBlB1: CALL NdCnt ;undo all but 1st marker below + RET C + LD HL,(EndTx) + LD A,(BlkChr) + CPDR + JP PE,UnBB01 ;one, leave and continue + RET ;none, finished +UnBlBl: CALL NdCnt ;undo all markers below + RET C + LD HL,(EndTx) +UnBB01: LD A,(BlkChr) + CPDR + RET NZ ;none, finished + CALL SetDn + PUSH BC + PUSH HL + LD D,H + LD E,L + INC DE + CALL RCnt + JR C,UnBB02 + LDDR ;remove it +UnBB02: INC DE + LD (AftCu),DE + POP HL + INC HL + POP BC + LD A,B + OR C + JR NZ,UnBB01 + RET +; +;Erase Block +; +EBlock: CALL IsBlk + BIT 1,A ;must be marked + JP Z,Error7 + BIT 7,A + JR NZ,EPrt3 ;straddles cursor? + BIT 6,A ;is it after cursor? + JR NZ,EPrt2 + LD B,H ;no, before cursor + LD C,L + LD HL,(BefCu) + SBC HL,BC ;bytes to move + PUSH HL + LD H,B + LD L,C + POP BC + JR Z,EPrt1a + INC HL + LDIR +EPrt1a: DEC DE + LD (BefCu),DE + JR EPrtRt +EPrt2: EX DE,HL ;it's after cursor + LD BC,(AftCu) + PUSH HL + SBC HL,BC + LD B,H + LD C,L + POP HL + JR Z,EPrt2a + DEC HL + LDDR +EPrt2a: INC DE + LD (AftCu),DE + JR EPrtRt +EPrt3: DEC DE ;cursor straddles it + LD (BefCu),DE + INC HL + LD (AftCu),HL +EPrtRt: CALL RitH ;Adjust cursor + CALL CountS + CALL ELret2 + JP SetAl +; +;Block Copy +; +Copy: CALL IsBlk + AND 82H ;must be marked, not straddled + CP 2 ;(bit 1 set, 7 clear) + JP NZ,Error7 + CALL CmpLng ;compute length + RET Z ;was empty + CALL CpSafe + JR NC,Copy02 ;okay, go do it + CALL Cmprs ;try to get more room + CALL IsBlk + CALL CmpLng ;compute length now + CALL CpSafe ;well? + JP C,Error1 ;REALLY won't fit +Copy02: LDDR + INC DE + LD (AftCu),DE + CALL RitH ;adjust cursor + CALL CountS + CALL ELret2 + JP SetDn +; +CmpLng: DEC HL + INC DE + PUSH HL + INC HL + SBC HL,DE ;compute length now + LD B,H + LD C,L + POP HL + LD DE,(AftCu) + DEC DE + RET +; +CpSafe: PUSH HL ;Set C if BC bigger than gap + PUSH BC + CALL GpCnt + LD H,B + LD L,C + POP BC + SCF ;(just to be safe) + SBC HL,BC + POP HL + RET +; +;Block Move +; +MovBlk: CALL Copy ;first copy + LD A,(EdErr) + OR A + RET NZ + JP EBlock ;then delete +; +; +; DISK FUNCTIONS +; +;View Directory +; +Dir: LD HL,DirQ + CALL Prompt + LD A,8+1 ;ask for Duu: or NDR name (8 chars max) + CALL GSEnt + DW 0 + PUSH AF + LD A,(FCB) ;defaults + LD B,A + LD A,(FCBU) + LD C,A + POP AF + JR Z,Dir00 + LD B,A + LD HL,DMA +DirULp: LD A,(HL) + CALL UCase ;new D (?) + LD (HL),A + INC HL + DJNZ DirULp + CP ':' + JR NZ,Dir0x ;jump if not a ":" + DEC HL + LD (HL),0 +Dir0x: LD DE,DMA + CALL NdrChk + JR NZ,Dir00 ;is an NDR name + LD A,(DE) ;new D (?) + CP '0' + JP C,Error7 ;<'0', not even a user # + CP '9'+1 + JR C,Dir0 ;jump is just a user # + SUB 'A'-1 + CP 17 ;drive letter > 'P'? + JP NC,Error7 ;yep.. a no no + LD B,A + INC DE +Dir0: PUSH BC + CALL GetNN ;new uu + POP BC + JR NC,Dir0a + LD A,(FCBU) ; fetch user # + JR Dir0y +Dir0a: CP 32 ;0-31 ok + JP NC,Error7 +Dir0y: LD C,A +Dir00: PUSH BC + LD E,C + LD C,USRN + CALL BDOSep ;set user + POP BC + LD HL,FCBBuf + LD (HL),B ;and drive + INC HL + LD (HL),'?' ;set up *.* FCB + LD DE,FCBBuf+2 + LD BC,10+1 + LDIR ; wildcard filename, type and extent + LD (HL),0 + LD BC,19 + LDIR ; zero out S1, S2, RC and alloc. map + CALL MakAlt + LD DE,010Fh ;position to col 2 + LD A,(RulFlg) + OR A + JR Z,Dir1 + INC D ;move down a line to preserve the ruler +Dir1: CALL GoTo + LD A,(View) ;initialize + SUB 14 + LD (HPos),A + LD A,(TxtLns) ;lines free on screen + DEC A + LD (DirLns),A + LD A,(View) ;columns free + LD HL,DirCls + LD (HL),A + XOR A + RRD ;cols=view/16 + LD C,(HL) + DEC C + PUSH BC + LD DE,FCBBuf ;first file? + LD C,SRCH + CALL BDOS ; search for first matching file + POP BC + CP 0FFH + JR NZ,Sk1Dir + CALL DsplC + DB 'N','o'+X,'File',CR,0 + JP Sk3Dir +; +Lp3Dir: PUSH BC + LD DE,FCBBuf ;next one... + LD C,SRCN + CALL BDOS ; search for next matching file + POP BC + CP 0FFH + JP Z,DirEnd ;all done? +Sk1Dir: ADD A,A + ADD A,A + ADD A,A + ADD A,A + ADD A,A ;desired FCB is at 32*A + DMA + LD E,A + LD D,0 + LD HL,DMA + ADD HL,DE + INC HL ;point to filename + EX DE,HL + LD HL,9 + ADD HL,DE ;test SYS attribute + BIT 7,(HL) + JR Z,Sk2Dir + LD A,(DirSys) ;yes, include? + OR A + JR Z,Lp3Dir ;no +Sk2Dir: EX DE,HL + PUSH HL + LD B,11 +Lp4Dir: RES 7,(HL) ;strip flags + INC HL + DJNZ Lp4Dir + LD DE,4 + ADD HL,DE + LD (HL),0 ;terminator + DEC HL + LD A,' ' ;separator + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD (HL),A + DEC HL + LD D,H + LD E,L + DEC HL + LD A,C ;save DirCls + LD BC,3 ;move TYP + LDDR + EX DE,HL + LD (HL),'.' ;punctuate + POP HL + LD C,A ;save DirCls + PUSH BC + CALL DspLp ;SHOW IT + POP BC + DEC C + JR NZ,Lp3Dir ;finish line? + LD HL,DirLns + DEC (HL) + JR Z,DirFul ;out of room? + LD A,CR + CALL DsByt ;okay, new line + LD A,(DirCls) + LD C,A + JR Lp3Dir +; +DirFul: CALL DsplC ;ran out of lines + DB '...',CR,0 + JR Sk3Dir +DirEnd: LD A,C ;done, need CR? + LD HL,DirCls + CP (HL) + JR Z,Sk3Dir + LD A,CR + CALL DsByt +Sk3Dir: CALL UnAlt + CALL IfSpLn + LD A,(FCBU) + LD E,A + LD C,USRN ;reset user + CALL BDOSep + CALL SetAl + JP ESCLp ;wait for ESC to clear +; +;Load a new file. +; +Load: LD A,(Modify) + OR A + JR Z,LoadY + LD HL,QuitQ ;warn if old file was changed + CALL Prompt + CALL Confrm + JP NZ,ShoLn1 +LoadY: JP Restrt ;go do it +; +;Erase a disk file. +; +Era: CALL SavNam ;save old FCB + LD HL,EraQ + CALL NewNam + LD A,(EdErr) + OR A + JR NZ,EraDon + LD (FCBs1),A ;zero S1 + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD C,FDEL + CALL BDOSfc + INC A + CALL Z,Error7 +EraDon: CALL GetNam ;restore FCB + JP ShoLn1 +; +; +;Read text from disk file to cursor location. +; +Read: CALL SavNam ;save old FCB + LD HL,ReadQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,RdDone +; +LoadIt: CALL IOon ;say wait + CALL Cmprs ;need all our room + CALL GpCnt + JR C,Sk1Rd ;No room? + LD HL,(BefCu) ;Start here + CALL MSIn ;Read it in + JR NZ,Sk2Rd ;Worked? +Sk1Rd: CALL Error1 ;no, out of room + JR RdDone +Sk2Rd: JR NC,Sk3Rd ;Okay? + CALL Error3 ;no, I/O error + JR RdDone +Sk3Rd: LD DE,(BefCu) ;Get old BefCu + LD (BefCu),HL ;Set new one + EX DE,HL + INC HL ;Point at first byte loaded + CALL MoveL ;Move the cursor +RdDone: CALL GetNam ;restore FCB + CALL IOoff + CALL ELret2 + JP SetAl +; +; +;Write the whole file out to disk. +; +Save: LD A,(FCB+1) ;must have filename + CP ' ' + JR NZ,Save00 + CALL ChgNam + LD A,(EdErr) + OR A + RET NZ +Save00: LD A,(Modify) + OR A + JR NZ,Save01 + LD HL,UnchgQ ;hey, no changes! + CALL Prompt + CALL Confrm + PUSH AF + CALL ShoLn1 + POP AF + RET NZ +Save01: CALL IOon ;say wait + LD HL,(AftCu) + LD (LastCu),HL ;save position + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL NdCnt ;count number of bytes + JR NC,Save02 + LD BC,0 +Save02: LD HL,(AftCu) ;point at first byte + CALL MSOut ;write it out + JR NC,Save03 + CALL Error3 ;I/O error + JR Save04 +Save03: XOR A + LD (Modify),A ;clean slate +Save04: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + JP IOoff +; +; +;Write block text to a disk file. +; +Write: CALL SavNam ;save orig FCB + LD HL,WritQ + CALL NewNam + LD A,(EdErr) ;check entry error + OR A + JR NZ,WrXit + CALL IOon ;say wait + LD HL,(AftCu) ;save position + LD (LastCu),HL + LD HL,(BegTx) + CALL MoveL ;go to top of file + CALL IsBlk + BIT 1,A ;must be marked + JR Z,WrOops + INC DE ;point to it + SBC HL,DE ;size of block + EX DE,HL + LD B,D + LD C,E + CALL MSOut + JR NC,WrDone +WrOops: CALL Error7 +WrDone: LD HL,(LastCu) + DEC HL + CALL MoveR ;go back + CALL IOoff +WrXit: CALL GetNam ;restore orig FCB + JP ShoLn1 +; +; +SavNam: LD HL,FCB ;Preserve main filename + LD DE,FCBBuf + LD BC,12 + LDIR ; copy drive, file name and type + XOR A + LD (FCBd0),A + LD A,(FCBU) ;and user, W/A, FilFlg + LD (DE),A ; set user number in FCBBuf+13 + INC DE + LD A,(FMode) + LD (DE),A ; set S1 + INC DE + LD A,(FilFlg) + LD (DE),A ; set S2 + RET +GetNam: LD HL,FCBBuf ;And restore them + LD DE,FCB + LD BC,12 + LDIR + XOR A + LD (FCBd0),A + LD A,(HL) + LD (FCBU),A + LD E,A + INC HL + LD A,(HL) + LD (FMode),A + INC HL + LD A,(HL) + LD (FilFlg),A + LD C,USRN + JP BDOSep +; +; +;Accept a new file name to be used for disk i/o. +; +ChgNam: CALL SavNam + LD HL,NameQ + CALL NewNam + LD A,(EdErr) + OR A + CALL NZ,GetNam ;bad? restore + CALL DfltM ;may have changed modes + CALL DoHdr + CALL ELret2 + JP ShoLn1 +; +NewNam: CALL Prompt ;subroutine entry + LD A,24+1 + CALL GSEnt ;Ask for input + DW FNamBf + JP Z,Error7 ;Error if no input + LD B,A + PUSH BC + LD HL,DMA ;uppercase it +NNUlp: LD A,(HL) + CALL UCase + LD (HL),A + INC HL + DJNZ NNUlp + POP BC ;restore length + LD HL,DMA + LD A,(HL) + CP '/' ;watch for mode only + JR NZ,NNMod + INC HL + CP (HL) ;second '/' + DEC HL + JR NZ,NNMod2 +NNMod: LD A,B + CALL Parse ;parse DU:FN.T /O + JP C,Error7 ;check bad entry + XOR A + LD (FilFlg),A ;kill fileflg + RET +NNMod2: INC HL + LD A,(HL) ;do mode only + CP 'W' ;WordStar + JR Z,NNMdOK + CP 'A' ;ASCII + JR Z,NNMdOK + CP 'N' ;non document + JP NZ,Error7 +NNMdOK: LD (FMode),A + RET +; +DfltM: LD HL,0101H + LD (LMSav),HL ;margins set + LD A,(FMode) ;doc or nondoc mode? + SUB 'N' + JR Z,Dflt2 + XOR A + LD (AIFlg),A + DEC A + LD (VTFlg),A + LD A,(HCDflt) + LD (HCRFlg),A ;HCR display? + LD A,(RtMarg) ;If RM set, avoid wierd WW/AI conflict + DEC A + JR NZ,DfltX + LD HL,(DfltLM) ;from NONdoc: reset margins + LD (LfMarg),HL +DfltX: LD A,';' ;punctation chars: , ; : - . ? ! + JR DfltX2 +Dflt2: LD (LfMarg),HL ;NONdocument mode + LD (VTFlg),A ;varitabs off + LD (HCRFlg),A ;HCR display off + DEC A + LD (AIFlg),A ;auto indent ON + LD A,':' ;punctation chars: , : - . ? ! (NOT ;) +DfltX2: LD (PunTbl+1),A + JP RulFix +; +; +;Toggle case of character at cursor +; +UpLow: CALL Fetch ;also points to byte with (HL) + AND 5FH ;strip off both hidden space and case + CP 'A' + JR C,UpLo1 ;leave alone if not letter + CP 'Z'+1 + JR NC,UpLo1 + BIT 5,(HL) ;toggle case + RES 5,(HL) + JR NZ,UpLo0 ;was lower, now up + SET 5,(HL) ;was upper, now low +UpLo0: CALL ELret2 +UpLo1: CALL Right ;move right for next(?) + JP SetRCu +; +; +;Set page length +; +PgSet: LD HL,PgLnQ + CALL Prompt + LD A,(FormL) ;default value + CALL GetNum + JP C,Error7 + LD (PgLen),A + CALL DoHdr + JP ShoLn1 +; +; +;VARIOUS TOGGLES +; +;Simple on/off toggles +; +HCRTog: CALL SetAl ;HCR display + LD HL,HCRFlg +ToggHL: LD A,(HL) + CPL + LD (HL),A + RET +; +;These require header display +; +HypTog: LD HL,HypFlg ;hyphenation + CALL ToggHL +HYshow: LD HL,HYon + LD A,(FMode) + CP 'N' ;irrelevant in N mode + JR Z,HYsho0 + LD A,(HypFlg) + OR A + JR NZ,HYsho1 +HYsho0: LD HL,TogOff +HYsho1: LD DE,DspHyp + JP TogSho +; +IToggl: LD HL,InsFlg ;INSERT + CALL ToggHL +ITshow: LD A,(InsFlg) + LD HL,MacFlg + BIT 7,(HL) + JR Z,ITsho0 + LD A,(SavIns) +ITsho0: OR A + LD HL,INSon + JR NZ,ITsho1 + LD HL,TogOff +ITsho1: LD DE,DspIns + JP TogSho +; +DblTog: LD HL,DSFlg ;double spacing + CALL ToggHL + OR A + CALL NZ,AIoff ;turn off auto ident if double spacing +DblSho: LD A,(DSFlg) + OR A + LD HL,DSon + JR NZ,DSsho1 + LD HL,TogOff +DSsho1: LD DE,DspSpc + JP TogSho +; +AIoff: LD HL,AIFlg + INC (HL) + DEC (HL) + RET Z ;fall thru to turn off auto indent if it's on +; +AITog: LD HL,AIFlg ;auto indentation + CALL ToggHL + OR A + JR Z,AIshow + LD HL,DSFlg ;is double spacing on? + INC (HL) + DEC (HL) + CALL NZ,ToggHL ;turn it off if so + CALL NZ,DblSho ;turn off the old DS display + LD A,1 + CALL SLM1 ;reset left margin to 1 +AIshow: LD A,(AIFlg) + OR A + LD HL,AIon + JR NZ,AIsho1 + LD HL,TogOff +AIsho1: LD DE,DspInd + JP TogSho +; +PSTog: LD A,(PSokFl) + OR A + JP Z,Error2 ;invalid key + LD HL,PSFlg + CALL ToggHL + LD A,(RMSav) + DEC A + RET NZ ;margins released? then we're done +PSDisp: LD A,(FMode) + CP 'N' + JR Z,PSTogU ;no PS in nondocument mode + LD A,(PSFlg) + OR A + LD HL,PSon ;proportional spacing on + JR NZ,PSTogX +PSTogU: LD HL,TogOff ;turn off margin release +PSTogX: LD DE,DspMrg + JP TogSho +; +; +;TEXT FORMAT functions +; +SetRM: CALL StMrCm ;Same for left and right + LD C,A + LD A,(LfMarg) + CP C + JR C,SRM1 ;inside LM? + LD A,1 + LD (LfMarg),A ;if so, reset LM +SRM1: LD A,C + LD (RtMarg),A + JR StMgEn +; +SetLM: CALL StMrCm ;Same for left and right + LD HL,RtMarg + CP (HL) + JR NC,MrgErr +SLM1: LD (LfMarg),A + DEC A + CALL NZ,AIoff +StMgEn: CALL RulFix + JP ShoLn1 +; +StMrCm: LD A,(FMode) ;Set right margin + CP 'N' ;(must be Document mode) + JR Z,MrgErr + LD A,(RMSav) ;okay, do it + DEC A + CALL NZ,RelM ;(undo Margin Release) + LD HL,ColQ + CALL Prompt + LD A,(CurCol) ;default: cursor column + CALL GetNum + JR Z,MrgErr + RET NC +MrgErr: POP HL + JP Error7 +; +RelM: CALL RelLM ;release both margins (Toggle) + LD HL,RtMarg + LD DE,RMSav + CALL RelSb + CALL MRshow + JP RulFix +; +RelLM: LD HL,LfMarg ;SBR: release left only + LD DE,LMSav +RelSb: LD A,(HL) ;common subroutine + CP 1 + JR Z,Rel1 + LD (DE),A ;note: if RMSav>1, margins released + LD (HL),1 + RET +Rel1: LD A,(DE) + LD (HL),A + LD A,1 + LD (DE),A + RET +; +;Check the right margin +; +ChkRM: LD A,(CurCol) ;be sure this is up to date + LD B,A + LD A,(RtMarg) + INC A + LD C,A + SUB B ;set C if over + RET NC + CALL IgnCtl ;yes, ignore ctlchars + LD A,C ;try arithmetic once again + ADD A,E + SUB B + RET ;now C set if really over +; +IgnCtl: CALL Fetch ;count ctlchars to be ignored + LD E,0 ;(up to present cursor) + LD HL,(BefCu) + JR NZ,IgnC1 +IgnCLp: LD A,(HL) ;count em + DEC HL + CP CR ;quit at BOL + RET Z +IgnC1: CP TAB ;tabs don't count + JR Z,IgnCLp + CP 20H + JR NC,IgnCLp + INC E ;others do + JR IgnCLp +; +;Check left margin, space over if needed +; +ChkLM: LD A,(LfMarg) + LD B,A + LD A,(CurCol) + SUB B ;be sure this is uptodate + RET ;ret Z if at, C if over +; +UpToLM: LD A,(LfMarg) ;git on over to the LM column +; +MvCol: PUSH AF ;move to col A saving any existing text + CALL GoCol + POP AF +MvColI: LD HL,CurCol ;move to col A inserting spaces + SUB (HL) + RET C ;we're past already + RET Z ;we're there + LD B,A + CALL SetCu ;this is going to hurt +MvClp: PUSH BC ;insert B spaces + CALL InsSpc + POP BC + RET C ;quit if out of space + CALL IncH + DJNZ MvClp + RET +; +DoLM: LD A,(LfMarg) ;create whole left margin + DEC A + RET Z + LD B,A + JR MvClp +; +;Handle former margin for reformat +; +CntSpc: CALL QuikLf ;count lead spaces/tabs on line + CALL Fetch + LD B,A + EXX + XOR A +CSpLp: LD (NumTab),A + PUSH AF + CALL Fetch + CP ' ' + JR Z,CSpL1 + CP TAB + JR NZ,CSpLpF +CSpL1: EXX + CP B + EXX + JR NZ,CSpLpF + CALL Right ;move 1 char right + POP AF + INC A ;incr # tabs + JR CSpLp +CSpLpF: CALL QuikLf ;back to start + EXX +CntSpX: POP AF + RET +; +EatSpc: OR A ;eat up to A lead spaces on line + RET Z +ESpLp: PUSH AF + CALL Fetch + CP TAB + JR Z,ESpLpF + CP ' ' + JR NZ,CntSpX +ESpLpF: CALL EChar + POP AF + DEC A + JR NZ,ESpLp + RET +; +; +;Update CurCol and return it in A and B +;(NOTE: slow. When possible, LDA CurCol.) +; +ColCnt: CALL WhatC + LD (CurCol),A + RET +; +WhatC: CALL FetchB ;col 1 is spcl case + CP CR + LD A,1 + LD B,A + RET Z + LD E,1 + CALL CrLft ;start of line + LD BC,0 +; +CCLp: CALL GetNx ;get a char + CP TAB + JR NZ,CC1 + LD A,B ;tabs are special + PUSH HL + LD HL,TabCnt + OR (HL) ;round up + POP HL + LD B,A +CC1: INC B ;count char + LD A,B + CP 254 + JR Z,CC2 ;too long? return column 255 forever + XOR A + CP C + JR NZ,CCLp ;get hidden space? + PUSH BC + CALL LCnt ;compare HL to BefCu + POP BC + JR NC,CCLp ;get another, if more exist +CC2: INC B + LD A,B ;that is curcol. + RET +; +; +;Do wordwrap if needed +; +WdWrap: LD A,(RtMarg) ;WW off if RM=1 + DEC A + RET Z + LD IY,CurCol + INC (IY) ;count the char you just put in + CALL ChkRM + RET NC + LD B,0 ;past margin... +WWLp: INC B ;count moves + PUSH BC + CALL Left + DEC (IY) + POP BC + CALL FetchB + CP CR ;oh no Uncle Bill + JP Z,Error9 + CP '-' ;hyphenation + JR NZ,WW1 + LD A,(HypFlg) + OR A + JR Z,WW1 + CALL Fetch + CP ' ' + JR Z,WW1a + INC B + PUSH BC + CALL InsSpc ;tuck in a space if there isn't one + JR WW2 +WW1: CALL Fetch + CP ' ' + JR NZ,WWLp +WW1a: PUSH BC + CALL Right ;leave it if there is + INC (IY) +WW2: CALL ChkLM + JR Z,WWerr + JR C,WWerr + CALL ICRB ;break line + CALL QuikLf + CALL DoLM + POP BC + LD A,(NumTab) + ADD A,B + JP C,WWerr + DEC A ;one spc gone +GoRtA: OR A ;Go right A chars - used by wordwrap etc + RET Z + PUSH AF + CALL Right + POP AF + DEC A + JR GoRtA +; +WWerr: POP BC + JP Error9 +; +;Reform a paragraph +; +Reform: LD A,(RtMarg) ;is RM set? + DEC A + RET Z + CALL QuikLf + CALL NdCnt + JP C,RfmE10 + CALL Fetch ;empty line? + JP Z,Down + CALL XQuiet + LD A,(AIFlg) + OR A + JR NZ,RfmBg + CALL RfmNL ;figure out indentation + JR C,RfmBg + CALL CntSpc + PUSH AF + CALL RfmPL + POP AF + CALL EatSpc ;remove spaces acc. to NEXT line indent + CALL DoLM ;and add current margin +RfmBg: CALL QuikLf + CALL KyPeek ;peek for a keypress + CP ESC ;check for abort + JR NZ,RfmBg1 ;no... keep going + CALL Keybd ;eat the ESC + JP RfmEnd ;and quit +RfmBg1: CALL ColCnt ;only once per line (slow) + LD IY,CurCol + LD A,63 + LD (PScnt),A +; +RfmLp: CALL NdCnt + JP C,RfmE10 ;check for EOF + CALL Fetch + JP Z,Rfm7 ;and EOL + CP TAB ;tabs are special + JR NZ,RfmTab + LD A,(IY) + DEC A + LD HL,TabCnt + OR (HL) ;round up + INC A + LD (IY),A + JR Rfm3 +RfmTab: LD HL,PSFlg + DEC (HL) + INC (HL) + JR Z,Rfm3 + LD HL,PSTbl-32 + ADD A,L + LD L,A + LD A,0 + ADC A,H + LD H,A + LD A,(PScnt) + ADD A,(HL) + CP 63+30 + JR NC,RfmTb1 + CP 63-30+1 + JR NC,Rfm3 + ADD A,30 + JR Rfm3a +RfmTb1: ADD A,-30 + INC (IY) +Rfm3: INC (IY) ;Keep CurCol updated +Rfm3a: LD (PScnt),A + CALL Right + CALL ChkRM + JR NC,RfmLp +; +Rfm4: CALL FetchB ;just the right length? + CP ' ' + JR NZ,Rfm4a + CALL Fetch + JR Z,Rfm7 +Rfm4a: CALL Left ;oops, too long. + CALL FetchB + CP CR + JP Z,RfmErr + CALL Fetch + CP '-' + JR NZ,Rfm4b + LD A,(HypFlg) + OR A + JR Z,Rfm4b + CALL Right + CALL ColCnt ;## + CALL ChkRM ;## + JR NC,Rfm4a2 ;## + CALL Left ;## + JR Rfm4 ;## +; +Rfm4a2: CALL InsSpc + JR Rfm4c +Rfm4b: CALL IsBlnk ;break after blank + JR NZ,Rfm4 + CALL Right +Rfm4c: CALL ColCnt + CALL ChkLM ;watch out for left mgn + JP Z,RfmErr + JP C,RfmErr + CALL ICRB +Rfm5: CALL Fetch ;avoid spurious para + JR Z,Rfm6a ;(stop after CR) + CP ' ' + JR NZ,Rfm6b + CALL EChar + JR Rfm5 +Rfm6a: CALL EChar + JR RfmBg2 +Rfm6b: CALL DoLM + JR RfmBg2 +; +Rfm7: CALL FetchB ;is the CR soft or hard? + CP ' ' + JR NZ,Rfm9 ;hard, quit + CALL Left ;soft, delete any other spaces +Rfm7a: CALL FetchB + CP ' ' + JR NZ,Rfm7b + CALL Delete + JR Rfm7a +Rfm7b: CP '-' ;unhyphenate? + JR Z,Rfm20 +Rfm8: CALL Right ;and now the CR itself + CALL EChar + CALL RfmSD ;and any soft CR following + LD A,255 + CALL EatSpc ;and any leading spaces + CALL Fetch + JR NZ,Rfm8a ;hit bald CR? + CALL Delete ;yep, kill space and quit + JR Rfm9 +Rfm8a: CALL Left + CALL Left + CALL IsEndS ;(extra spc for punc) + JR NZ,RfmBg2 + CALL Right + CALL InsSpc +RfmBg2: JP RfmBg +Rfm9: CALL Right ;hard CR (check following soft?) + CALL RfmSD ;delete, if there + CALL ICRB0 ;may need to separate paras +RfmEnd: CALL XLoud + JP SetAl +RfmErr: CALL XLoud + JP Error9 +RfmE10: CALL XLoud + JP Eror10 +; +Rfm20: LD A,(HypFlg) ;unhyphenation + OR A + JR Z,Rfm8 ;not allowed, continue +Rfm21: CALL Loud + CALL ShoAll + CALL YesNo1 + PUSH AF + CALL XQuiet + POP AF + JR NC,Rfm22 + JR Z,Rfm21 ;C,Z means "*": unacceptable + JR Rfm8 ;C,NZ means ESC: don't join at all +Rfm22: CALL Z,Delete ;kill hyphen if it was "Yes" + CALL Join ;join lines (whether "Yes or No") + JR RfmBg2 +; +RfmNL: CALL QuikRt ;go to next line of text + CALL NdCnt + JR NC,RfmNL0 + CALL QuikLf ;oops, none + SCF + RET +RfmNL0: CALL Right + CALL Fetch ;(may be blank) + JR NZ,RfmNL1 ;bald CR next? also give up + CALL Up + SCF + RET +RfmNL1: CP ' ' + JR Z,RfmNL2 + CALL QuikLf ;no, fine, we're here + OR A + RET +RfmNL2: CALL Right + CALL Fetch + JR NZ,RfmNL1 ;just spaces and CR? doublespacing, + CALL Right ; go on to next line + JR RfmNL1 +RfmPL: CALL QuikLf ;return to previous line of text +RfmPL0: CALL Left + CALL FetchB ;(may be blank) + CP CR + JP Z,RfmPLx ;yes, take next + CP ' ' + JR Z,RfmPL0 + JP QuikLf ;no, fine +RfmPLx: CALL Left + JP QuikLf +; +RfmSD: CALL Fetch ;delete a soft CR if present + CP ' ' + RET NZ + CALL Right + CALL Fetch + PUSH AF + CALL Left + POP AF + RET NZ + CALL EChar + JP EChar +; +; +;Center or flush a line +; +Center: LD E,1FH ;(RRA) if Center + CP 'F'-40H + JR NZ,Ctr0 + LD E,0C9H ;(RET) if Flush +Ctr0: LD A,E + LD (Flush),A + LD A,(RtMarg) + CP 1 + RET Z ;not if no margin + CALL QuikLf ;start of line +CtrL1: CALL Fetch + JR Z,CtrXit ;end? done + CALL IsBlnk + JR NZ,CtrL1F + CALL EChar ;delete spaces + JP C,Error9 + JR CtrL1 +CtrL1F: CALL QuikRt ;end of line +CtrL2: CALL Left + CALL IsBlnk + JR NZ,CtrL2F + CALL EChar ;delete spaces + JR CtrL2 +CtrL2F: CALL ColCnt ;where are we? + CALL IgnCtl ;ignore ctlchars + LD HL,CurCol + LD A,(LfMarg) + DEC A + LD B,A + LD A,(RtMarg) + ADD A,E ;(ctlchars) + SUB B + SUB (HL) + JP C,Error9 ;error + CALL Flush + JR Z,CtrXit + PUSH AF + CALL QuikLf ;start again + CALL DoLM + POP BC +CtrL3: PUSH BC ;insert spaces to center + CALL InsSpc + POP BC + DJNZ CtrL3 +CtrXit: CALL QuikLf + CALL ShoCu + CALL QuikRt ;to next line(?) + JP Right +; +Flush: RRA ;<--- goes to RET if Flush + AND 7FH ;take half the difference for Center + RET +; +; +;Fetch character at (or before) cursor +; +Fetch: LD HL,(AftCu) + LD A,(HL) + AND 7FH ;ignore any hidden space + CP CR + RET +FetchB: LD HL,(BefCu) + LD A,(HL) + BIT 7,A + RET Z ;ordinary byte + LD A,' ' + RET ;hidden space +; +;Tests on char at cursor (use only A,HL) +; +IsBlnk: LD HL,BlkTbl ;point to tbl + JR IsTest +IsPara: LD HL,ParTbl + JR IsTest +IsParB: LD HL,ParTbl + JR IsTstB +IsPunc: LD HL,PunTbl + JR IsTest +IsPunB: LD HL,PunTbl + JR IsTstB +IsEndS: LD HL,EndTbl +; +IsTest: PUSH HL + CALL Fetch + POP HL + JR IsTLp +IsTstB: PUSH HL + CALL FetchB + POP HL +IsTLp: BIT 7,(HL) + JR NZ,IsTst1 ;at end of tbl? + CP (HL) + RET Z ;Z set if match + INC HL + JR IsTLp +IsTst1: OR A ;clear Z if none + RET ;ret char in A +; +PunTbl: DB ',;:-' ;fall thru... +EndTbl: DB '.?!',0FFh ;end with 0FFh +ParTbl: DB CR ;fall thru... +BadTbl: DB 0,EOF ;characters not "part" of file text +BadLen EQU $-BadTbl ;(<--BlkChr patches in here) +BlkTbl: DB ' ',TAB,0FFh ;end with 0FFh +; +;DISK I/O +; +IOon: LD DE,DspEsc ;show Wait.... + CALL GoTo + CALL MakAlt + LD HL,IOmsg + LD B,4 + CALL BHLMsg + CALL UnAlt + RET +; +BDOSfc: LD DE,FCB +; +;Enter BDOS, but latch onto warm start for +;recovery purposes. (CP/M 2 ONLY) +; +BDOS: CALL DOSVer + JP NC,BDOSep ; just do the BDOS call for CP/M 3.0 + LD A,(DE) ; grab drive # + LD (FcbDrv+1),A ; and stuff it into code + PUSH DE + LD HL,(0001H) + INC HL ;trap warm boot vector in BIOS JP table + LD E,(HL) + INC HL + LD D,(HL) + LD (BIOSws+1),DE + LD DE,BIOSws + LD (HL),D + DEC HL + LD (HL),E + POP DE + CALL BDOSep ;DO IT + PUSH HL + LD DE,(BIOSws+1) ;Restore real warm boot + LD HL,(0001H) + INC HL + LD (HL),E + INC HL + LD (HL),D + POP HL + RET +BIOSws: LD DE,0 ;<--- Warm boot vector + LD HL,(0001H) + INC HL + LD (HL),E ;restore it + INC HL + LD (HL),D +FcbDrv: LD A,0 ;<----- + LD (FCB),A ;restore drive + LD SP,Stack ;restore stack + CALL RDlog ;and disks + CALL Error3 ;Give I/O message + JP Sk1Ed ;Continue editing +; check dos version - 22h=>CP/M2.2, 31h=>CP/M3, 'S'=>ZSDOS & "D"=> ZDDOS +; on return: (Carry set if 2.2, reset if CP/M3, ZxDOS) +DOSVer: LD A,0 ;<---- Version @ DOSVer+1 + CP 30H + RET +; +RstDrv: OR A ;CP/M 2 drive reset (A=1 etc) + JR Z,RDlog + LD HL,FixDsk + RES 6,(HL) ;(have to adjust from ASCII) + CP (HL) ;one of 2 fixed drives? ignore + RET Z + INC HL + RES 6,(HL) + CP (HL) + RET Z + PUSH AF + LD C,GDRV + CALL BDOSep + POP BC + INC A + CP B ;is it logged drive? + JR Z,RDlog + LD HL,1 ;if NOT, can be selective +RDlp: DEC B + JR Z,RDok + ADD HL,HL + JR RDlp +RDok: EX DE,HL + LD C,RSTV ;reset single drive + JR RDxit +RDlog: LD C,RSTD ;sigh, whole system +RDxit: JP BDOSep +; +; +Parse: PUSH AF ;parse FCB w/Duu: and [A/W (NO WILDCARDS) + LD A,(DFMode) + LD (FMode),A + PUSH HL ;Entry: HL=string, A=length + CALL BlkFCB ;Exit: set FCB, FCBU, FMode + POP HL ;...now checks filetypes too + LD D,H + LD E,L + POP AF + OR A + JP Z,PNODRV + LD C,A + LD B,0 ;chars there + LD A,':' + CPIR ;find drivespec? + JR NZ,PNODRV + DEC HL ;yep...NDR? + LD (HL),0 + CALL NdrChk + LD (HL),':' + JR Z,Parse1 ;not an NDR name + INC HL + LD A,B + LD (FCB),A ;store drive + LD A,C + LD (FCBU),A ;store user number + LD E,A + LD C,USRN + PUSH HL + CALL BDOSep ;set user number + POP HL + JR PNAME +Parse1: DEC HL ;yep...User number? + LD A,(HL) + CP '0' + JR C,PDRV + CP '9'+1 + JR NC,PDRV +; +PUSR: SUB '0' + LD E,A ;Got user... figure units + DEC HL + LD A,(HL) + CP '0' + JR C,ZPAR1 ;thats all? + CP '9'+1 + JR NC,ZPAR1 + SUB '0' + LD D,A ;nope, tens too + ADD A,A + ADD A,A + ADD A,A ;*8 + ADD A,D + ADD A,D + ADD A,E ;*(8+2)+units = user + LD E,A + DEC HL + CP 32 + JR NC,ZPBAD ;illegal? +ZPAR1: LD A,E + LD (FCBU),A ;set user + LD C,USRN + PUSH HL + CALL BDOSep + POP HL +; +PDRV: BIT 7,L ;now, parse FCB (start with drive) + JR Z,ZPAR2B ;(Kludge: stay above 0080h) + LD A,(HL) + CP ' ' ;oops, was it there? + JR Z,ZPAR2B +ZPAR2: SUB 'A' + JR C,ZPBAD ;make sure it's legal + LD E,A + LD A,15 + CP E + JR C,ZPBAD + DEC HL + BIT 7,L + JR Z,ZPAR2A ;kludge again (stay about 0080H) + LD A,(HL) + CP ' ' + JR NZ,ZPBAD +ZPAR2A: INC HL + LD A,E + INC A + LD (FCB),A +ZPAR2B: LD BC,4 + LD A,':' + CPIR ;skip over user, to filename + JR PNAME +PNODRV: LD A,' ' ;no du: at all + EX DE,HL + DEC HL ;find filename +PNDL: INC HL + CP (HL) + JR Z,PNDL ;(first nonblank) +; +PNAME: LD B,8 + LD DE,FCB+1 ;do filename at (HL) + EXX + LD DE,FNamBf + LD H,D + LD L,E + LD B,13 + XOR A + CALL Fill + EXX +ZPRL1: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP '.' + JR Z,ZPRL1X + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZRLP1A + CP (HL) + JR NZ,POPT + INC HL +ZRLP1A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL1 + JR ZPRL1F +ZPRL1X: LD A,' ' ;fill with " " + CALL Fill + JR PTYP +ZPBAD: CALL BlkFCB ;bad entry + SCF + RET +ZPRL1F: XOR A + ADD A,(HL) + JR Z,ZPARX + CP '.' + JR NZ,ZPRL2F ;no "."? leave type blank + INC HL +; +PTYP: LD B,3 ;fill type at (HL) + EXX + LD A,'.' + LD (HL),A + INC HL + EXX +ZPRL2: XOR A + ADD A,(HL) + INC HL + JR Z,ZPARX + CP ' ' + JR Z,ZPRL2F + RET C + CP '/' + JR NZ,ZPRL2A + CP (HL) + JR NZ,POPT + INC HL +ZPRL2A: CALL ZPBADC + JR Z,ZPBAD + LD (DE),A + INC DE + EXX + LD (HL),A + INC HL + EXX + DJNZ ZPRL2 +ZPRL2F: LD A,(HL) ;(eat spaces) + CP ' ' + JR NZ,POPT + INC HL + JR ZPRL2F +; +POPT: LD A,(HL) ;process W/A/N option + CP '/' + JR NZ,POPT1 + INC HL + LD A,(HL) ;process W/A/N option +POPT1: OR A + JR Z,ZPARX + CALL VerOpt ;verify legality + JR NZ,ZPBAD + LD (FMode),A + JR ZPARX2 ;any specification overrides defaults +; +ZPARX: LD HL,FCBt1 ;check filetype mode defaults + LD DE,FDflt1 + CALL TypDfl + LD DE,FDflt2 + CALL TypDfl + LD DE,FDflt3 + CALL TypDfl + LD DE,FDflt4 + CALL TypDfl +ZPARX2: LD A,(FCB+1) + CP ' ' + JR Z,ZPBAD + OR A ;DONE. + RET +; +ZPBADC: PUSH HL ;check bad chars + PUSH BC + LD HL,ZPBLST + LD BC,ZPBLEN + CPIR ;Z set if bad + POP BC + POP HL + RET +ZPBLST: DB ' .,;:?*=' ;illegal chars +ZPBLEN EQU $-ZPBLST +; +TypDfl: PUSH HL + LD B,3 ;Set mode from filetype if (HL),(DE) MATCH +TypDLp: LD A,(DE) + CP '?' + JR Z,TypD2 + CP (HL) + JR NZ,TypDex ;no match, quit +TypD2: INC DE + INC HL + DJNZ TypDLp + LD A,(DE) ;match, here's your mode + CALL VerOpt +TypDex: POP HL + RET NZ + LD (FMode),A + RET +; +; +VerOpt: CP 'A' ;verify mode option legal + RET Z + CP 'N' + RET Z + CP 'W' + RET +; +; +;IN: DE=string to match +;OUT: Z=0,B=drive,C=user# (if NDR match found) +; Z=1 if no NDR match +; +NdrChk: PUSH HL + PUSH DE + EX DE,HL ;string addr to HL + LD A,' ' + DEC HL +NdrSpc: INC HL ;skip over spaces + CP (HL) + JR Z,NdrSpc + LD D,H ;addr of 1st non blank to DE + LD E,L + LD B,Z3NdrM+1 ;# chars to allow before + XOR A ;we MUST see a NUL +NdrEos: CP (HL) ;find terminating NUL + JR Z,NdrNul + INC HL + DJNZ NdrEos + JR NoNdr ;more than 8 chars, not an NDR +NdrNul: LD BC,Z3NDR + CALL Z3EAdr + JR Z,NoNdr ;no NDR block + EX DE,HL ;start of string to HL + LD D,B ;NDR addr to DE + LD E,C +NxtNdr: LD A,(DE) ;end of NDRs? + OR A + JR Z,NoNdr ;yep, no match + INC DE + INC DE ;DE points to NDR string + PUSH HL ;save start of string + PUSH DE ;save NDR string addr + LD B,Z3NdrM +NdrNxC: LD A,(DE) + CP ' ' ;end of NDR name string? + JR NZ,NdrChC ;not yet + INC (HL) ;did we hit the NUL + DEC (HL) ;at the end of string + JR NdrMis ;(i.e. was it a full match?) +NdrChC: CP (HL) + JR NZ,NdrMis + INC HL ;next char in string + INC DE ;next char in NDR entry + DJNZ NdrNxC +NdrMis: POP DE ;restore start of NDR string + POP HL ;restore start of string + JR Z,NdrMtc ;all chars match, got an NDR + EX DE,HL ;start of NDR string to HL + LD BC,Z3NdrL + ADD HL,BC ;next NDR entry to HL + EX DE,HL ;and now to DE + JR NxtNdr +NdrMtc: EX DE,HL ;NDR matched + DEC HL + LD C,(HL) ;fetch user number + DEC HL + LD B,(HL) ;fetch drive + OR 0FFh ;Z=0H +NoNdr: POP DE + POP HL + RET +; +;Read in a word from the Z3ENV block. +;IN: offset in BC +;OUT: addr in BC +; Z=1 if addr is invalid +; +Z3EAdr: PUSH HL + LD HL,(Z3Env) + LD A,H + OR L + JR Z,NoZEnv ;no Z3ENV: Z=1 + ADD HL,BC + LD C,(HL) + INC HL + LD B,(HL) + LD A,B + OR C ;Z=1 if no address at offset +NoZEnv: POP HL + RET +; +; +;Read in the file. (HL=prev byte, BC=max size) +;Return with HL=last byte, Z=out of room, C=input error. +; +MSIn: PUSH HL ;Initialize FCBex thru FCBrc and FCBcr + PUSH BC + XOR A + LD DE,FCBex + LD B,4+16+1 + CALL Fill + LD (MSIFlg),A + CPL + LD (SftFlg),A + LD C,FOPN + CALL BDOSfc + INC A ;Not found? + JR NZ,MSIfnd +MSIerr: POP BC ;Error... + POP BC + OR 1 ;Clear Z + SCF ;Set C + RET +MSIfnd: LD DE,DMA + LD C,SDMA + CALL BDOS +; +MSIlp1: LD C,RSEQ + CALL BDOSfc + CP 1 ;No more reocrds? + JP Z,MSIefX + JR NC,MSIerr ;Other error? + LD IX,DMA + POP DE ;target count + LD B,128 ;1 record + POP HL ;target address +MSIlp2: LD A,(FMode) + CP 'W' + JR NZ,MSIlp3 + LD A,(IX) ;Wordstar: handle soft hyphens + CP 1Fh + JR NZ,MSIl2x + LD A,'-' + LD (IX),A +MSIl2x: CP 1Eh ;remove dead soft hyphens + JR Z,MSIlf + CP ' '+080H ;remove soft spaces + JR NZ,MSIl2a + LD A,(SftFlg) + OR A ;(unless at beginning of line) + JR Z,MSIlf + JR MSIlp3 +MSIl2a: XOR A + LD (SftFlg),A + LD A,(IX) ;and keep hard/soft CRs straight + CP CR+80H + JR NZ,MSIl2b + LD A,(HL) ;SCR must have space before... + CP ' ' + JR Z,MSIlp3 + SET 7,(HL) + JR NC,MSIlp3 + RES 7,(HL) ;can't set hi bit on ctlcodes + LD A,' ' + INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z + JR MSIlp3 +MSIl2b: CP CR + JR NZ,MSIlp3 +MSIl2c: RES 7,(HL) ;...and HCR must not have space + LD A,(HL) + CP ' ' + JR NZ,MSIlp3 + DEC HL + INC DE + JR MSIl2c +MSIlp3: LD A,(IX) ;take the byte + AND 7Fh ;Mask parity + CP EOF ;EOF? + JR Z,MSIeof + CP LF ;toss line feeds + JR NZ,MSIl3a + LD (SftFlg),A ;but record them + JR MSIlf +MSIl3a: LD IY,BlkChr + CP (IY) ;toss block chars + JR Z,MSIlf + CP ' ' ;take non-spaces + JR NZ,MSIok + LD A,(HL) + CP 20H ;Last one CTL? take space + JR C,MSIsp + BIT 7,(HL) ;Already hidden space? take space + JR NZ,MSIsp + SET 7,(HL) ;Hide space + JR MSIlf +; +MSIsp: LD A,' ' +MSIok: INC HL ;Bump output + LD (HL),A ;Insert byte + DEC DE ;Room left? + LD A,D + OR E + RET Z +MSIlf: INC IX ;Bump input + DEC B ;Go through record + JP NZ,MSIlp2 + PUSH HL + PUSH DE + JP MSIlp1 ;Get next block +; +MSIefX: POP DE ;(for last rec bug fix) + POP HL +MSIeof: OR 1 ;clear Z/C + LD (MSIFlg),A ;Show load OK + RET +; +; +;Write out BC characters at HL to file FCB (C=error) +; +MSOut: PUSH BC + PUSH HL + ADD HL,BC ;ending address + PUSH HL + CALL DOSVer + LD A,(FCB) + CALL C,RstDrv ;reset drive + LD HL,FCB+1 ;strip attributes + LD B,11 +MSOlp0: RES 7,(HL) + INC HL + DJNZ MSOlp0 + LD B,4 + XOR A +MSOlp1: LD (HL),A ; zero out FCBex, FCBs1, FCBs2, FCBrc + INC HL + DJNZ MSOlp1 +; cpm3 and zsdos get date/time stamps differently. zsdos puts it in DMA buffer +; while cpm3 puts create or access at FCB+18h & update at FCB+1Ch +; zsdos returns A=1 for success, A=0FFh for fail +; cpm3 returns A=0-3 for success, A=0FFh for fail + ld a,(DOSVer+1) + cp 31h ;is it cpm + jr z,TS3 ;Br if CPM3 + LD DE,tStamp ; set the buffer for the + LD C,SDMA ; set file timestamp buffer as DMA buf + CALL BDOSep + LD C,GETS ; get the file timestamp + CALL BDOSfc + jr TSRD +TS3: ld c,GETS + call BDOSfc + ld hl,FCB+18h + ld de,tStamp + ld bc,8 + ldir ;copy timestamp to buffer +TSRD: LD (tsFlg),A ; A=0FFh if no stamp + LD A,(FilFlg) ; make a backup file? + OR A + JR Z,MSOdel ; no backup needed + LD HL,FCB ; copy original filename and extension + LD DE,DMA + LD BC,16 ;FCB length + LDIR ;copy it + LD BC,8+1 ;copy original filename only + LD HL,FCB + LDIR ;again + LD BC,3 ;extension of BAK + LD HL,Bak + LDIR + LD DE,DMA+16 ;delete BAKfil + LD C,FDEL + CALL BDOS + INC A + JR NZ,MSOren + OR H ;no BAK deleted, h/w error? + JP NZ,MSOer2 ;yep... +MSOren: LD DE,DMA ;rename old file to BAK + LD C,FREN + CALL BDOS + JR MSOmak +; +MSOdel: CALL DOSVer + JR C,MSOdl2 ; skip if plain CP/M + CP 'S' + JR Z,MSOdl2 ; skip if ZSDOS + CP 'D' + JR Z,MSOdl2 ; skip if ZDDOS + LD C,ERRM ; ... we get here, we're CP/M 3.0 + LD E,0FFH ; return error, no print + CALL BDOS + XOR A + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK ;make a new file + CALL BDOSfc + PUSH AF + PUSH HL + LD C,ERRM ; return error, print + LD E,0FEH + CALL BDOS + POP HL + POP AF + PUSH AF + OR A + JR Z,MSOnSt + POP AF + LD A,H + CP 8 + JR NZ,MSOmak + LD C,FTRU ; truncate file to 0 bytes (cpm3 only!) + XOR A + LD (FCBr0),A + LD (FCBr1),A + LD (FCBr2),A + CALL BDOSfc + OR A + JP NZ,MSOer2 + LD C,FOPN + CALL BDOSfc ; open the file + PUSH AF + JR MSOnSt ; --- end of CP/M3 specific open code +; +MSOdl2: LD C,FDEL ; +++ CP/M2.2, ZxDOS specific + CALL BDOSfc ; delete any old BAK file + INC A + JR NZ,MSOmak ; jump if all good + OR H ; hardware error code? + JP NZ,MSOer2 ; ...yep +; +MSOmak: XOR A ;Initialize FCB + LD (SftFlg),A + LD (FCBex),A + LD (FCBcr),A + LD C,FMAK + CALL BDOSfc + PUSH AF +; CP/M3 doesn't have a BDOS function to set a file's timestamp +; like ZSDOS does. So we need to use a special routine that writes +; the stamp directly into the disk's directory. + LD A,(tsFlg) ;+++ timestamp code start + inc A ;do we have a timestamp? + JR Z,MSOnSt ;no, don't update the timestamp + ld a,(DOSVer+1) ;check version + cp 31h ;is it cpm + jr nz,TSZ ;Br if ZSDOS + ld hl,tStamp ;time stamp + ld de,FCB + ld bc,dirdma ;1k dma buffer + call setds3 ;set the stamp + jr MSOnSt +TSZ: LD C,SETS ;set create timestamp of new file + CALL BDOSfc ;to the same as existing file +MSOnSt: LD C,SDMA + LD DE,DMA + CALL BDOSep + POP AF ;restore result of FMAK + POP DE ;end + POP HL ;start + POP BC ;(bytes) + INC A + JP Z,MSOerr ;make file failed + LD A,B + OR C ;any bytes? + JP Z,MSOcls + LD C,0 ;Initialize GetNx + LD B,128 ;1 record + LD IX,DMA +MSOlp2: CALL GetNx + EXX + LD HL,BadTbl ;skip illegal chars + LD BC,BadLen + CPIR + EXX + JR Z,MSOsk1 ;0 or EOF +MSOlp3: LD (IX),A ;put it out + LD A,(FMode) + CP 'W' ;Wordstar mode? + JR NZ,MSOWSx + LD A,(IX) + CP ' ' + JR NZ,MSOWSa + LD A,(IX-1) ;add microjustification bits + CP 21h + JR C,MSOWS2 + SET 7,(IX-1) + JR MSOWS2 +MSOWSa: CP CR + JR Z,MSOWS1 + CP LF + JR Z,MSOWSx +MSOWS0: XOR A + LD (SftFlg),A + JR MSOWSx +MSOWS1: LD A,(IX-1) ;soften CRs after spaces + AND 7FH + CP ' ' + JR NZ,MSOWS0 +MSOW1a: SET 7,(IX) + LD A,0FFH + LD (SftFlg),A + JR MSOWSx +MSOWS2: LD A,(SftFlg) ;and spaces after soft CRs + OR A + JR NZ,MSOW1a +MSOWSx: LD A,(IX) + INC IX ;bump pointer + DJNZ MSOsk1 ;Skip if buffer not full + PUSH BC + PUSH DE + PUSH HL + LD C,WSEQ + CALL BDOSfc + POP HL + POP DE + POP BC + OR A + JR Z,MSOook + CALL MSOcls ;output error + JR MSOerr +MSOook: LD B,128 + LD IX,DMA + LD A,(DMA+127) + LD (IX-1),A +MSOsk1: AND 7FH + CP CR ;Add LF after CR + LD A,LF + JR Z,MSOlp3 + LD A,H + XOR D ;At end yet? + JP NZ,MSOlp2 + LD A,L + XOR E + JP NZ,MSOlp2 + OR C ;Still got hidden space? + JP NZ,MSOlp2 + OR B ;need EOF? + JR Z,MSOsk2 +MSOefL: LD (IX),EOF ;yes + INC IX + DJNZ MSOefL +MSOsk2: LD C,WSEQ + CALL BDOSfc + OR A + JR Z,MSOcls + CALL MSOcls + JR MSOerr +MSOcls: LD C,FCLO ;all done, close up + CALL BDOSfc + INC A + OR A ;bug fix 2.67 + RET NZ +MSOerr: SCF + RET +MSOer2: POP HL ;discard start, + POP HL ;end, + POP HL ;(bytes) + LD C,SDMA + LD DE,DMA + CALL BDOSep ;reset DMA buffer + JR MSOerr +; +; +; +; +; DISPLAY FUNCTIONS +; +;(Re)initialize screen to begin editing +; +DoHdr: LD A,(NoHdrF) + OR A + RET NZ + LD DE,0 + CALL GoTo + LD HL,Header + CALL AltDsp + CALL ShoFnm ;Show file name + LD HL,OPoff + LD A,(FMode) + CP 'N' + JR NZ,DoHdr1 ;show "Pg " if document + LD A,(PgLen) + OR A + JR NZ,DoHdrT + LD HL,OPon ;show "OP" if ^OP in nondoc +DoHdr1: LD DE,DspOP + CALL TogSho +DoHdrT: CALL ITshow ;show toggles + CALL VTshow + CALL HYshow + CALL AIshow + CALL DblSho +MRshow: LD A,(RMSav) ;requires header display + DEC A + LD HL,MRon + JP Z,PSDisp + LD DE,DspMrg + JP TogSho +; +TogSho: LD A,(NoHdrF) + OR A + RET NZ + PUSH HL ;toggle show subroutine + CALL GoTo + CALL MakAlt + POP HL + LD B,3 + CALL BHLMsg + JP UnAlt +; +; +UpLft: LD DE,0100H ;go to "top of text" + LD A,(RulFlg) + OR A + JR Z,UndrX + INC D + JR UndrX +UndrHd: LD DE,0100H ;go below header regardless +UndrX: JP GoTo +; +; +NoHdr: LD HL,NoHdrF ;toggles on/off + CALL ToggHL + OR A + JR Z,HdrOn +HdrOff: CALL AdjLns ;that's one more line + CALL IncVO + JP SetAl +HdrOn: CALL AdjLns + CALL DecVO + CALL DoHdr ;let's see it again + JP SetAl +; +; +;Show current file data in the heading +; +ShoFnm: CALL MakAlt + LD DE,DspFnm+8 ;blank out old stuff + CALL GoTo + LD B,19 + CALL BBlank + LD DE,DspFnm + CALL GoTo + LD A,(FCB) + ADD A,'A'-1 ;drive letter + CALL PutChA + LD A,(FCBU) ;user number 0-15 + LD C,A + LD B,'3' ;user 30+? + SUB 30 + JR NC,ShoFn1 + LD B,'2' ;user 20+? + LD A,C + SUB 20 + JR NC,ShoFn1 + LD B,'1' ;user 10+? + LD A,C + SUB 10 +ShoFn1: PUSH AF + LD A,B + CALL NC,PutChA + POP AF + JR NC,ShoFn2 + LD A,C +ShoFn2: ADD A,'0' ;show LSD of user number + CALL PutChA + LD BC,Z3NDR + CALL Z3EAdr + JR Z,ShoFnN ;skip if no NDR + LD H,B + LD L,C +ShFnNl: LD B,(HL) ;drive of this NDR entry + INC B + DEC B + JR Z,ShoFnN ;0 means no more entries + LD A,(FCB) + CP B ;drive match? + INC HL + JR NZ,ShFnNx + LD C,(HL) + LD A,(FCBU) + CP C ;user # match? + JR Z,ShFnNn ;yes, display NDR name +ShFnNx: LD DE,Z3NdrL+1 ;skip over NDR + ADD HL,DE + JR ShFnNl ;try next NDR +ShFnNn: LD A,'/' + CALL PutChA + LD B,8 ;show up to first 8 chars of NDR +ShFdLp: INC HL + LD A,(HL) + CP ' ' + CALL NZ,PutChA + DJNZ ShFdLp +ShoFnN: LD A,':' + CALL PutChA ;punctuate + LD HL,FCB+1 + LD B,8 ;Name +ShFnLp: LD A,(HL) + RES 7,A + CP ' ' ;Quit on blank + JR Z,ShFnLF + CALL PutChA + INC HL + DJNZ ShFnLp ;Loop for 8 +ShFnLF: LD A,'.' ;punctuate + CALL PutChA + LD HL,FCBt1 + LD B,3 ;Type +ShFnL2: LD A,(HL) + CALL PutChA + INC HL + DJNZ ShFnL2 + CALL PutSpc + LD A,'/' ;option + CALL PutChA + LD A,(FMode) + CALL PutChA + JP UnAlt +; +; +Ruler: LD HL,RulFlg ;toggle ruler on/off + CALL ToggHL + OR A + JP Z,RulOff +; +RulOn: CALL AdjLns ;readjust screen length + CALL DecVO + CALL Z,SetAl ;maybe on line 1? + JR RuShow +; +RulFix: LD A,(RulFlg) ;update ruler if on + OR A + RET Z +RuShow: LD IY,RulBuf ;build ruler here + LD A,(NSkip) ;starting column + INC A + LD C,A + LD A,(View) ;length + LD B,A +RuLp: LD E,'-' ;default char is "-" + LD A,(VTFlg) ;which tab mode? + OR A + JR Z,RuLpH + PUSH BC ;"T" if varitab stop + LD A,C + LD HL,VTList + LD BC,VTNum + CPIR + POP BC + JR Z,RuVtab + JR RuNtab +RuLpH: LD HL,TabCnt ;"I" if hardtab stop + LD A,C + DEC A + AND (HL) + JR Z,RuHtab +RuNtab: LD A,(RtMarg) ;"R" if right margin + CP C + JR Z,RuRM + JR C,RuDot ;or dot if outside + LD A,(LfMarg) + CP C + JR Z,RuLM ;or "L" if left margin + DEC A + CP C + JR NC,RuDot +RuLpF: LD (IY),E ;okay, show it + INC IY + INC C + DJNZ RuLp + LD (IY),0 + CALL UndrHd + LD HL,RulBuf + JP AltDsp +RuLM: LD E,'L' + JR RuLpF +RuRM: LD E,'R' + JR RuLpF +RuDot: LD E,'.' + JR RuLpF +RuVtab: LD E,'!' + JR RuLpF +RuHtab: LD E,'I' + JR RuLpF +; +RulOff: CALL AdjLns ;adjust screen size + CALL IncVO + LD E,A + CALL CrLft ;oops, may be near top + XOR A + ADD A,E + JP Z,ShoLn1 + JP SetAl +; +; +;Display one byte on the screen for messages rather than text. +;Hi bit set = following space. +; +DsByt: CP CR ;Is it a CR + JR Z,Sk1DB ;Yes, skip + CP X ;compressed space? + JR NC,Sk3DB +DsBy1: LD E,A ;normal character + LD HL,HPos ;room? + DEC (HL) + JP NZ,PutCh ;put it out + INC (HL) ;EOL + RET +Sk1DB: LD A,(HPos) ;Fill out spaces for CR + LD E,A ;(needed for attributes, etc) + CALL SpEOL + LD A,(AuWrap) ;does autowrap occur? + OR A + JR NZ,Sk1aDB + LD E,CR ;NO, put out a CRLF + CALL PutCh + LD E,LF + CALL PutCh +Sk1aDB: LD A,(View) + INC A + LD (HPos),A ;new line + RET +Sk3DB: AND 7FH ;compressed space + CALL DsByt +DsSpc: LD A,' ' + JR DsBy1 +; +; +;Display message pointed to by HL. 00h is end. +;80H,nn = skip count. +; +Dspla: LD A,(View) ;initialize + INC A + LD (HPos),A +DspLp: LD A,(HPos) ;or continue, here + LD E,A + LD A,(HL) ;get byte + INC HL + OR A ;All done? + RET Z + CP X ;hidden spaces? + JR NZ,Dsp10 + LD A,(HL) ;get space count + INC HL + LD B,A +Dsp01: PUSH BC + PUSH HL + CALL DsSpc + POP HL + POP BC + DJNZ Dsp01 + JR DspLp +Dsp10: PUSH HL + CALL DsByt ;Put it out + POP HL + JR DspLp ;Do next one +; +;Display message which immediatly follows the CALL +; +Dspl: POP HL + CALL Dspla + JP (HL) +DsplC: POP HL ;same, but continued + CALL DspLp + JP (HL) +; +; +;Make a text "window" at screen bottom +; +Window: LD A,(PhysLn) ;requires 16 lines or more + CP 16 + JP C,Error7 + LD HL,WinFlg ;toggles on/off + CALL ToggHL + OR A + JR Z,WinOff +; +WinOn: CALL AdjLns ;adjust counts + LD A,(PhysLn) + AND 1 + CALL NZ,ClLast ;clear odd line? + CALL TopV ;put chosen text on top + LD A,0FFh + LD (BelowF),A ;go below + CALL ShoSc ;show text + LD A,(NoHdrF) + OR A + JR NZ,WinOn2 + LD DE,0000h ;separator needed? + CALL GoTo + CALL SepLin + CALL ShoFnm ;with name +WinOn2: XOR A + LD (BelowF),A + JP SetAl +; +WinOff: CALL AdjLns + JP SetAl +; +; +AdjLns: LD A,(PhysLn) ;KEEP screen counts consistent + LD HL,WinFlg + BIT 0,(HL) + JR Z,AdjL1 + SRL A +AdjL1: LD (Lines),A ;physical window size + LD HL,NoHdrF + BIT 0,(HL) + JR NZ,AdjL2 + DEC A ;adjust for header if present +AdjL2: LD HL,RulFlg + ADD A,(HL) ;adjust for ruler if present + LD (TxtLns),A + RET +; +; +; SCREEN I/O ROUTINES +; +;Do screen control code strings (return Carry if none) +; +CtlStr: XOR A + ADD A,(HL) ;HL points to #,bytes (# may be 0) + SCF + RET Z + LD B,A + INC HL ;set up count +BHLMsg: +CtlSLp: LD E,(HL) + INC HL + PUSH BC + PUSH HL + CALL ShutUp ;do NOT filter + POP HL + POP BC + DJNZ CtlSLp + OR A + RET +; +BlkFCB: LD B,11 ;blank out FCB name,typ + LD DE,FCB+1 +BlkFil: LD A,' ' ;blank out B bytes at DE + LD (DE),A + INC DE + DJNZ BlkFil + RET +BBlank: PUSH BC ;blank out B spaces + LD E,' ' + CALL ShutUp + POP BC + DJNZ BBlank + RET +; +;Show messages and prompts +; +MsgDsp: PUSH HL ;must start at "top" + CALL UpLft + POP HL +AltDsp: PUSH HL ;display message in alt video + CALL MakAlt + POP HL + CALL Dspla + JR UnAlt +; +Prompt: PUSH HL ;Prompt: blank first line + CALL UpLft ;(with attribute) + CALL MakAlt + LD A,(View) + INC A + LD E,A + CALL SpEOL + CALL UnAlt + POP HL + JR MsgDsp ;then show prompt message +; +;Handle alternate video +; +MakAlt: LD A,(AltHdr) ;optional for messages and prompts + OR A + RET Z +AltY: LD HL,AltOn ;mandatory for ctl-chars + LD A,(AltBit) ;ram always uses hi bit + OR A + JP Z,CtlStr + LD A,X + LD (AltMsk),A + RET +UnAlt: LD A,(AltHdr) + OR A + RET Z +UnAltY: LD HL,AltOff + LD A,(AltBit) + OR A + JP Z,CtlStr + XOR A + LD (AltMsk),A + RET +; +;Character output +; +XPutCh: LD A,(Horiz) ;show character in E + LD HL,View ;UNLESS in lower rt corner + CP (HL) + JR NZ,PutCh + LD A,(Vert) + LD HL,TxtLns + CP (HL) + RET Z +PutCh: PUSH HL ;show char in E + PUSH DE + PUSH BC + LD A,(Filter) ;filtered + CP E + JR C,PutChQ ;'?' if char >= Filter (07FH) +PutCh1: LD A,(AltMsk) + OR E + CALL CONOut + POP BC + POP DE + POP HL + RET +PutChQ: LD E,'?' + JR PutCh1 +; +PutSpc: LD A,' ' +Echo: CP 20H ;echo typed char, IF nice + RET C ; (used for one-char input) +PutChA: PUSH DE ;show char in A + PUSH AF ; save it too (for Echo) + LD E,A + CALL PutCh + POP AF + POP DE + RET +; +CONOut: LD E,A +ShutUp: NOP ;<--- goes to RET for Quiet + LD C,UCON ;put byte to console (mostly ctls) + JP BDOSep +; +PosCur: LD A,(Horiz) + LD E,A + DEC E + LD A,(RulFlg) + AND 1 + LD HL,Vert + ADD A,(HL) + LD D,A +; +;Position cursor to row D column E +; +GoTo: LD A,(NoHdrF) ;lie for lack of header + AND D ;(decrement row if >0) + JR Z,GoTo01 + DEC D +GoTo01: LD A,(BelowF) ;implement window below + OR A + JR Z,GoToIt + LD A,(Lines) + ADD A,D + LD D,A +GoToIt: LD A,D + LD (CurRow),A + LD A,(PosMod) + CP 'N' + JR NZ,GoYPos + LD HL,PCu ;use Down,Right method (gaak) + CALL Go2Byt ;home first + LD A,D + OR A + JR Z,Go2RwF +Go2Row: PUSH DE ;move down to desired row + LD E,LF + CALL ShutUp + POP DE + DEC D + JR NZ,Go2Row +Go2RwF: LD A,E + OR A + RET Z +Go2Col: LD HL,PCu+2 + CALL Go2Byt ;now across to desired col + DEC E + JR NZ,Go2Col + RET +GoYPos: CP 'A' ;Okay, can be more sophisticated... + JR Z,GoANSI + LD HL,PCu ;use ESC = sequence + CALL Go2Byt ;leadin byte(s) + LD HL,PCu+2 + PUSH DE ;now coordinates + PUSH HL + LD A,(PosMod) ;which order? + CP 'R' + JR Z,GoToX ;(backwards) + LD A,D + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,E + ADD A,(HL) + CALL CONOut + JR GoToDl +GoToX: LD A,E + ADD A,(HL) + CALL CONOut + POP HL + POP DE + INC HL + LD A,D + ADD A,(HL) + CALL CONOut +GoToDl: LD A,(PosDly) ;optional delay for some terminals + OR A + RET Z + LD B,A + LD C,0 + JP BDlyLp +GoANSI: LD HL,ANSIms+3 ;use ANSI sequence + LD A,D + INC A ;origin 1,1 + CALL GoASub + LD HL,ANSIms+6 + LD A,E + INC A + CALL GoASub + LD HL,ANSIms + CALL CtlStr + JR GoToDl +GoASub: LD (HL),'0' ;tens digit +GASl1: CP 10 + JR C,GAS2 + INC (HL) + SUB 10 + JR GASl1 +GAS2: INC HL + ADD A,'0' ;units + LD (HL),A + RET +Go2Byt: CALL Go1Byt ;show one or two bytes at HL + LD A,(HL) + OR A + RET Z +Go1Byt: PUSH DE + LD B,1 ;just do one byte + CALL CtlSLp + POP DE + RET +ANSIms: DB 8,ESC,'[00;00H' ;for use with CtlStr +; +; +IfSpLn: LD A,(AltHdr) ;draw sep line IF headers not alt + OR A + RET NZ +SepLin: CALL MakAlt ;draw separator line + LD A,(View) + LD D,A + LD E,'-' +SLDlp: PUSH DE + CALL PutCh + POP DE + DEC D + JR NZ,SLDlp + JP UnAlt +; +; +;SHOW SCREEN ROUTINES +; +; | +------------------------ +; |HELLO! | ^ +; |This is your |text file, which is seen Vert +; |on the screen| just like this._ v +; | | \ +; |<---NSkip---> <-----Horiz-----> \ +; |<-----------CurCol------------> \Cursor at (H,V) +; +;Recheck current position on screen +; +Orient: LD A,(Vert) ;Adjust Horiz and Vert + LD E,A + CALL CrLft ;Start of first screen line + JR NC,Ornt1 + CALL TopV ;At top, set Vert to 1 + JR Ornt2 +Ornt1: LD A,(Vert) ;Decrement Vert if needed + SUB E ; to avoid whitespace at top + LD (Vert),A +Ornt2: CALL ColCnt ;Update columen (in A,B,CurCol) + INC A + JR NZ,Ornt3 + LD B,0FEH +Ornt3: LD A,(Horiz) ;Compute cursor offset in line + LD C,A + LD A,B + SUB C ;CurCol-Horiz is minimum offset + JR NC,Ornt4a + XOR A ;set 0 if negative +Ornt4a: LD E,A + LD A,(NSkip) ;present offset < min? + CP E + JR C,Ornt4b ;if so, change + CP B ;bigger than CurCol-1? + JR C,Ornt4c ;if not, OK + LD A,B ;round down to small enough + DEC A + AND 0C0H ;multiple of 32 + JR Ornt4c +Ornt4b: LD A,E ;round up to big enough + OR 1FH + JR Z,Ornt4c + INC A +Ornt4c: LD (NSkip),A ;set (new?) offset + SUB B + NEG + LD (Horiz),A + LD HL,(CurLin) ;Figure line, page + LD (CurPgL),HL + LD A,(FMode) + CP 'N' + LD A,(PgLen) + JR NZ,Ornt5 + XOR A ;don't SHOW pagination for nondocs +Ornt5: LD E,A + LD D,0 + DEC HL + LD B,D + LD C,D + OR A ;not paginating? + JR Z,OrnLpF + INC BC +OrntLp: SBC HL,DE + JR C,OrnLpF + INC BC + JR OrntLp +OrnLpF: ADD HL,DE + INC HL + LD (CurPgL),HL + LD (CurPg),BC + RET +; +;Show (just) as much of the text as necessary +; +ShoTx: CALL KyStat ;check keybd + JR NZ,ShoTx1 + CALL TestSc ;check postponed screen disp + JP NZ,ShoAll ;do it! + CALL ShoPos ;quiet? update header + CALL TestCu ;check postponed line disp + JR NZ,DoPost ;do it (or more, if requested) +ShoTx1: LD A,(ShoFlg) ;busy... + OR A ;nothing (0) + RET Z + DEC A + JP Z,ShoRCu ;just one line (1,2) - can be postponed + DEC A + JP Z,ShoCu + DEC A + JP Z,ShoDn ;bottom part (3) + JP ShoSc ;or whole screen +DoPost: LD A,(ShoFlg) + CP 3 + JP C,ShoCu ;at LEAST this + JP Z,ShoDn + JP ShoSc +; +;Show position in file, no matter what +; +ShoPos: LD A,(NoHdrF) + OR A + RET NZ + CALL Force ;must see this + LD DE,DspPg ;Update header + CALL GoTo + CALL MakAlt ;C128 bug fix requires GoTo first + LD HL,(CurPg) + LD A,(FMode) + CP 'N' + CALL NZ,ShPSb1 + LD DE,DspLin + LD HL,(CurPgL) + CALL ShPoSb + LD DE,DspCol + LD A,(CurCol) + LD L,A + LD H,0 + CALL ShPoSb + CALL UnAlt + JP UForce +ShPoSb: PUSH HL ;show a number + CALL GoTo + POP HL +ShPSb1: LD DE,PNBuf + CALL BCDCon + LD HL,PNBuf + LD B,5 + JP BHLMsg +; +;Show current line only (fast) +; +ShoCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu +ShoCu1: LD A,(Vert) + LD B,A + JP ShoLn +; +ShoRCu: CALL ConChk ;(postpone if busy!) + JP NZ,HoldCu + CALL FetchB + CP TAB ;can't do this with tab at left + JP Z,ShoCu + LD A,(Vert) ;special routine: only RIGHT of cursor + LD D,A ;...modeled on ShoLCu + LD A,(RulFlg) + AND 1 + ADD A,D + LD D,A ;current row + LD A,(Horiz) + DEC A + LD E,A + JP Z,ShoCu ;can't do this at left of screen + DEC E + CALL GoTo ;position to start + LD E,1 ;find start of line + CALL CrLft + PUSH HL + LD HL,Horiz + LD A,(NSkip) + ADD A,(HL) + DEC A + LD D,A + DEC A + LD B,A ;skip till just before cursor + LD A,(View) + INC A + SUB (HL) + LD E,A + INC E + POP HL + CALL ShoLSb ;do part (char!) left of cursor + INC E ;(DON'T ask me why this INC is needed) + LD D,E + DEC D + LD A,(Vert) + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShRCu3 + DEC D +ShRCu3: LD HL,(AftCu) + JP ShoLSb +; +;Display from Cursor line-1 down +; +ShoDn: CALL ConChk ;(postpone if busy!) + JP NZ,HoldSc + LD HL,CsrOff + CALL CtlStr + LD A,(DSFlg) ;(or line-2 if DS) + LD HL,Vert + ADD A,(HL) + JR Z,ShoSc0 + LD B,A + DJNZ ShScLp + JR ShoSc0 +; +;Show everything on emerging from macros etc +; +ShoAll: CALL Orient + CALL DoHdr + CALL ShoPos + JR ShoScX +; +;Display whole text screen (sigh) +; +ShoSc: CALL ConChk ;(Postpone if busy!) + JP NZ,HoldSc +ShoScX: LD HL,CsrOff + CALL CtlStr +ShoSc0: CALL RulFix + CALL SetNo ;kill any pending redisps + XOR A + LD (CuFlg),A + CPL + LD (HorFlg),A + LD B,1 ;Simple method if not memory mapped +ShScLp: PUSH BC + CALL ShoLn + POP BC + INC B + LD A,(TxtLns) + INC A + SUB B + JR NZ,ShScLp + LD HL,CurOn + CALL CtlStr + RET +; +IOoff1: LD DE,DspEsc ;header: blank prompt + CALL GoTo + CALL MakAlt + LD B,4+1 ;(cursor) + CALL BBlank + JP UnAlt +; +IOoff: LD A,(NoHdrF) ;headerless? redo top line + OR A + JR Z,IOoff1 + LD A,(RulFlg) + OR A + JP NZ,RuShow +; +;Show line 1 (to wipe out msgs) +; +ShoLn1: LD B,1 ;fall thru... +; +;Show line number B (=1...TxtLns) +; +ShoLn: LD A,(ShutUp) + OR A + RET NZ + PUSH BC + CALL KyStat ;(helps buffering for slow keyboards) + POP BC + LD A,(RulFlg) + AND 1 + ADD A,B + LD D,A ;position cursor on screen + LD E,0 + PUSH BC + CALL GoTo + POP BC + LD A,(Vert) ;is line before or after cursor? + SUB B + JR Z,ShoLCu ;ouch, it's cursor line + JR C,ShoLAf +ShoLBf: LD E,A ;okay, before + INC E + CALL CrLft + LD A,(View) + INC A + LD E,A + LD A,(NSkip) + LD B,A + LD D,255 + JR ShoLSb +ShoLAf: NEG ;okay, after + PUSH BC ;save line# + LD E,A + CALL CrRit + POP BC + PUSH AF + LD A,(View) + LD D,A + INC A + LD E,A + LD A,(TxtLns) + CP B ;last line? avoid last column + JR NZ,ShLAf0 + DEC D +ShLAf0: POP AF + JR C,ShLAf1 + JR Z,ShLAf2 +ShLAf1: JP ClEOL ;no line! +ShLAf2: LD A,(NSkip) + LD B,A + ADD A,D + LD D,A + JR ShoLSb +ShoLCu: LD E,1 ;hmm, right on cursor + PUSH BC ;save line# + CALL CrLft + LD A,(NSkip) + LD B,A + LD A,(CurCol) ;do part to left + DEC A + LD D,A + LD A,(View) + INC A + LD E,A + CALL ShoLSb + LD D,E + DEC D + POP AF ;line# + LD HL,TxtLns + CP (HL) ;avoid last line, col + JR NZ,ShLCu1 + DEC D +ShLCu1: LD HL,(AftCu) +; +ShoLSb: LD A,D ;Show up to column D of text starting at HL + OR A ;E=room+1, B=Cols to skip (if any) + RET Z + XOR A + EXX + LD B,A ;B',C' keep track of previous chars + LD C,A + LD E,A ;E' is count skipped + EXX + LD C,A ;initialize GetNx + ADD A,B + JR Z,ShLSL2 +ShLSL1: CALL GetNx ;eat skipped columns + JP Z,ClEOL ;end of line? + CP TAB + JR Z,ShLS1T + EXX + INC E ;E' + EXX + DEC D + DJNZ ShLSL1 + CALL ShSvCh + INC D + DEC D + RET Z + JR ShLSL2 +ShLS1T: EXX ;count for tabs + LD A,E + LD HL,TabCnt + AND (HL) + XOR (HL) ;extra spaces + INC A ;plus usual one + PUSH AF + ADD A,E + LD E,A + POP AF + EXX + PUSH AF + SUB D + NEG + LD D,A + POP AF + SUB B + NEG + LD B,A + JR NZ,ShLSL1 + LD A,TAB + CALL ShSvCh + INC D + DEC D + RET Z +ShLSL2: CALL GetNx ;show the rest + EXX + LD C,B + LD B,A + EXX + JR Z,ShLSCr ;take care of CR,TAB + CP ' ' + JR C,ShCtl + PUSH DE + LD E,A + CALL PutCh + POP DE +ShLSL3: DEC E + DEC D + RET Z + LD A,E + DEC A + RET Z + JR ShLSL2 +ShCtl: PUSH HL + PUSH BC + PUSH DE + CP TAB + JR Z,ShLSTb + ADD A,40H ;other ctls are hili letters + EX AF,AF' + CALL AltY ;(mandatory) + EX AF,AF' + CALL PutChA + CALL UnAltY + JR ShLRet +ShLSCr: PUSH HL + PUSH BC + PUSH DE + EXX + LD A,C ;last char + EXX + CP ' ' + JR Z,ShLCrF ;SCR doesn't show + LD A,(HCRFlg) + OR A + JR Z,ShLCrF ;HCRs also MAY not... + LD E,'<' + CALL PutCh + POP DE + DEC D + DEC E + PUSH DE + LD A,E ;don't ClEOL if now in last col + CP 2 +ShLCrF: CALL NC,ClEOL + POP DE ;end of line + POP BC + POP HL + RET +ShLSTb: LD A,(View) ;hit a tab... + INC A + SUB E ;column + LD HL,TabCnt + AND (HL) + XOR (HL) ;figure extra spaces + LD B,A + JR Z,ShLTLF +ShLTbL: CALL PutSpc ;do them + POP DE + DEC E + DEC D + PUSH DE + JR Z,ShLRet + DJNZ ShLTbL ;then one last +ShLTLF: CALL PutSpc +ShLRet: POP DE + POP BC + POP HL + JR ShLSL3 +ShSvCh: EXX ;keep track of prev chars + LD C,B + LD B,A + EXX + RET +; +; +ClEOL: LD HL,CIL ;clear to EOL (quickly if possible) + CALL CtlStr + RET NC +SpEOL: DEC E ;this always SPACES (for attributes) + RET Z +ClELp: LD A,(CurRow) + INC A + LD HL,PhysLn + CP (HL) + JR NZ,ClEL3 + DEC E ;avoid last char on last line + RET Z +ClEL3: CALL PutSpc + DEC E + JR NZ,ClEL3 + RET +; +ClLast: LD A,(PhysLn) ;clear last line on screen + DEC A + LD D,A + LD E,0 + CALL GoToIt + LD A,(View) + LD E,A ;do NOT INC this, it's last line + JR ClEOL +; +; +;Set level of display required +; +SetAl: LD A,0FFH ;routines to set it + JR Set1 ;(must preserve ALL REGS and FLAGS) +SetDn: LD A,3 + JR Set1 +SetCu: LD A,2 + JR Set1 +SetRCu: LD A,1 + JR Set1 +SetNo: XOR A ;this one WILL shut it up... + JR Set2 +Set1: PUSH AF ;...otherwise, do not DEcrease previous requests + EX (SP),HL + LD A,(ShoFlg) + CP H + EX (SP),HL + JR NC,Set3 + POP AF +Set2: LD (ShoFlg),A + RET +Set3: POP AF + RET +; +SmlDly: LD A,(Timer) + LD B,A + LD C,1 + JP BDlyLp +; +ScrUDx: LD A,0C9H ;(RET) + LD (UpLft),A + CALL ScrlUD + CALL NC,SmlDly ; delay if scrolled + LD A,11H ;(LD DE,nnnn) + LD (UpLft),A + RET +; +ScrlU2: LD HL,DelL + CALL ScrlUD + JR C,SetAl ; no scroll + JR SetCu +; +ScrlU: LD HL,DelL + JR ScrlX +; +EdgeU: LD A,(Vert) + DEC A ;first line: scroll + RET NZ +ScrlD: LD HL,InsL +ScrlX: CALL ScrlUD + JR C,SetAl ; no scroll + CALL SmlDly + JR SetCu +ScrlUD: PUSH HL ;[common sbr, used in one-liners too] + CALL TestCu + CALL NZ,ShoCu1 + LD A,(NoHdrF) ;canNOT do this if header is suppressed + LD HL,OddDel ; and ins/del specific to ln 1. + AND (HL) + LD HL,WinFlg ; or if Windowing (in any event) + OR (HL) + POP HL + JR NZ,NoScrl + PUSH HL + CALL UpLft + POP HL + CALL CtlStr ;do it + RET C ;(maybe couldn't) + LD A,(OddDel) + OR A + CALL NZ,RulFix + RET +NoScrl: SCF ; didn't scroll + RET +; +; Set flag for redisplay due to arrow keys +; +EdgeL: LD A,(Vert) + DEC A + RET NZ + LD A,(CurCol) + DEC A + RET NZ + JR ScrlD ;scroll if at top left +EdgeR: CALL Fetch + JR Z,ER01 + LD A,(Horiz) ;not CR: if off right edge, scroll + LD HL,View + CP (HL) + JR Z,HorScl + RET +ER01: LD A,(Vert) ;CR: if at bot right, scroll + LD HL,TxtLns + CP (HL) + JP Z,ScrlU +EdgeD: LD A,(Vert) + LD HL,TxtLns + CP (HL) + JP Z,ScrlU ;last line: scroll + RET +; +;Watch for horizontal scroll +; +IfScl: LD A,(NSkip) ;request scroll if already scrolled + OR A + RET Z +HorScl: CALL SetCu ;request scroll + XOR A + LD (HorFlg),A + RET +; +;Postpone display for speed +; +HoldCu: LD A,0FFH ;save if busy + LD (CuFlg),A + RET +HoldSc: LD A,0FFH + LD (ScFlg),A + RET +TestSc: LD HL,ScFlg ;test & reset postponement + JR TestX +TestCu: LD HL,CuFlg +TestX: XOR A ;(ret with Z if none) + ADD A,(HL) + LD (HL),0 + RET +; +; Position cursor for input +; +Cursr: CALL PosCur ;turn on cursor + CALL Fetch + RET NZ + LD A,(HCRFlg) ;oops, on a CR + OR A ;HCRs showing? + RET Z + CALL FetchB ;got to fix HCR flag + LD E,' ' ;kludge to " " or "<" + CP E + JR Z,Csr01 + CALL NdCnt + JR C,Csr01 + LD E,'<' +Csr01: CALL XPutCh + LD E,BS + JP PutCh +; +; +; Module: SETDS3 +; Version: 1.1 +; Author: Carson Wilson, modifed by Lars Nelson for use with +; ZDE (Dec 3, 2022). +; Date: February 11, 1990 +; +; SETDS3 -- Set file datestamp in CP/M Plus. +; +; Entry: DE = address of file's FCB +; HL = address of datestamp buffer +; BC = address of 1024-byte DMA buffer +; Exit: A = 0, zero flag set (Z), if stamp set +; A = error, zero flag reset (NZ), if error or not CP/M Plus: +; FF = file not found +; 06 = not CP/M Plus +; 05 = no stamps on disk +; 04 = BIOS sector size greater than 1024 bytes +; 03 = drive invalid +; 02 = BIOS read error +; 01 = BIOS write error +; Uses: AF +; Notes: The datestamp buffer should be filled on entry with a valid, eight +; byte CP/M Plus datestamp. It is assumed that the create stamp +; rather than the access stamp is being used. The file +; whose stamp is to be set must either be on the current drive or +; at the drive specified by FCB byte 0. Only files at the current +; user number will be matched. No wildcards allowed. To allow a +; reasonable interface standard, this routine will NOT work under +; systems configured with BIOS sectors larger than 1k. No systems +; exceeding this size have yet been encountered, but BIOS sectors +; of 2k and 4k are technically legal under CP/M Plus. +; +SETDS3: + ld (SAVEIX),ix ; save registers + ld (DMAPTR),bc + ld (FCBPTR),de + ld (STPPTR),hl + xor a + ld (CHGFLAG),a ; Say no changes + ld (SECTOR),a +; +; Set BIOS DMA to ours, get DPH address from BIOS +; + push de ; Save FCB pointer + ld (BCREG),bc + ld a,12 ; Set BIOS DMA to our buffer + ld (FUNC),a + call CALLBIOS + ld c,GDRV ; Get current BDOS disk + call BDOSep + ld (BDOSDRV),a + pop hl ; FCB pointer + ld a,(hl) + or a ; Disk specified? + jr nz,DSKPR1 + ld a,(BDOSDRV) + inc a +DSKPR1: dec a + ld (DRVCOD),a ; Save code for reset later + ld c,a ; Disk number + ld e,0 ; Flag initial select + ld (BCREG),bc ; BIOS select disk function + ld (DEREG),de + ld hl,0 + ld (HLREG),hl ; Required by Morrow BIOS (bug?) + ld a,9 ; 'SELDSK' + ld (FUNC),a + call CALLBIOS + ld a,h + or l ; Check for drive error + jp z,DRVER ; Quit if so + ld e,(hl) ; Get DPH address + inc hl + ld d,(hl) + ld (XLTADD),de ; Save address of XLT + ld bc,11 + add hl,bc ; HL --> .DPB + ld e,(hl) + inc hl + ld d,(hl) ; DE --> DPB + ex de,hl + ld e,(hl) ; Get logical SPT + inc hl + ld d,(hl) + ld (SPT),de + ld de,3 ; Offset to EXM (# of extents/entries-1) + add hl,de ; Add offset + ld a,(hl) ; Get EXM + ld (EXM),a + ld de,3 ; Offset to DRM (# of directory entries) + add hl,de ; Add offset + ld e,(hl) ; Get DRM + inc hl + ld d,(hl) + push de ; Save DRM + push hl ; Save .highDRM + ld de,7 ; Point to PSH + add hl,de + ld a,(hl) ; Get it + ld (PSH),a ; Save it + pop de ; Get .highDRM + pop hl ; Get DRM + inc hl ; Add 1 for total directory entries + ld a,(PSH) + cp 4 + jp nc,PHYSER ; Physical sector size > 1024 + inc a + inc a + ld b,a + call DIVHLB + ld (DVD),a + ld a,l ; Save # of directory sectors + ld (DIRSEC),a + ld hl,(SPT) ; Logical sectors per track + ld a,(PSH) + ld b,a + call DIVHLB + ld a,l ; PHSPT = SPT for 128 byte sectors + ld (PHSPT),a ; Physical sectors per track + ld hl,5 ; Add offset to # of reserved tracks + add hl,de + ld e,(hl) ; Get number of reserved tracks + inc hl + ld d,(hl) + ld (RESTKS),de ; Save reserved tracks for later + ld c,USRN ;set or get user function # + ld e,0FFh ; Get + call BDOSep ;get user # in A + ld hl,(FCBPTR) + ld (hl),a ; Stuff to match dir. entry +; +; Now copy Caller's stamp to STPBUF + ld hl,(STPPTR) ; Caller's stamp + ld de,STPBUF ; Put it here + ld bc,8 ; Move 8 bytes only + ldir +; +; GETDIR - Read a physical sector of the directory to our buffer +; +GETDIR: ld a,(DIRSEC) ; Get # of directory sectors remaining + or a + jp z,EXIT3 ; Return if none + call PHSECTRK ; Compute cur. physical sector and track + ld bc,(RESTKS) ; Get number of reserved tracks in BC + ld h,0 ; Get physical track number in HL + ld a,(PHTRK) + ld l,a + add hl,bc ; Directory track in HL + ld (BCREG),hl ; Set track to directory + ld a,10 ; SETTRK + ld (FUNC),a + call CALLBIOS + ld a,(PHSECT) ; Get current physical sector + ld c,a + call TRNSEC ; Translate sector if necessary + ld b,0 + ld (BCREG),bc ; Point to current sector + ld a,11 ; SETSEC + ld (FUNC),a + call CALLBIOS + ld a,13 ; Read sector of directory + ld (FUNC),a + call CALLBIOS + or a + jp nz,RDERR ; Read error +; +; Check entries for match. Modify and write back if match found. +; + xor a ; Zero flag + ld (RECFLG),a + ld (OFFST),a ; Offset of entry in directory record + ld a,(DVD) ; Get number of dir. entries per sector + ld b,a + ld hl,(DMAPTR) +CKNXT: push bc + ld de,(FCBPTR) + call COMP12 ; Match? + jp nz,GETNXT ; No +; HL points to buffer location of our entry + push hl + push bc + ld a,(OFFST) + add a,a + add a,a + add a,a + add a,a + add a,a ; x32 + ld b,0 + ld c,a + sbc hl,bc ; HL --> start of record + ld bc,60h + add hl,bc ; Now find stamp in record + ld a,(OFFST) + add a,a + ld b,a + add a,a + add a,a + add a,b ; *10 + inc a ; +1 + ld b,0 + ld c,a + add hl,bc ; HL --> our file's stamp + ld de,STPBUF + ex de,hl + ld bc,8 + ldir ; Copy STPBUF --> SECTOR + pop bc + pop hl + ld a,1 ; Set changed flag + ld (RECFLG),a + ld (CHGFLAG),a +GETNXT: ld a,(OFFST) + inc a +GETNX1: ld (OFFST),a + ld de,32 ; Advance to next entry + add hl,de + ld a,(hl) + cp '!' ; Stamp? + jr nz,GETNX2 ; No + pop bc ; Yes, skip + dec b ; Decrement entry count + jr z,GETNX3 ; Stop if done + push bc + xor a ; Reset OFFSET + jr GETNX1 +; +GETNX2: pop bc + ld a,(OFFST) + cp 3 + jp nc,NOSTER ; No stamps if 4 consecutive entries lack '!' + djnz CKNXT ; Decrement counter +GETNX3: ld a,(RECFLG) ; Check for changed entry + or a ; Write? + jr nz,WRTSEC ; Yes, finish up + ld a,(DIRSEC) ; Nope, decrement physical directory sectors + dec a + ld (DIRSEC),a + ld a,(SECTOR) ; Increment sector + inc a + ld (SECTOR),a + jp GETDIR ; Back for another +; +; Write sector back to disk and quit +; +WRTSEC: ld bc,1 ; Non-deferred write + ld (BCREG),bc + ld a,14 ; Write + ld (FUNC),a + call CALLBIOS ; Update directory + or a ; Check for write error + jp nz,WRTER + ld a,(DRVCOD) ; Reset drive (0..15) + ld hl,1 + and a ; Ready if drive A + jr z,RESETT + ld b,a +ADDHL: add hl,hl ; Else calculate vector + djnz ADDHL +RESETT: ex de,hl + ld c,37 ; Tell BDOS to log out drive + call BDOSep + jr EXIT3 ; Return to caller +; +; EXIT ROUTINES +; +NOSTER: ld a,6 ; No stamps + jr EXIT1 +; +PHYSER: ld a,5 ; Sector size > 1024 + jr EXIT1 +; +DRVER: ld a,4 ; Drive invalid + jr EXIT1 +; +RDERR: ld a,3 ; BIOS read error + jr EXIT1 +; +WRTER: ld a,2 ; BIOS write error + jr EXIT1 +; +EXIT3: ld a,(CHGFLAG) +EXIT1: dec a ; (NZ) means error + push af +; restore drive in fcb + ld a,(DRVCOD) ; 0-15 + inc a ; make it 1-16 + ld hl,(FCBPTR) ; point to fcb + ld (hl),a ; restore drive + ld a,(BDOSDRV) ; Re-synchronize BIOS w/BDOS + ld c,a ; Disk number + ld e,1 ; Not initial select + ld (BCREG),bc ; BIOS select disk function + ld (DEREG),de + ld hl,0 + ld (HLREG),hl ; Required by Morrow BIOS (bug?) + ld a,9 ; 'SELDSK' + ld (FUNC),a + call CALLBIOS + pop af ; Restore result code + ld bc,(DMAPTR) ; restore all registers + ld de,(FCBPTR) + ld hl,(STPPTR) + ld ix,(SAVEIX) + ret ; Return to caller +; +; SUBROUTINES +; +COMP12: ; Compare 12 bytes directory entry @HL + push de ; ..with FCB @DE + push hl + push bc + ld b,12 +COMP12A: + ld a,(de) + sub (hl) + and 01111111b ; Ignore high bits + jr nz,COMPX ; Unequal + inc hl + inc de + djnz COMP12A ; RETURN (Z) if match + ld a,(EXM) ; Make sure we're at first entry + cp (hl) + ld a,0 + jr nc,COMP12B ; At first if <= EXM + ld a,0FFh ; Otherwise no match +COMP12B: + or a +COMPX: pop bc + pop hl + pop de + ret +; +; Divide HL by 2^B, A = 2^B on exit +; +DIVHLB: ld a,1 +DIVHL1: add a,a ; Double A, zero (C) + rr h + rr l + djnz DIVHL1 + ret +; +PHSECTRK: + ld c,0 ; Set 'PHTRK' to 0 + ld a,(PHSPT) + ld b,a ; Phys SPT in 'B' + ld a,(SECTOR) ; Logical directory sector +CKPHTRK: + cp b ; Compute PHSECT = sectors mod PHSPT + jr c,STSECTRK ; And PHTRK = (sectors - PHSECT)/PHSPT + sub b + inc c + jr CKPHTRK +STSECTRK: + ld (PHSECT),a + ld a,c + ld (PHTRK),a + ret +; +TRNSEC: ld hl,(XLTADD) ; Get translate table address + ld (DEREG),hl + ld (BCREG),bc + ld a,16 ; SECTRAN + ld (FUNC),a + call CALLBIOS + ld c,l + ret +; +CALLBIOS: ; CP/M v3.0 direct BIOS call + ld c,GOBIOS + ld de,FUN50 + call BDOSep + ret +; +; MESSAGES +; +ErrTab: DW 0,MSG1,MSG2,MSG3,MSG4,MSG4,MSG7,MSG7,MSG8,MSG9 +; +MSG1: DB 'Ou','t'+X,'o','f'+X,'Memory',0 +MSG2: DB 'Invali','d'+X,'Key',0 +MSG3: DB 'I/','O'+X ;(fall through to 7) +MSG7: DB 'Error',0 +MSG4: DB 'No','t'+X,'Found',0 +MSG8: DB 'Synta','x'+X,'Error',0 ;(note 5,6 not used) +MSG9: DB 'Canno','t'+X,'Reformat',0 ;(note error 10 has no MSG) +; +NameQ: DB 'Name',':'+X,0 +ReadQ: DB 'Read',':'+X,0 +WritQ: DB 'Write',':'+X,0 +EraQ: DB 'Erase',':'+X,0 +LoadQ: DB 'Load',':'+X,0 +FindQ: DB 'Find',':'+X,0 +ChgQ: DB 'Chang','e'+X,'to',':'+X,0 +DirQ: DB 'Dir',':'+X,0 +PrtQ: DB 'Options',':'+X,0 +PgLnQ: DB 'Length',':'+X,0 +ColQ: DB 'Column',':'+X,0 +PageQ: DB 'Page',':'+X,0 +LineQ: DB 'Line',':'+X,0 +MacroQ: DB 'Macro',':'+X,0 +RptcQ: DB 'Repea','t'+X,'coun','t'+X,'([Q],0-9/*)',':'+X,0 +KeyQ: DB 'Ke','y'+X,'numbe','r'+X,'([N/Q],0-9)',':'+X,0 +QuitQ: DB 'Abando','n'+X,'changes','?'+X,'(Y/N)',':'+X,0 +UnchgQ: DB 'Unchanged',';'+X,'save','?'+X,'(Y/N)',':'+X,0 +; +; Changed: Q File size: NNNNN Memory used: NNNNN Free: NNNNN +InfMsg: DB CR + DB ' '+X,'Changed',':'+X +ModQQQ: DB 'Q',X,7,'Fil','e'+X,'size',':'+X +SizNNN: DB 'NNNNN',X,5,'Memor','y'+X,'used',':'+X +UsdNNN: DB 'NNNNN',X,5,'Free',':'+X +FreNNN: DB 'NNNNN',CR,0 +; +; [Menus disabled; see VDE.DOC or .QRF] +; [See VDE.DOC and .QRF for help] +; +HlpMsg: DB X,26,'[Menu','s'+X,'disabled',';'+X,'se','e'+X + DB 'Manual]',CR,0 +; +;A4/DOC:FILENAME.TYP /A Pg 1 Ln 1 Cl 51 INS vt by AO DS scr top ^QY del to EOL ^QF Find +; ^QP to Place mk ^Q scr bot ^QDel " to BOL ^QA replAce +; ^QR goto TOF ^Q ln start ^QT del to char ^QP to last cursor +; ^QC goto EOF ^Q ln end ^QU UNdel line ^QI goto pg/ln +; ^QQ goto ZCPR queue line +; +QMenu: DB X,4,'^Q','B'+X,'got','o'+X,'Block',X,4,'^Q'+X,'sc','r'+X,'top' + DB X,5,'^Q','Y'+X,'de','l'+X,'t','o'+X,'EOL',X,4,'^Q','F'+X,'Find',CR + DB X,4,'^Q','Z'+X,'t','o'+X,'plac','e'+X,'mk',X,3,'^Q'+X,'sc' + DB 'r'+X,'bot',X,5,'^QDe','l'+X,'"'+X,'t','o'+X,'BOL',X,4,'^Q','A'+X + DB 'replAce',CR + DB X,4,'^Q','R'+X,'got','o'+X,'TOF',X,6,'^Q'+X,'l','n'+X,'start' + DB X,4,'^Q','T'+X,'de','l'+X,'t','o'+X,'char',X,3,'^Q','P'+X,'t','o'+X + DB 'las','t'+X,'cursor',CR + DB X,4,'^Q','C'+X,'got','o'+X,'EOF',X,6,'^Q'+X,'l','n'+X,'end' + DB X,6,'^Q','U'+X,'UNde','l'+X,'line',X,4,'^Q','I'+X,'got','o'+X + DB 'Pg/Ln',CR + DB X,'(^Q','Q'+X,'got','o'+X,'ZCP','R'+X,'queu','e'+X,'line',CR,0 +; +;^OL,R marg set ^OI tab set ^OP Page length ^O make top ln ^OA Auto-in +; ^OX marg rel ^ON tab clr ^OS dbl Spacing ^OW Window ^OQ Quiet +; ^OC Center ^OV Vari tabs ^OH Hyphenation ^OJ proportional +; ^OF Flush rt ^OT ruler ^OD Display CRs ^OZ Zap screen +; +OMenu: DB '^OL,','R'+X,'mar','g'+X,'set',X,2,'^O','I'+X,'ta','b'+X,'set' + DB X,4,'^O','P'+X,'Pag','e'+X,'length',X,2 + DB '^O'+X,'mak','e'+X,'to','p'+X,'ln',X,2,'^O','A'+X,'Auto-in',CR + DB X,2,'^O','X'+X,'mar','g'+X,'rel',X,2,'^O','N'+X,'ta','b'+X,'clr' + DB X,4,'^O','S'+X,'db','l'+X,'Spacing',X,4,'^O','W'+X,'Window',X,7 + DB '^O','Q'+X,'Quiet',CR + DB X,2,'^O','C'+X,'Center',X,4,'^O','V'+X,'Var','i'+X,'tabs' + DB X,2,'^O','H'+X,'Hyphenation',X,4,'^O','J'+X,'proportional',CR + DB X,2,'^O','F'+X,'Flus','h'+X,'rt',X,2,'^O','T'+X,'ruler' + DB X,6,'^O','D'+X,'Displa','y'+X,'CRs' + DB X,4,'^O','Z'+X,'Za','p'+X,'screen',CR,' ',CR,0 +; + DS 4 +MnuEnd: ;menus end here, text can begin + END + \ No newline at end of file diff --git a/Source/Images/Common/All/u15/ZDE.COM b/Source/Images/Common/All/u15/ZDE.COM index b80559beb42aa801f7a08277700b47b2bb3db66a..2f30876b89822827f7a3d765937f5b47ca8fe4f1 100644 GIT binary patch literal 18688 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 diff --git a/Source/Images/d_ws4/u1/README.MD b/Source/Images/d_ws4/u1/ReadMe.md similarity index 87% rename from Source/Images/d_ws4/u1/README.MD rename to Source/Images/d_ws4/u1/ReadMe.md index 2fc3496b..b7e9be64 100644 --- a/Source/Images/d_ws4/u1/README.MD +++ b/Source/Images/d_ws4/u1/ReadMe.md @@ -28,4 +28,9 @@ your terminal and printer. ## ZDE 1.8 - Lars Nelson 12/3/2022 Added routine to save create time stamp under CP/M Plus since -CP/M Plus, unlike ZSDOS, has no native ability to set time stamps. \ No newline at end of file +CP/M Plus, unlike ZSDOS, has no native ability to set time stamps. + +## ZDE 1.9 - Peter Onion 03/27/2025 + +- Added support for ANSI PgUp, PgDn, Home, & End. +- Support ANSI F1 key for menu/error escape. diff --git a/Source/Images/d_ws4/u1/ZDE16.COM b/Source/Images/d_ws4/u1/ZDE16.COM deleted file mode 100644 index 55c492a5f0c309c96fcaa50e5953b0d6dfad1f8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16896 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 NGjq$Q{9oGH{wKiUo$>$x diff --git a/Source/Images/d_ws4/u1/ZDE16A.COM b/Source/Images/d_ws4/u1/ZDE16A.COM deleted file mode 100644 index 3e9fdcc04bcf4128d60a4662e694f9410b6517db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16896 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 diff --git a/Source/Images/fd_ws4.txt b/Source/Images/fd_ws4.txt new file mode 100644 index 00000000..d10b7891 --- /dev/null +++ b/Source/Images/fd_ws4.txt @@ -0,0 +1,4 @@ +# +# Add the ZDE binaries +# +../../Binary/Apps/ZDE/*.com 1: diff --git a/Source/Images/hd_ws4.txt b/Source/Images/hd_ws4.txt new file mode 100644 index 00000000..d10b7891 --- /dev/null +++ b/Source/Images/hd_ws4.txt @@ -0,0 +1,4 @@ +# +# Add the ZDE binaries +# +../../Binary/Apps/ZDE/*.com 1: diff --git a/Source/RomDsk/ROM_256KB/ZDE.COM b/Source/RomDsk/ROM_256KB/ZDE.COM index b80559beb42aa801f7a08277700b47b2bb3db66a..2f30876b89822827f7a3d765937f5b47ca8fe4f1 100644 GIT binary patch literal 18688 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 diff --git a/Source/RomDsk/ROM_384KB/ZDE.COM b/Source/RomDsk/ROM_384KB/ZDE.COM index b80559beb42aa801f7a08277700b47b2bb3db66a..2f30876b89822827f7a3d765937f5b47ca8fe4f1 100644 GIT binary patch literal 18688 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 diff --git a/Source/RomDsk/ROM_896KB/ZDE.COM b/Source/RomDsk/ROM_896KB/ZDE.COM index b80559beb42aa801f7a08277700b47b2bb3db66a..2f30876b89822827f7a3d765937f5b47ca8fe4f1 100644 GIT binary patch literal 18688 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