IMD 1.16: 8/06/2007 19:21:13                    EDITM DOCEDITM COMMBASEDITBASU COMZ80 RDF STRIP DOC STATWILDASM UNERA COM WASH COM HATSNEWCOMWHATSNEWDOC STRIP COMPIPPATCHASM#RPIP ASM2SORTDIR COMSPIP COMDSTACK LIBPghijkI8085 LIBlINTER LIBmnNCOMPARELIB oSELECT LIB pSEQIO LIBRqrstuvSIMPIO LIBwSTACK LIB xTREADLESLIByWHEN LIBzZ80 LIB/{|}SEQIO22 LIB~OBSLIB RELOBSLIB RELzPAGE COM9The editor EDIT.ASM published in CPMUG has been modified in three features. 1. It allows the use of both upper and lower case in the commands, which increases speed. 2. A new command, the M(ove) command, is included. This command allows to write data to disk starting any place in the edited material. Assume you have a text which you want to process and you want to exchange the first and the second paragraph. Simply move the pointer to the beginning of the second paragraph and EXTEND ASM*FILE-XT2ASM: !"#FILE14 ASMe$%&'()*FILFND12ASM+,-./0123FLOPCOPYASM}456789:;FLOPCOPYDOC <FMAP3 ASM8=>?@I/OCAP11ASMABCDEFGHIJXLATE2 MACKLMNOPQRSTUVWXYZXLATE2 MAC [\XLATE2 COM(]^_XCAT37 DOC `aXCAT37 COMbcBUTTONS LIBdCOMPARE LIB eDOWHILE LIBftype nM (or nm) ;where n is the number of lines ;to be writte to disk. The moved lines are killed in memory and the gap is closed. Then type 999W (or 999w) which transfers the first paragraph and the remainder of text to disk. 3. Characters deleted by RUBOUT are actually deleted instead of being echoed as in the previous version. Editor based on the one published in CPMUG Volume 16. Modified by: Dr. Donat-P. Hader, Marburg, West Germany.     ---------- From Ward Christensen: No new documentation was supplied with this program, so here is the original documentation with the new commands added, and Tony Gold's original comparison of ED and EDIT. This is an editor similar to cp/m's ed.com, but with command syntax like intel's editor for those of you who are used to that. the escape char is used as a delimiter in command lines (it is echoed as a $), and a double escape is used to terminate a command line. This editor is much faste-existing back-up file so that there will be room for the temporary. If you don't, you will get a disk full error. In find or substitute commands, the character '|' will match any character. If you want to change this character, look for the sequence fe, 7c in the code and change the 7c to the character you prefer. [A.R.G SUMMARY OF COMMANDS COMPARED WITH ED.COM: NOTE () ARE TO INDICATE A CONTROL CHARACTER, <> USED LITERALLY ED.COM EDITM.COM B B Beginning of file -B Z End o(to interupt printing) Extended command: 2MF.ASM(^Z)0LK(CR) 2(ESC)(ESC) Control characters referenced above: (CR) := 0DH ^M Return (SUB) := 1AH ^Z (ESC) := 1BH ^[ Escape (NUL) := 00H ^@ Break rence of string # 65536 No "#" in EDITM M <> SEE EXTENDED COMMAND BELOW P NONE H NONE O NONE R NONE (^Z) (ESC) (as terminator in searches) (CR) (ESC) (ESC) (to execute commands) (CR) NONE (to cause LT sequence) Char (NUL) 2 2 1 * "###"w!]~ , !\ mb<:ld !\s m! 6#6:\2stgsTÎY*+D}: >!4N! ~¶2 !6=Ÿ>ó!r4N! qy>2!rs!:s m6s!r s: !] ~# ppp# } NEW FILE$ NO .LIB FILE $ NO MORE DISK SPACE$ NO SOURCE FILE SPECIFIED$Ÿ>óASMN! qy>2!rx#" *|* " +" 2 2 v2 C * * WuͶ Ͷ"P>$O|A{Ͷu|2 * #" "u * * Ͷڔ|": «* +"  q|> }²>2 O½$|* +" : w: u~2 "* * Ͷ ! 6* ~A{! 60:! 6* +" : -1! 62 <+<2 !: aT]))): 0_2 ?" : |#" * DM* >W> * xʓ: ҾͶ¤ Ͷʤ+ xʻ~ʼ+®è## x~Ȼ#!A 6 *A w!A ~ 4* ! er than either the intel editor or ed.com; unlike the intel editor, this one does have the 'n' command and the 'q' command; it does not have the 'r' command, however. Another difference with respect to the intel editor is that the 'a' command only appends one line, but you can say 9999a to append much. The editor creates a third file with type $$$ which is renamed when the edit job is complete. This means that if you are editing a file which occupies over half of the disk, you must erase any prf file E E End edit Q Q Quit (does not ask if OK) C C Move a character T T Type line from cursor L L Move up/down lines K K Kill lines D D Delete characters I I Insert text A A Append from input file W W Write to output N N Next occurrence of string # 65536 No "#" in EDITM M <> SEE EXTENDED COMMAND BELOW P NONE H NONE O NONE R NONE (^Z) (ESC) (as terminator in searches) (CR) (ESC) (ESC) (to execute commands) (CR) NONE (to cause LT sequence) Char (NUL) s!:s m6s!r s: !] ~ pp$$$ NEW FILE$ NO.LIB FILE $ NO MORE DISK SPACE$ NO SOURCE FILE SPECIFIED$Ÿ>óASMN! qy>2!rs!:s SUPER CP/M EDITOR " ILLEGAL IN THIS CONTEXT CANNOT FIND " ITERATION STACK FAULT *BREAK*  | y † G: /Gy 2 |y گ: <2 |}`iN#|zþ͉vC : * * +" ! {#OzG~+ %BK# ~| PY%7Dͼ:A A _ͼ"|uC * * {Oz! ~#O~Gڂ* * w# xo+6" * +" 61 ͼ͌o`" !" ! " " ͺô* " * " ! 6!" 2 -+: :  SͼC * ! s#r* ! s#r>VNyV! ~w#~w+Q! ^#V" ! 5:  : [ Ao&) ^#V* DM* * ͶҪ͕ʌʌʪw# † x†" 6! " ;" : * * {_zW! Ͷ* Ͷ;: ! ! s#rL!    ~ O# ͕O :  m6B#6A#6K#}s'*A " L* #" * * ͶC ! {O#zG * ~ʷ +ì *  Ͷ Ͷ " " w+ x #" * * }O|G* ~+  x ~" " € Lq" * ͶL" " Lq" i * * ͶU !2" Ϳ * {'" * " 8 ssD'*A " " q q* }o|gҶ * z/W{/_DMz¼! 6! " q" ! ͶLN# * " vc   q   .10 :REM********************* MBASEDIT.BAS ************************ 20 :REM* AL BRENDEL 3/15/81 30 :REM* A DATA ENTRY AND EDITING SUBROUTINE FOR MBASIC 5.X 40 :REM* FOR TERMINALS WITH OR WITHOUT CURSOR CONTROL 50 :REM* ESPECIALLY USEFUL FOR GETTING OR EDITING DATA WITH FIXED 60 :REM* FIELD LENGTHS FOR FORM PRINTING OR RANDOM ACCESS FILES 70 :REM* ( SEE ALSO CBASEDIT.BAS FOR C-BASIC2 VERSION ) 80 :REM* 90 :REM*************** TEST OF THE BASEDIT FUNCTION ******************* 100 :REM 110 DATA NUMBER REM 'EDITING COMMANDS INCLUDE: 1070 : REM 'MOVE CURSER RIGHT.. > 1080 : REM 'MOVE CURSER LEFT... < OR BS(^H) 1090 : REM 'DELETE CHARACTER... DEL 1100 : REM 'INSERT CHARACTER... ^ 1110 : REM 'RETURN TO PROGRAM... CR 1120 : NAM$=NAM$+STRING$(LENGTH-LEN(NAM$),42) 1130 : PRINT MSG$;": ";NAM$+STRING$(LENGTH,8); 1140 : FOR NUM = 1 TO LENGTH 1150 : ANS%=ASC(INPUT$(1)):PRINT CHR$(ANS%); 1160 : IF ANS%=13 THEN GOTO 1280 1170 : IF ANS%=8 AND NUM=1 THEN PRINT CHR$(32)+MID$ IF ANS%=94 THEN NAM$=LEFT$(NAM$,NUM-1) +" "+MID$(NAM$,NUM,LENGTH-NUM) :PRINT CHR$(8)+RIGHT$(NAM$,LENGTH-NUM+1) +STRING$(LENGTH-NUM+1,8); :NUM=NUM-1:GOTO 1270 1240 : IF ANS%=127 THEN NAM$=LEFT$(NAM$,NUM-1) +RIGHT$(NAM$,LENGTH-NUM)+"*" :PRINT RIGHT$(NAM$,LENGTH-NUM+1) +STRING$(LENGTH-NUM+1,8); :NUM=NUM-1:GOTO 1270 1250 : NAM$=LEFT$(NAM$,NUM-1) +CHR$(ANS%)+RIGHT$(NAM$,LENGTH-NUM) 1260 : IF NUM=LENGTH THEN PRINT CHR$(7)+CHR$(8);:NUM=NUM-1 1270 : NEXT NUM 12 L 5   t      : !u"|! N|)1 ͼñj 8 ! 6q" * ͶLN#[ " 8 ssD'*A " " q ~" " € Lq" * ͶL" " Lq" i * * ͶU !2" Ϳ * {'" * " 8 ssD'*A " " q q* }o|gҶ * z/W{/_DMz¼! 6! " q" ! ͶLN# * " vc   q   . 1 = ,12345,10 120 DATA NUMBER 2 = ,1234567890,20 130 DATA NUMBER 3 = ,ABCDEFG,30 140 FOR X=1 TO 3 150 READ MSG$,NAM$,LENGTH 160 GOSUB 1000 170 ANS$(X)=NAM$ 180 NEXT 190 PRINT ANS$(1),ANS$(2),ANS$(3) 200 END 1000 : REM ********** GET DATA AND EDIT FUNCTION ************* 1010 : REM *TYPICAL APPLICATION: 1020 : REM MSG$="EDIT..":NAM$="1234":LENGTH=20:GOSUB 1000 1030 : REM 'PRINTS MSG AND THEN ALLOWS 1040 : REM 'ENTRY OR MODIFICATION OF NAM$ AND 1050 : REM 'SHOWS LENGTH OF FIELD 1060 :(NAM$,NUM,1)+CHR$(8); :NUM=NUM-1:GOTO 1270 1180 : IF ANS%=8 THEN NUM=NUM-2 :GOTO 1270 1190 : IF ANS%=62 AND NUM=LENGTH THEN PRINT CHR$(8) +MID$(NAM$,NUM,1)+CHR$(8)+CHR$(7); :NUM=NUM-1:GOTO 1270 1200 : IF ANS%=62 THEN PRINT CHR$(8)+ MID$(NAM$,NUM,1);:GOTO 1270 1210 : IF ANS%=60 AND NUM>1 THEN PRINT CHR$(8)+ MID$(NAM$,NUM,1)+CHR$(8)+CHR$(8); :NUM=NUM-2:GOTO 1270 1220 : IF ANS%=60 AND NUM=1 THEN PRINT CHR$(8) +MID$(NAM$,NUM,1)+CHR$(8); :NUM=NUM-1:GOTO 1270 1230 : 80 : FOR NUM=1 TO LENGTH 1290 : IF MID$(NAM$,NUM,1)="*" THEN NAM$= LEFT$(NAM$,NUM-1)+" " +RIGHT$(NAM$,LENGTH-NUM) 1300 : NEXT NUM 1310 : PRINT MSG$;": ";NAM$ 1320 : RETURN 1330 : FT$(NAM$,NUM-1)+" " +RIGHT$(NAM$,LENGTH-NUUM)+"*" :PRINT RIGHT$(NAM$,LENGTH-NUM+1) +STRING$(LENGTH-NUM+1,8); :NUM=NUM-1:GOTO 1270 1250 : NAM$=LEFT$(NAM$,NUM-1) +CHR$(ANS%)+RIGHT$(NAM$,LENGTH-NUM) 1260 : IF NUM=LENGTH THEN PRINT CHR$(7)+CHR$(8);:NUM=NUM-1 1270 : NEXT NUM 12   !]~ i:+_Aii_:2#~ 0i i_#~ Q0i iO{__{i?O:2r Drive and user selector: U.COM - Version 1.0 by Robert Fisher - November 27, 1981 Sample usage: U B4 selects drive B, user area 4. U 13 selects user area 13 of the current drive. U B selects drive B, current user area. Lower case is acceptable for the drive letter. The drive or the user area may be omitted. $= equ  X ext  S defs  W defw  B defb  % msg < Z defm  D adc  A add  & and  U call  M cp  D dec  Q di E ex  P ei N in  I inc  J jp  R jr  L ld  | or  O out  < pop  > push  T ret F(bc) G(de) H(hl) C sbc  S sub  V xor      STRIP.OBJ will allow you to make an ASM file from a PRN file in case you should lose your original ASM file. It will also allow you to name the ASM file to something else if you wish. Command syntax: STRIP ( or ) This program looks automatically for the PRN file and automatically creates the new file with the extension of ASM.  n of ASM. COM Fun game of guessing a number that the computer knows. This program will run only on a Z-80 system; STATWILD.ASM ; by Keith Petersen, W8SDZ ; (revised 1/16/81) ; ;This patch fixes STAT.COM so it will not accept wild-cards. ; ; CAUTION: THE PATCHES SHOWN HERE ARE VALID FOR ; CP/M 2.2 STAT.COM ONLY. ; BDOS EQU 05H FCB EQU 5CH CR EQU 0DH LF EQU 0AH ; ORG 0100H ; JMP PATCH ; ORG 1502H ;VERSION 2.2 STAT ; PATCH: LXI H,0 DAD SP ;GET OLD STACK SHLD STACK ;SAVE IT LXI SP,STACK ;SET NEW STACK ; ;First check to see if modem is active. ;If not, allow normaLF DB ' USE SD FOR MULTIPLE FILES',CR,LF,'$' ; ;Temporary storage area ; DS 64 ;ROOM FOR NEW STACK STACK DS 2 ;OLD STACK SAVED HERE ; END OOP JMP 433H ;GO BACK TO STAT ; ;Print error message, then return to CCP ; ERROR: LXI D,MSG ;POINT TO STRING MVI C,9 CALL BDOS LHLD STACK ;GET OLD STACK SPHL ;RESTORE IT RET ;RETURN TO CCP ; MSG: DB '++CAN''T USE WILD CARD OPTIONS',CR,0 WILDCARD UN-ERASE (CP/M VERSION $2.x) $1.4) $!4w_#~ ʸ A:4~~# ¼ > \ ?ʻ w# !ͼ ? !ͼ !)ͼ !ͼ :5͡ :6:6͡ :71 *Dd  :=X:\Q<=2\:]   >*/Ԡ2:\Oͷ|ʄ:0^#V"^#V#t}2!~2>0(*:Gk::Oͺ:O͖ͽɯ2!~l stat functions. ; LDA 3 ;GET IOBYTE ANI 3 ;ISOLATE CONSOLE BITS CPI 1 ;SEE IF CON:=CRT: JZ 433H ;YES, GO BACK TO STAT ; ;Check for wild cards LXI H,FCB+1 ;POINT TO FCB MVI B,11 ; LOOP: MOV A,M CPI '?' JZ ERROR INX H DCR B JNZ LOOP JMP 433H ;GO BACK TO STAT ; ;Print error message, then return to CCP ; ERROR: LXI D,MSG ;POINT TO STRING MVI C,9 CALL BDOS LHLD STACK ;GET OLD STACK SPHL ;RESTORE IT RET ;RETURN TO CCP ; MSG: DB '++CAN''T USE WILD CARD OPTIONS',CR,R6>2:<2 :C:Oͺ:O͖ͽ:=2:<2#] >?d# Y~#kw|g}o .*M^#V#t}2!~2>0(*: nOͺ:O͖      ERROR OCCURED DURING DISK WRITE - ABORT$ SPECIFIED AN ILLEGAL DISK DRIVE - ABORT$ RECOVERED - PLEASE DOUBLE CHECK BEFORE USING$ NO FILE NAME SPECIFIED - ABORT$ FILE NOT FOUND$   1 e:] 0:e 0!%] 0???????????2h2|\ ++ Not Found ++ä MICRO RESOURCES DIRECTORY "WASH UTILITY" Ver 1.3 Command Function ------- ---------------------------- V View file at Console (any key aborts) L Print file to List Device P Send file to Punch Device C Copy file to another Disk R Rename file ^VʗLʤPʩC>Sʵ e*> \ U Beginning of List *D  ">  < *>  "> Û *> *D › End of List !P "> Û*>     New Name ?   !! Fm#~ w! 6# 6 #!! N#  i&6   d.=w# d d.=*!  X X.Xw#B! 6#] !  G>w# l: 2  !  ! 6#‘  ++ Name Already Exists ++ *>  !   m ++ Not Found ++mce ++  =  Replace ?  Ym  t  ++ Destination Directory Full ++m*+*F   x  ++ No Memory Available for Copy Buffer ++mi`"J 2O !"L *F "H *H   *H "H *L #"L *J  >2O *F "H *L |z +"L *H "H    ++ Disk or Directory Full or error on Write ++m:O  m ++ Destination Close Error ++m New Drive ?  mA<2\> 2]2ez{}o|g~#D Delete file X Exit to CP/M B Backup one file in List S Restart on another Drive sp or cr Forward to next file in List H or anything else Display this help message !P "> O! :\:  "> \*> "D "F \ ʕ!P "@  "B *B *@  F  P *B  "B *D T*@  "@ "B *D T!P "> *>    "> :@2 X: XXXXXXXX.XXX :  m mBXʤRʧ*>     5 ++ Not Found ++m Deleted*>  "> *D f Q"D P m*> m List Emptyä >ë>ë>2N *>    ! 6#  ++ File Cannot Be Opened ++m2  m!~m_:N O #*>    ! 6#T2 !!   £ ++ Source File Cannot Be Opened ++m Destination Drive ?  A<2 G:  ++ Cannot Select Same Disk as Sour ~_#  `_ _D =D :D ;D D 7#F Nwy#P Full or error on Write ++m:O  m ++ Destination Close Error ++m New Drive ?  mA<2\> 2]2ez{}o|g~# ~_#  `_  m ++ Destination Close Error ++m New Drive ?  mA<2\> 2]2ez{}o|g~#   !9"H1H*"n""kPWHATSNEW 10/25/81 derived from D-27A.ASM --------> CTL-S pauses, CTL-C aborts :ʁ2\*m"L:o2N!]͞ADD  ͣ¾ͺͯ!m ͘>!]LOK  ͣ:l22\!]DEL  ͣͺͱ++NAME NOT IN TABLE++$!]0SET  ͣS!m͘>2R>2U:] 2S̬f:\t=_Å\<.=o&))))) ~2T ~w#®:R(:S!U~< # 6à :Tڃ ͘\2R2J2K2L2|\ͯD\i!z0\<|ͱ++DONE++$ͱ++WRITE ERROR++$ͱ++BAD CLOSE, WHATSNEW.COM CLOBBERED!!++$   *H:\<@fP: !LO#\2R2J2K2L2|HIHI)9p@# S WHATSNEWCOMLDIR11 OBJCDOSCPM LBRDU-V81 AQMOBSLIB RQLPIP COMPUTZCPR LBRSCRAMBLELBRSORTDIR OBJSQ OBJSIZE OBJSTRIP DOCSTRIP OBJLISTT LBRMBASIC COMVAX-VMNERA OBJPAGE COMLU300 DQCDASM LBRLU300 OQJARCHIVE AQMDISASM DOCFINDBAD OBJWC OBJXTYPE OBJZ80ASM LBRDOS OBJDISASM OBJPISTOL LBRAPPEND AQMASSIGN AQMFLOPCOPYLBRAUTOCPM AQMBACK2DDTAQMBANNER AQMBANZAI AQMBDLOC AQMRAMDISK LBRDUTIL LBRXLATE2 LBRMAC-LIB LBRLU DOCMEMMAP ASMMOVER ASMPAUSE ASMPIPIO ASMTPA3 ASMSMALL-C LBRLINKASM LBROKIDAT92LBRBEEP ASMBISHOW16AQMBLOCKREFAQMCATALOG AQMCATFILTRAQMCCPPATCHAQMCDEMO LBRREZ LBRCKSUM AQMCLS ASMCPMUTIL AQMCPU F-SSEDLBRGOCCP-1 LBRSECRTARYLBRSWEEP38 COMTYPE1 LBRUMPIRE LBRZCMD LBRFORTH OBJSD-77 LBRSMALLC LBRLISP-INTLBRCASM LBRFIND OBJLTYPE80 LBRCPMHDOS ABSELIZA OBJy +| !*S| | *S ~#fo| *S~#fo| ! *S~#MFILE-XT2AQMFILE14 AQMFILFND12AQMFIND AQMFIXALL AQMFMAP3 AQMFORMHAM1AQMFROMHARDAQMGETADR AQMGO AQMHAMLINK4AQMHELP ASMHELPCPM ASMI/OCAP11AQMLABLDISKAQMAUTOCPM LBRUN LBRLPR COMREAD24 COMHELP LBRARCHIVE LBRCHEK15 LBRCRCK44 LBRDI ------------------------------------------- WHATSNEW.DOC 05/10/82 T McCormick. Whatsnew is derived from D-27A directory program. When you execute whatsnew at the A> prompt, it reads the directory of the logged-in drive and compares each file name found to a list of filenames kept inside whatsnew.com, itself. It then displays the files added or removed since the date specified when the "set" option was last run. B>WHATSNEW SET 12/25/82 would cause the filenames from the>2JF>.fFd> fdƒ]~:JJ:SJP++NONE++ :R:S:f:\!U ~ʨ<>2KF>.fFd> fdt]otP -->New filesP -->Deleted files: P since >:f]:K:SP++NONE++ :Rʷ5:TBͯ ͘>Ã~f# F~f#~QP > O x̧ͧͱ ++ABORTED++ $~# x˜# x£!U~#<²+!U~7m ͣ ý!w#<!] >?w#]HATSNEWCOMS LBREDITM LBRXDIR COMBYIIK2/4OBJGENHEX OBJZESOURCELBRCPMGEN COMMBASIC HLPD LBRDYNATESTAQMHELP COMLCOPY OBJSD OBJSPIP OBJSD60 LBRDU LBRZPIP COMSQ/USQ DOCCRC OBJSORBAS01LBRSTRIP LBRT LBRSURVEY OBJWASH OBJNEWSWEEPLBRPASCAL LBRPOW2 LBRCAT LBRFAST2 LBRSTATWILDAQMTYPER OBJTED OQJU OBJDD COMDIRR OBJFIND COMBASIC-E LBRVLIST LBRWHATSNEWLBRRESOURCELBRUSQ1/119LBRLTYPE COMLU COMMEMRS OBJMFT OBJXCAT37 LBRLDIR COMU ASMCRCK-51 AQMLDIR MQGLOCATE AQMLPRINT AQMLRUN20 AQMMDIR21 AQMMENU-V2 AQMPIPPATCHAQMPRNTWB AQMRAMTEST AQMGRAPHICSLBRRECOVER AQMRPIP AQMSAP36 AQMSCRAMBL2AQMSD-48R AQMSUPERSUBAQMTOHARD AQMDIR AQMDISSAM LBREXTEND AQMEZCHECK CBLFF ASMFILE-XT2AQMFILE14 AQMFILFND12AQMFIND AQMFIXALL AQMFMAP3 AQMFORMHAM1AQMFROMHARDAQMGETADR AQMGO AQMHAMLINK4AQMHELP ASMHELPCPM ASMI/OCAP11AQMLABLDISKAQMAUTOCPM LBRUN LBRLPR COMREAD24 COMHELP LBRARCHIVE LBRCHEK15 LBRCRCK44 LBRDI B: directory (and the set date 12/25/82) to be stored within whatsnew.com. Another use is to run the set command on one disk, pip whatsnew.com to a 2nd disk, and run whatsnew (without the set option) on the 2nd disk. In this way you get a list of all files on each disk that are NOT on the other. Whatsnew is most commonly used on remote CP/M systems where callers can simply run it rather than paw through lots of directories looking for new stuff. It will NOT notice that you re   placed a specific filename with a later version under the same name. On the other hand, it does not require "maintenance" since it uses the current directory vs a directory snapshot from some day in the past. Whatsnew can be useful to note which diskettes have had additions or deletions when you are updating your catalog, or at other housekeeping times. ------------------------------------------------  when you are updating your catalog, or at other housekeeping times. ------1 !\h 2t2!""h<= :m!\ K!l 22!"!"<… * څÞa !g5›6Ð*}¶">aª< ?S ê~# **}|J!"*{z<*h6*"*"!"**}>*#"**}|ھ!"*{zҰ*¤*"v !"**#" PRN STRIP PROGRAM, VER 1.2 CONVERTS PRN TO ASM ; PIPPATCH.ASM mod B ; ; Notes on PIPPATCH mod A ; ; One problem which is often encountered with PIP.COM is that ; there is no convenient method to transfer files to and from ; several different diskettes without rebooting CP/M and rerunning ; PIP after each output disk change. This is especially a problem ; when some of your archive disks do not contain a system, and also ; when your system does not allow warmbooting from a single density ; disk. These patches to PIP.COM add a special com in this ; file to be your reset character. I chose "R". When the prompt ; returns, all disks have been restored to R/W status. ; ; Also, the opportunity was taken to make PIP give a signon ; message, to help weed out the old versions, especially v1.4 ; ; Additional notes on PIPPATCH mod B ; ; While I was at it, it seemed a good idea to be able to repeat ; the previous command without having to retype it. This feature ; takes advantage of the fact that CP/M doesn't bother to clear the ;FILE $ NO SOURCE FILE$ DISK FULL: DEST$ NO DIR SPACE: DEST$ CANNOT CLOSE DEST$CONVERSION COMPLETE$ PRN ASMJ!"*{z<*h6*"*"!"**}>*#"**}|ھ!"*{zҰ*¤*"v !"**#" PRN STRIP PROGRAM, VER 1.2 CONVERTS PRN TO ASM mand to allow ; the disk system to be reset, which allows the output diskettes to ; be changed and then restored to R/W status. ; ; The idea for these patches came from LIFELINES, October 1981. ; This coding of the idea, however, is my own and is placed in the ; PUBLIC DOMAIN for all to use as they desire. ; ; The useage is simple: When you have finished with an output ; disk, change it. Then, before doing anything else, let your ; first command be the single character which you specified console input buffer, but instead just overwrites a portion of ; it, based on what was typed. The command to repeat the last ; command is also specified at assembly time. I have chosen the ; "!" for this, for no particular reason. If you don't like it, ; change it! ; ; Patches courtesy of: ; Lewis Moseley, Jr. ; 2576 Glendale Ct. NE ; Conyers, GA 30208 ; Reciprocation encouraged. org 100H ;program start jmp signon org 130H ;custom I/O area signon: lda fcb+1 ;was a command giv   en on the command line? cpi ' ' jnz 04CEH ;skip new signon message if so lxi d,msg1 ;else give new signon message mvi c,9 call bdos ;write it to console jmp 04CEH ;join mainline code msg1: db 0dh,0ah db 'PIP v2.2 mod B',0dh,0ah,'$' getcon: lxi h,buff mvi m,80H ;specify max length of reply xchg ;buffer address to DE mvi c,10 ;bdos command to read console buffer call bdos ;ask bdos to do it lda buff+1 ;length of reply cpi 1 ;just 1 caharacter entered? jnz gobak ;let  bdos ;write it to console lxi h,buff+1 ;get length byte mov c,m ;to reg BC mvi b,0 inx h ;get buffer start address to HL dad b ;point to first free position in buffer mvi m,'$' ;flag end of line with a "$" lxi d,buff+2 mvi c,9 call bdos ;echo line mvi c,13 ;bdos command to RESET call bdos ret ;let PIP process the previous command again msg2: db 0dh,0ah db 'Repeating: $' getc1: ani 5FH ;convert lc to UC (note: don't use for numbers) cpi rstchr ;is it the user-speciftash dw 0 ;no initial command org 96FH ;patch PIP to vector to this routine jmp getcon bdos equ 5 ;cp/m entry point fcb equ 05CH ;default fcb crlf equ 082EH ;PIP's internal CR-LF routine buff equ 1ECBH ;PIP's input buffer rstchr equ 'R' ;put your choice for the reset char here rptchr equ '!' ;same here for the repeat command char e buffer for later ; gobak: lhld buff+1 ;save length and first char typed shld stash ret ;and back to PIP to process s; Patching CP/M-80's PIP for Multiple Disk File Transfers ; ; By: Kelly Smith ; ; ; "We shall not cease from exploration, and the end of all our ; exploring will be to arrive where we started and know the place ; for the first time." - T.S. Eliot, Little Gidding ; ; Digital Researchs's PIP (Peripheral Interchange Program) is the ; CP/M transient command used to move a single file or multiple ; files from one disk to another, or to othePIP process the command if not lda buff+2 ;first (and only) char typed cpi rptchr ;was it the repeat command? jnz getc1 ;jump if not ; ; ; REPEAT command - Restore first 4 chars of the console buffer to ; their former contents, echo the old command to ; console, RESET disk system, and let PIP reprocess it ; lhld stash ;restore length and first char typed shld buff+1 lxi d,msg3 ;'Disk system reset' msg mvi c,9 call bdos lxi d,msg2 ;'Repeating...' message mvi c,9 callied RESET command? jnz gobak ;let PIP process if not ; ; RESET command - make all diskettes R/W ; lxi d,msg3 ;'Disk system reset' msg mvi c,9 call bdos mvi c,13 ;bdos command to RESET call bdos call crlf pop h ;clear stack jmp 53CH ;rejoin command loop within PIP msg3: db 0DH,0AH db 'All disks made R/W.$' ; ; not a special command, so stash the console buffer for later ; gobak: lhld buff+1 ;save length and first char typed shld stash ret ;and back to PIP to process sr peripheral devices. ; Unfortunately PIP will not allow the transfer of files to ; multiple disks...you must always exit PIP and re-log any new ; disks or warm boot (by entering your keyboard Control-C) the CP/M ; system, then invoke PIP again to proceed...agonizing, if you want ; to do multiple disk copies of specific files. ; ; How would you like to be able to transfer files to multiple ; disks without exiting PIP, as well as have it repeat the last ; operation t   hat you entered at PIP's command level with ONE ; keystroke? Its EASY Edit and assemble the following 'patch', ; then merge it into your existing CP/M-80 (Version 2.2) 'PIP.COM' ; utility as follows: ; ; A>ddt pip.com <-- invoke DDT to load memory with 'PIP.COM' ; DDT VERS 2.2 <-- DDT telling us that... ; NEXT PC ; 1E00 0100 <-- 'PIP.COM' uses 29 pages of memory ; -ipatch.hex <-- Input the 'patch' file ; -r <-- Read it in to memory (overlaying partb <-- change any (or all) disks here if you like, ; and start PIP'n to your hearts content... ; COPYING - ; MACRO.LIB ; COPYRGHT.LIB ; *q <-- change disks, and then a little "quickie" ; with Q)uick Repeat... ; ; Repeating: b:=a:*.lib <-- PIP remembers us...amazing ; ; COPYING - ; MACRO.LIB ; COPYRGHT.LIB ; *q <-- change disks again for two "quickies" ; in a row (and no Vitamin-E required) ; Repeating:k equ 13 ; reset disk system function ; start$pip equ 04ceh ; normal start of pip con$buff equ 1ecbh ; pip's internal console buffer pip$cr$lf equ 082eh ; pip's internal cr/lf output routine pip$prompt equ 053ch ; pip's command parser entry address pip$patch equ 096fh ; pip gets patched at this address ; lf equ 0ah ; line feed character cr equ 0dh ; carriage return character ; org 100h ; jmp begin ; jump over INP:/OUT: vectors and EOF ; org 10ah ; begin: lda fcb+1 ; filename specjust one? jnz save$char$cnt ; if not, save character count and return lda con$buff+2 ; get single character command ani 05fh ; force to uppercase character cpi 'Q' ; repeat pip function last specified? jnz reset$dsk$sys ; if not, check for reset disk system lhld char$cnt ; get character count shld con$buff+1 ; stuff back to console buffer lxi d,msg3 ; tell'em repeating last process call prnt$messg ; print message lxi h,con$buff+1 ; point to last command entry in console buffer mov cys: ; cpi 'R' ; reset disk system? jnz save$char$cnt ; if not, restore character count and return lxi d,msg2 ; tell'em all disk set R/W call prnt$messg ; print message mvi c,rsetdsk ; reset disk system function call bdos ; let CP/M do the work call pip$cr$lf ; do carriage return/line feed pop h ; clean the stack for pip restart jmp pip$prompt ; do pip '*' prompt and wait for command ; save$char$cnt: ; lhld con$buff+1 ; get character count + character shld char$cnt ; save characs of PIP) ; NEXT PC ; 1E00 0000 ; -^C <-- Control-C to exit DDT ; ; A>save 29 rpip.com <-- save 29 pages of memory as 'RPIP.COM' ; ; So, for a little "demo" of what you can do and expect from adding ; this 'patch', lets give it a whirl: ; ; A>rpip <-- invoke our new 'Repeating PIP'... ; ; PIP 1.5 with (R)eset Disks and (Q)uick Repeat ; *r <-- lets try 'R' for R)eset of the disk system ; Resetting all disks to R/W <-- keeping user informed... ; *b:=a:*.li b:=a:*.lib ; ; COPYING - ; MACRO.LIB ; COPYRGHT.LIB ; * <-- PIP waiting patiently for something else to do... ; ; Alright, now that I have whetted your appetite to incorporate ; this into your PIP,...here's the code to do it ; ; ; ; PIP Patch to add '(R)eset Disks' and '(Q)uick Repeat' function ; bdos equ 05h ; bdos entry address fcb equ 5ch ; default file control block address ; pmessg equ 9 ; print message function rdcbuf equ 10 ; read console buffer function rsetdsified? cpi ' ' ; if space character, no file jnz start$pip ; let pip do it's thing if file specified lxi d,msg1 ; and sign in please... call prnt$messg ; print message jmp start$pip ; and off to pip ; added: lxi h,con$buff ; point to pip's console buffer mvi m,128 ; set-up for 128 character command string xchg ; pointer swapped to [DE] for CP/M mvi c,rdcbuf ; read console buffer function call bdos ; let CP/M do the work lda con$buff+1 ; check how many characters typed cpi 1 ; ,m ; get command length to calculate offset mvi b,0 ; clean high byte bias inx h ; bump to start of command string address dad b ; add bias to locate end of string mvi m,'$' ; tag end of command string for message lxi d,con$buff+2 ; point to command string for message output call prnt$messg ; print message mvi c,rsetdsk ; reset disk system function call bdos ; let CP/M do the work ret ; "Vulcan Princes...How I love You..." ; - Stanley Clark, 'Return to Forever' ; reset$dsk$ster count ret ; "Welcome Back My Friends, ; To The Show That NEVER Ends..." ; - Emerson, Lake & Palmer, Brain Salad Surgery ; prnt$messg: ; mvi c,pmessg ; print message function call bdos ; let CP/M do the work ret ; "We May Never Pass This Way Again..." ; - Seals and Crofts, Diamond Girl - ; msg1: db cr,lf,'PIP 1.5 with (R)eset Disks and (Q)uick Repeat',cr,lf,'$' ; msg2: db cr,lf,'Resetting all disks to R/W$' ; msg3: db cr,lf,'Repeating: $' ; char$cnt dw 0 ;    console buffer character count ; org pip$patch ; patch to get to added code goes here ; jmp added ; check for reset or repeat command ; ; ; end Never Pass This Way Again..." ; - Seals and Crofts, Diamond Girl - ; msg1: db cr,lf,'PIP 1.5 with (R)eset Disks and (Q)uick Repeat',cr,lf,'$' ; msg2: db cr,lf,'Resetting all disks to R/W$' ; msg3: db cr,lf,'Repeating: $' ; char$cnt dw 0 ; 1 |2O:\=Ot:Y|^#V"! ~#fo^#V"}!^#V"!^#V"*"{22!"b*DM!t$t*":<2!}ڧ*{#"{2!4~=!o&.22*"{!"b*DM!t't*":<2!} *{#"{2!4~=!DMt>2!~G ~V~V:! 6# O:!<(::{!ou$NtO*-*Mv     :!:! ~G# >2:<2ͯ:<2!:<2!Ⱦ;C Copyright (c) 1983 by Frank Gaude' All Rights Reserved"B1%:2U͖ 23:\f=2-_/:] „:e „!] 2h2|\<4F ++ Unable to find file(s) ++$F ++ Drive/User Entry Error ++1%ÎF New drive/user: $:e23 > 2]2eF f!͆  r :ʳ2e:0z:0m:0k6&2ez>G:0x2e:2!} o>$~0h h2#~$h#~$h#:w+6$+6$+6$:!<0*?{#"{2!4~=!DMt>2!~G ~V~V:! 6# O:!<(::{!ou$NtO*-*Mv     :!:! ~G# >2:<2ͯ:<2!:<2!ȾC - Copy to another drive/user D - Delete file | F - Forward to next file L - Log-in new drive/user | M - Mass copy of tagged files P - Print file to List | R - Rename file T - Tag file for mass copy | U - Untag file from mass copy V - View file on Console | X - Exit to CP/M !"c=ƀo&:\w*c 6 #"c\<:*c"a"+  !"] "_*_*] ›# ҭNwy#¢*_ "_*a …*] "]"_*a …͑ !"cF *c~@U :3     >1U 0U F : #~U #>.U ~U #'~2=#"cF : d BCb D[Fʳ ʳ ʳLM0 P`RDTʛUʧVX$͖/*c"c*c6*ó*c6 ó*c*a F List End!"c*c  F List Beginning*a "cF <- *c"c:U_ F *c4 F New filename:  r !D6# ͆ !N#͎ i&6 ͚  .ʹw#“͚  .©!M͚  .w#¾!P 5!E G>w# :42f !Egmore...] d F * >2W2! "c>*#"cb *c*a W *c: 2/2!"/ !r 2 !g5 f<° F ++ Unable to Open Source ++ó: F To drive/user: $:\G:f :eG:3 F ++ Drives or User Areas must be different ++Î :\24:e:u 4<} F ---> Copy exists, erase? (Y/N): d Yu :3ó44<² F ++ Destination Directory Full ++ó*+*+ x F ++ No Memory for Copy Buffer ++ói`"erified :³>2D F ++ Error on CRC compare ++ó~U #~G _a{_!Fx#~i w{ 6 #†   Î  [ * , : ; < = > ? 7*cf ~# 6#  :X_z{_   | {0U <2\@2##~2(#~2'##^#V"%*%#lW+}}zgci`:(ʍ)=ˆ F k bytes free on drive : ??????????? ; ; extend.asm: v1.0 ; usage: APPEND ; appends to end of file ; ; Intended mainly to illustrate a fast file-append ; algorythm, but may be useful as a quick-update ; notations file handler ; ; 09/13/81 Ron Fowler, Westland MI ; ; CHARACTER EQUATES ; CR EQU 13 ;CARRIAGE RETURN LF EQU 10 ;LINEFEED EOF EQU 1AH ;END OF FILE ; ; CPM EQUATES ; CPBASE EQU 0 ;SET TO 4200H FOR ALT CPM BDOS EQU CPBASE+5 ;BDOS ENTRY POINT PRINTF EQU 9 ;PRINT STRING FUNCTIONAVE THE STACK DAD SP SHLD STACK LXI SP,STACK MVI C,SDMAF ;SET DMA TO DBUF LXI D,DBUF CALL BDOS CALL MOVSTR ;MOVE THE STRING CALL ADVANC ;OPEN AND ADVANCE OUT FILE CALL WRLINE ;WRITE LINE TO OUTPUT FILE CALL CLOSE ;CLOSE OUTPUT FILE CALL ERRXIT ;EXIT WITH MESSAGE DB CR,LF DB '++ Done ++' DB CR,LF,'$' ERRXIT: POP D MVI C,PRINTF ;PRINT MESSAGE CALL BDOS EXIT: LHLD STACK ;RESTORE STACKPOINTER SPHL RET ; ; MOVE STRING INTO BUFFER ; MOVSTR: LXI H,DBUF+1 ;POINT TO START OF !r f<<F ++ File already exists ++  Î*c!E 4<ŽÆ F Ok? (Y/N): d YzÎf<£F ++ File Not Found ++óF Deleted.*c"c*a  ý"a ³*c ³F ++ List Empty ++$F cancels, turns up one line, other keys page screen. >2W2>f2>2. !r f<§F ++ Unable to Open File ++ó2f³!~ʳ_:.O: #¼ë{ :W<2Wد2WF [[!5W  :/> U F ---> Copying file . 2V:3!"Y*+")*)f¼ *)~ͼ #• *)")*Y#"Y*[ { >2V:e*+")*Y| +"Y*)")4 F ++ Copy Disk Full ++ó:Vi 4g>!o  r$s%# – */O!/ ~W$^"/:3*/"*1 " F ---> Copy CRC v OPENF EQU 15 ;OPEN FILE FUNCTION CLOSEF EQU 16 ;CLOSE FILE FUNCTION MAKEF EQU 22 ;MAKE NEW FILE FUNCTION READF EQU 20 ;READ RECORD WRITEF EQU 21 ;WRITE RECORD SDMAF EQU 26 ;SET DMA FUNCTION ; TPA EQU CPBASE+100H ;TRANSIENT PROGRAM AREA DFCB EQU CPBASE+5CH ;DEFAULT FILE CONTROL BLOCK DBUF EQU CPBASE+80H ;DEFAULT DISK BUFFER ; EX EQU 12 ;FCB EXTENT OFFSET FRC EQU 15 ;RECORD COUNT FCB OFFSET NR EQU 32 ;NEXT RECORD OFFSET ; ; PROGRAM CODE BEGINS HERE ; ORG TPA ; BASE: LXI H,0 ;S STRING CALL SCANB ;SKIP LEADING BLANKS CALL SCANC ;SKIP FILENAME CALL SCANB ;SKIP BLANKS AFTER FILENAME ; ; NOW AT STRING, TRANSFER TO BUFFER ; XCHG ;CMD LINE PTR IN DE LXI H,LINBUF ;POINT TO BUFFER MVLN: MVI M,EOF ;FIRST MARK POSSIBLE END LDAX D ;PICK UP BYTE OF LINE INX D ORA A ;TERMINATOR? RZ MOV M,A ;NO, MOVE IT INX H JMP MVLN ; ; SKIP BLANKS ; SCANB: MOV A,M ;GET CHAR ORA A ;TERMINATOR? RZ CPI ' ' ;BLANK? RNZ INX H JMP SCANB ;NO,SCAN MORE ; ; SKIP    TO FIRST BLANK ; SCANC: MOV A,M ;GET CHAR ORA A ;TERMINATOR? RZ CPI ' ' ;GOT BLANK? RZ INX H JMP SCANC ;NO, SCAN MORE ; ; OPEN INPUT FILE AND ADVANCE TO END ; ADVANC: LXI D,DFCB MVI C,OPENF ;OPEN IT CALL BDOS INR A ;CHECK RESULT JNZ ADV1 ;EXISTS, GO SCAN IT MVI C,MAKEF ;DOESN'T EXIST, CREATE IT LXI D,DFCB CALL BDOS INR A ;TEST RESULT JNZ MAKEOK CALL ERRXIT ;BAD MAKE DB CR,LF DB '++ Can''t create file ++' DB CR,LF,'$' MAKEOK: MVI A,80H ;NEW FILE BUF POINTER SBACKEX ;AN EXTENT WITH 0 RECS? STA DFCB+NR ;SET RECORD TO READ MVI C,READF ;NOW READ IT LXI D,DFCB CALL BDOS ;CAN'T GET ERROR HERE LDA DFCB+NR ;SEE IF NEW EXTENT ORA A JNZ FIXRC ;NO, GO RESET REC CNT LXI H,DFCB+EX ;SIGH...HAVE TO REOPEN PREV DCR M LXI D,DFCB MVI C,OPENF CALL BDOS ;CAN'T GET ERROR HERE LDA DFCB+FRC FIXRC: DCR A ;RESET NEXT REC STA DFCB+NR ; ; NOW SCAN SECTOR IN DBUF FOR EOF MARK ; LXI H,DBUF MVI B,128 ;SCAN LIMIT EOFSC: MOV A,M ;PICK UP A CHAR CPI EOF LE ; WRBYTE: PUSH PSW ;SAVE OUTPUT BYTE LDA BUFPTR ;GET BUFFER POINTER ORA A ;CHECK FOR WRAP CZ WRSEC ;WRAPPED, WRITE RECORD LXI H,DBUF ;GET ADDRESS OF DISK BUFFER MOV L,A ;OFFSET TO POINTER INR A ;BUMP POINTER STA BUFPTR POP PSW ;RETRIEVE OUTPUT BYTE MOV M,A ;STORE IT RET ; ; WRITE A DISK SECTOR ; WRSEC: MVI C,WRITEF ;BDOS WRITE SEC FUNCTION LXI D,DFCB CALL BDOS ORA A ;TEST RESULT MVI A,80H ;(LOAD NEW BUF PTR) RZ CALL ERRXIT ;PRINT DIAGNOSTIC AND EXIT DB CR,LF D ; LINBUF: DS 130 ;LINE BUFFER BUFPTR: DB 80H ;DISK BUFFER POINTER DS 128 ;STACK AREA STACK: DW 0 ;STACKPOINTER SAVE ; END BASE : DS 130 ;LINE BUFFER BUFPTR: DB 80H ;DISK BUFFER POINTER DS 128 ;STACK AREA STACK: DW 0 ;STACKPOINTER SAVE ; TEF ;WRITE THE LAST SECTOR LXI D,DFCB CALL BDOS MVI C,CLOSEF LXI D,DFCB ;DONE, CLOSE OUTPUT FILE CALL BDOS INR A ;CHECK RESULT RNZ CALL ERRXIT ;PRINT DIAGNOSTIC DB CR,LF DB '++ Can''t close output file ++' DB CR,LF,'$' ; ; DATA AREA; ; FILE-XT2.ASM Version 1.1 ; ; as of ; ; September 18, 1980 ; ; ; Renamed from filename FILE-EXT.ASM, to indicate CP/M Version ; 2.X only compatibility (display format) only. ; ; Added: User number display, "proprietary software" display ; and removed "ILLCHK" for non-ASCII characters which ; then requested deletion of the questionable file. ; ; Kelly Smith ; ; ; OrTA BUFPTR RET ADV1: LDA DFCB+FRC ;GET RECORD COUNT CPI 80H ;FULL EXTENT? JNZ WIND LXI H,DFCB+EX ;YES, TRY NEXT INR M LXI D,DFCB ;OPEN NEW EXTENT MVI C,OPENF CALL BDOS INR A ;GOOD OPEN? JNZ ADV1 ;YES, KEEP SCANNING BACKEX: LXI H,DFCB+EX ;NO, RE-OPEN PREV DCR M JP BACKOK ;TEST CASE OF EMPTY FILE INR M ;GET BACK TO EXTENT 0 JMP MAKEOK ;AND PRETEND WE MADE IT BACKOK: MVI C,OPENF LXI D,DFCB CALL BDOS ;CAN'T GET AN ERROR HERE LDA DFCB+FRC WIND: DCR A ;MAKE ZERO RELATIVE JM  JZ GOTEOF INX H ;NOT YET DCR B JNZ EOFSC ;CONTINUE SCAN CALL ERRXIT ;??? NO EOF IN LAST SECTOR DB CR,LF DB '++ No EOF in last sector ++' DB CR,LF,'$' GOTEOF: MOV A,L ;USE LO BYTE FOR BUF PTR STA BUFPTR RET ; ; WRITE LINE TO OUTPUT FILE ; WRLINE: LXI H,LINBUF WRLP: MOV A,M CPI EOF ;LINE END? JZ WREND PUSH H ;SAVE LINE POINTER CALL WRBYTE ;WRITE IT POP H INX H JMP WRLP WREND: MVI A,CR ;WRITE TERMINATING CR/LF CALL WRBYTE MVI A,LF ; ; WRITE A BYTE TO THE OUTPUT FIB '++ Disk full ++' DB CR,LF,'$' ; ; PAD OUT THE EXISTING BUFFER WITH EOF'S, THEN CLOSE ; CLOSE: MVI A,EOF ;WRITE AN EOF CALL WRBYTE LDA BUFPTR ;CHECK FOR SECTOR PAD ORA A ;SPILLED TO NEXT SECTOR? JNZ CLOSE ;NOT, THEN KEEP PADDING MVI C,WRITEF ;WRITE THE LAST SECTOR LXI D,DFCB CALL BDOS MVI C,CLOSEF LXI D,DFCB ;DONE, CLOSE OUTPUT FILE CALL BDOS INR A ;CHECK RESULT RNZ CALL ERRXIT ;PRINT DIAGNOSTIC DB CR,LF DB '++ Can''t close output file ++' DB CR,LF,'$' ; ; DATA AREAiginally named FILES.ASM, and from a disassembly by ; "J.A.P" of January 23,1980...FILE-XT2.ASM will display the ; selected disk's directory entries in the form: ; ; User Pro Filename.Typ R/OSysRes exs1s2rc <---------Group---------> ; ================================================================== ; ; Where: ; ; "User" is the User assignment for the file. ; "Pro" is the "proprietary software" control bit. ; "Filename" is the ASCII file name. ; "Typ" is the ASCII file type. ; "R/O"    is the "read only" control bit ; "Sys" is the "system directory" control bit ; "Res" is the "reserved" (MP/M Ver.1.0) control bit ; "ex" is the "file extension" byte ; "s1" is a CP/M "internal function" byte. ; "s2" is a CP/M "internal function" byte ; "rc" is the "record count" byte. ; "Group" is the "allocation vector table" for the file. ; ; The "hack-job" I did on this one was less than ideal, but ; none the less, it get's the job done...the display format is ; now alot cleaner, and ; Kelly Smith, CP/M-NET (tm) ; 805-527-9321 (Modem, 300 Baud) ; 805-527-0518 (Verbal) ; ORG 0100H BDOS EQU 05H TBUFF EQU 80H ; CR EQU 0DH ;ASCII CARRIAGE RETURN LF EQU 0AH ;ASCII LINE FEED ; ; FILES: ; LXI H,0 ; DAD SP ; SHLD OLDSTK ; LXI SP,NEWSTK ; MVI C,12 ;GET CP/M VERSION NUMBER CALL BDOS CPI 20H ;CP/M VERSION 2.0 OR BETTER? JNC BEGIN ;IF VERSION O.K., PRESS ON LXI D,BADVERESULT: ; DB 0 ;STORAGE FOR RESULT OF BDOS CALL ; ; FIND NEXT OCCURRENCE OF FILE ; NEXTFILE: ; PUSH B PUSH D PUSH H MVI C,12H LXI D,AFN ; CALL BDOS ; STA RESULT ; POP H POP D POP B RET ; ; GET INPUT FROM CONSOLE ; CONIN: ; PUSH B PUSH D PUSH H MVI C,1 CALL BDOS ; POP H POP D POP B RET ; ; CONVERT A BYTE IN (A) TO TWO PRINTED CHARACTERS ; HEXASC: ; CPI 0AH JC HEXA2 ; ADI '7' ; CALL TYPE ; RET HEXA2: ; ADI '0' ; CALL TYPE ; RET  IN IT. ; WORKLOOP: ; LDA RESULT ;RESULT HOLDS POSITION OF- MOV B,A ; -THE DIRECTORY ENTRY IN THE DIR. DMA ANI 3 RAL RAL RAL RAL RAL ANI 0E0H MOV E,A MVI D,0 LXI H,TBUFF ; DAD D ;HL NOW POINTS AT THE FILE INFO MOV A,M CPI 0E5H ;KILLED FILE? RZ ;YES CALL SPACE ;SPACE OVER FOR NEATNESS MOV A,M CALL HEXCON ;PRINT USER NUMBER CALL SPACE CALL SPACE CALL SPACE PUSH H PUSH H INX H ;POINT TO FIRST CHARACTER IN FILE NAME MOV A,M ;ALLOW HIGH BIT SET FOR "PROPRI/O, AND RESERVED MVI A,'1' JC WORK03B MVI A,'0' WORK03B:CALL TYPE CALL SPACE DCR B INX H JNZ WORK03A MVI B,20 WORK04: MOV A,B ANI 3 CZ SPACE ; MOV A,M CALL HEXCON ; INX H DCR B JNZ WORK04 ; CALL CRLF ; POP H RET ; BADVER: DB 'Sorry, CP/M Version 2.X required$' MSG: DB 'User Pro Filename.Typ R/OSysRes exs1s2rc' DB ' <--------------Group-------------->' DB CR,LF DB '=========================================' DB '====================================' DB CR, it does'nt "warm boot" as the ; FILES.ASM version did... ; ; The program will display the disk directory of the logged ; on disk, including all the Hexadecimal information on the ; groups. ; ; On the subject of "hack-job's" of software, read an ; interesting article in Psychology Today magazine, "The ; Hacker Papers; Computer Addiction: Reflection on a New ; Obsession"...August 1980 issue, pages 62-69. ; ; Best regards, ;R;OOPS...BAD VERSION FOR THIS FILE CALL PRINT JMP QUIT ;QUIT ; ; ; SYSTEM SUBROUTINES ; ; PRINT STRING FROM D&E REGS. ; PRINT: MVI C,9 CALL BDOS RET ; ; TYPE A CHAR FROM (A) ; TYPE: ; PUSH B PUSH D PUSH H MVI C,2 MOV E,A CALL BDOS ; POP H POP D POP B RET ; ; SEARCH FOR A FILE ; SEARCH: ; PUSH B PUSH D PUSH H MVI C,11H LXI D,AFN ; CALL BDOS ; STA RESULT ; POP H POP D POP B RET ; ; AMBIGUOUS FILENAME.TYP ; AFN: ; DB '?????????????' HEXCON: ; PUSH PSW RAR RAR RAR RAR ANI 0FH CALL HEXASC ; POP PSW ANI 0FH CALL HEXASC ; RET ; ; NEWLINE ; CRLF: ; MVI A,CR CALL TYPE ; MVI A,LF CALL TYPE ; RET ; ; PRINT A SPACE ; SPACE: ; MVI A,' ' ; CALL TYPE ; RET ; ; MAIN WORK LOOP ; ; THIS ROUTINE FINDS THE POSITION OF THE FILE ; INFORMATION IN THE DIRECTORY DMA, PRINTS THE ; DATA IF IT IS A CURRENT FILE, AND PROMPTS THE ; OPERATOR FOR INSTRUCTIONS IF THE FILENAME HAS ; ILLEGAL (NON-ASCII) DATAETARY SOFTWARE" RLC ;TEST "PROPRIETARY SOFTWARE" BIT MVI A,'1' JC WORK01 MVI A,'0' WORK01: CALL TYPE CALL SPACE CALL SPACE CALL SPACE MVI B,8 WORK02: MOV A,M ;PRINT FILE NAME CALL TYPE ; DCR B INX H JNZ WORK02 ; MVI B,3 MVI A,'.' CALL TYPE ;PRINT NEXT THREE CHARACTERS AS ASCII WORK03: MOV A,M CALL TYPE ; DCR B INX H JNZ WORK03 ; CALL TYPE CALL SPACE MVI B,3 POP H ;NOW DISPLAY ATTRIBUTES LXI D,9 DAD D WORK03A:CALL SPACE MOV A,M RLC ;TEST $SYS AND $RLF,'$' ; ; ; ; ERROR MESSAGES ; ERROR1: LXI D,ERMSG1;SAY NO GO, AND BAIL OUT CALL PRINT JMP QUIT ; ERMSG1: DB CR,LF,'Disk select should be " N:"$' ; ERROR2: LXI D,ERMSG2;SAY NO GO, AND BAIL OUT CALL PRINT JMP QUIT ERMSG2: DB CR,LF,'Bad delimeter, should be ":"$' ; ERROR3: LXI D,ERMSG3;SAY NO GO, AND BAIL OUT CALL PRINT JMP QUIT ERMSG3: DB CR,LF,'No drive specified$' ; ERROR4: LXI D,ERMSG4;SAY NO GO, AND BAIL OUT CALL PRINT JMP QUIT ERMSG4: DB CR,LF,'Only drives    A to D allowed$' ; ; PROGRAM BEGINS HERE ; BEGIN: ; ; CHECK FOR DRIVE SPECIFICATION ; LDA TBUFF ;GET LENGTH OF COMMAND PARAMETERS CPI 2 ; IF <2, NO PARAMETERS JC MAIN01 ; MUST BE PRESENT LOGGED-IN DRIVE JZ ERROR1 ;EXACTLY 2, IS ERROR LHLD TBUFF+2 ;AT LEAST 3 THEN... MOV A,H ;NEXT CHARACTER SHOULD BE ":" CPI ':' JNZ ERROR2 ;ONLY ALLOW DRIVE SET MOV A,L ;NEXT CHARACTER SHOULD BE DRIVE CPI 'A' ;AT A MINIMUM, "A" JC ERROR3 CPI 'E' ;AT A MAXIMUM "D" JNC ERROR4 ANI 7 ;STRIPD OLDSTK ; SPHL RET ; ; ; SOME STORAGE LOCATIONS ; OLDSTK: DS 2 ;STORAGE FOR "OLD" STACK POINTER DS 32 NEWSTK EQU $ ;STORAGE FOR "NEW" STACK ; ; END LL NEXTFILE ; JMP MAIN02 ; ;MAIN04: ; ; LHLD DELPTR ; ; LXI D,DELFIL ; MOV A,L ; CMP E ; JNZ MAIN06 ; ; MOV A,H ; CMP D ; JZ QUIT ; ;MAIN06: ; ; LXI D,-10H ; DAD D ; SHLD DELPTR ; ; XCHG ; CALL DELETE ; ; JMP MAIN04 ; QUIT: ; LHL ; FILE.ASM ; ; v14 - 01 JUNE 83 - IRV HOFF ; ; ORIGINALLY WRITTEN BY R. RODMAN. RENAMED TO 'FILEFIND' BY ANOTHER ; PERSON IN APRIL 1981. NOW RESTORED TO ORIGINAL INTENDED NAME. ; ; THIS PROGRAM WILL SEARCH ALL USER AREAS OF ALL DRIVES (CAN BE LIMITED ; BY CHANGING THE 'MAXUSR' EQUATE) FOR ANY FILES MATCHING THE REQUEST ON ; THE COMMAND LINE. IT THEN DISPLAYS THOSE FILES. ALLOWABLE USER AREAS ; FOR CP/M ARE 0-15. ; ; ; EXAMPLE: FILE *.COM LISTS ALL .COM FILES ON ALL DRIVES AND ALL AREAS NOT WORK. IN THAT CASE, SET 'DRVTYPE' TO ; FALSE AND 'MAXDRV' TO THE NUMBER OF DRIVES YOU HAVE. ; ; ; PLEASE RETURN ANY UPDATES TO TECHNICAL CBBS DEARBORN MI (313) 846-6127 ; SO THE FILE WILL BE AVAILABLE TO ALL. ; ; ;======================================================================= ; ; ; 06/01/83 ADDED "searching..." TO SHOW THE REASON FOR NO ACTIVITY ON ; LONGER SEARCHES. REVISED THE ONE OF THE EXIT ROUTINES. ; OTHER MINOR CHANGES. -Irv Hoff ; ; 02/13/83 NOW PRINT REMOVED UNNECESSARY CODE. THANKS TO TOM ; AND SHAWN FOR ADDING SOME MORE GOODIES. ; - Dave Hardy ; ; 07/31/81 MODIFIED 'AVAIL' ROUTINE TO ABORT ONLY ON CTL-C FROM THE ; CONSOLE. CLEANED UP THE FILE, RESTORED ORIGINAL AUTHOR'S ; NAME TO THE HEADING. ADDED TUTORIAL TO BE PRINTED IF FILE- ; NAME (FCB) FIELD (FN.FT TAIL OF THE COMMAND LINE) IS BLANK ; (OMITTED BY THE INEXPERIENCED USER). SUBSTITUTED IN-LINE ; PRINT ROUTINE WHERE APPROPRIATE FOR ALL PRINTED MESSAGES. ; BITS, FOR 0 TO 3 DCR A ;BACK OFF FOR 0 TO 3 MOV E,A ;MAKE DISK NUMBER MVI D,0 MVI C,14 ;BDOS SELECT DISK FUNCTION CALL BDOS MAIN01: LXI D,MSG CALL PRINT CALL SEARCH ; MAIN02: ; LDA RESULT ; CPI 0FFH JZ QUIT CALL WORKLOOP ; CALL NEXTFILE ; JMP MAIN02 ; ;MAIN04: ; ; LHLD DELPTR ; ; LXI D,DELFIL ; MOV A,L ; CMP E ; JNZ MAIN06 ; ; MOV A,H ; CMP D ; JZ QUIT ; ;MAIN06: ; ; LXI D,-10H ; DAD D ; SHLD DELPTR ; ; XCHG ; CALL DELETE ; ; JMP MAIN04 ; QUIT: ; LHL ; ; ; THIS PROGRAM MAKES A DIRECT CALL TO THE 'SELDSK' ROUTINE OF THE BIOS ; TO DETERMINE A DRIVE'S EXISTENCE WITHOUT CAUSING A BDOS ERROR. ; ; NOTE: THIS PROGRAM ASSUMES THAT ANY BIOS 'ILLEGAL DRIVE SELECT' TRAPS ; WILL CAUSE THE SYSTEM TO EXECUTE A WARM-BOOT BY JUMPING TO AD- ; DRESS 0. THIS OCCURS ON THE FIRST NON-EXISTANT DRIVE IT TRIES ; TO ACESS WHILE ATTEMPTING TO CHECK 0-15 DRIVES. IF A SELECT ; ERROR BYPASSES THE WARM-BOOT JUMP AT ADDRESS 0, THEN THE TRAP ; IN THIS PROGRAM WILL S A NORMAL DISPLAY FOR DRIVE/USER AREA WHILE KEEP- ; ING NORMAL COLUMN WIDTH FOR JUSTIFICATION. SEVERAL OTHER ; MINOR CHANGES. ALWAYS STARTS AT FIRST DISK, USER 0, REGARD- ; LESS OF THE CURRENT DISK OR USER NUMBER. IT THEN RETURNS TO ; THE PRESENT DRIVE AND USER AREA. ; - Irv Hoff ; ; 02/02/82 ENABLED PROGRAM TO LOOK AT A SPECIFIC NUMBER OF DRIVES IN ; THE EVENT THE BIOS 'ILLEGAL DRIVE SELECT' IS NOT INCLUDED. ; - Larry Clive ; ; 08/02/81 CLEANED UP FILE AND PRINTS MESSAGE ON EXIT IF NO FILES WERE FOUND (MATCHED). ; - Thomas V. Churbuck ; ; 07/30/81 MODIFIED 'AVAIL' ROUTINE TO ABORT PROGRAM IF ANY CHARACTER ; IS TYPED FROM THE CONSOLE. MODIFED USER NUMBER ROUTINE TO ; INCLUDE LEADING 0 WHEN PRINTING USER #'S 0-9 TO LINE UP ; PRINTOUT. - Shawn Everson ; ; ;======================================================================= ; ; ; DEFINE TRUE AND FALSE ; YES: EQU 0FFH NO: EQU 0 ;..... ; ; ; SET THE FOLLOWING AS     DESIRED: ; SHOWSYS: EQU YES ;'YES' IF WANT TO SHOW SYSTEM FILES DRVTYP: EQU YES ;'YES' IF BIOS HAS 'ILLEGAL DRIVE SELECT' ;TRAP. SET 'NO' IF NO TRAP IN BIOS, ;THEN SET 'MAXDRV' TO NUMBER OF DRIVES TO ;SEARCH THROUGH FOR THE REQUESTED FILE. MAXDRV: EQU 2 ;NUMBER OF DRIVES TO SEARCH THROUGH MAXCOL: EQU 4 ;MAX NUMBER OF COLUMNS DESIRED IN DISPLAY MAXUSR: EQU 15 ;MAX USER # TO BE CHECKED (0-15 POSSIBLE) ;..... ; ; ; DEFINE SOME MISCELLANEOUS VALUES: ; BASE: EQU 0 ;STION SRCHFST: EQU 17 ;SEARCH FOR FIRST FUNCTION SRCHNXT: EQU 18 ;SEARCH FOR NEXT FUNCTION SETIOB: EQU 24 ;SET I/O BYTE SETDMA: EQU 26 ;SET DMA ADDRESS FUNCTION SETUSR: EQU 32 ;SET/GET USER CODE FUNCTION ;..... ; ; ORG BASE+100H ; ; LXI H,0 ;SET 'HL' TO ZERO DAD SP ;GET STACK POINTER INTO 'HL' SHLD STACK ;SAVE FOR EXIT TO 'CCP' STACK LXI SP,STACK ;SET UP LOCAL STACK CALL ILPRT ;PRINT SIGN-ON MESSAGE DB CR,LF,'FILE v14 - CTL-X to abort',CR,LF,0 LDA FC STA MAXTEMP ;SET MAXIMUM USER NUMBER TO 'MAXUSR' ; SBOOT: LHLD 0000H+1 ;GET WARM-BOOT ADDRESS SHLD WBOOT ;SAVE WARM-BOOT ADDRESS LXI D,SETIOB ;GET ADDRESS FOR 'SET I/O BYTE' DAD D ;INDEX INTO BIOS SHLD DSKSEL+1 ;GET JUMP TO BIOS 'DSKSEL' ROUTINE ; ; ; THE FOLLOWING CODE SETS A TRAP AT THE WARM-BOOT JUMP, SO THAT ; ANY 'ILLEGAL DRIVE SELECT' TRAPS IN THE BIOS WILL BE DEFEATED. ; LXI H,DONE ;REPLACE WARM-BOOT POINTER WITH TRAP SHLD 1 LXI D,TBUF MVI C,SETDMA C IF KEY PRESSED CALL BDOS ORA A JZ NOPRESS ;IF NO KEY PRESSED, THEN CONTINUE MVI C,CONIN ;IF KEY PRESSED, THEN CHECK FOR ABORT CALL BDOS CPI 'C'-40H ;IS IT CTL-C? JZ AVAIL1 ;IF NO, THEN CONTINUE CPI 'X'-40H ;IS IT CTL-X? ; AVAIL1: JNZ NOPRESS ;IF NO, THEN CONTINUE CALL ILPRT ;IF YES, THEN PRINT ABORT MESSAGE DB CR,LF,CR,LF,'++ ABORTED ++',0 JMP DONE1 ;..... ; ; NOPRESS: LXI D,FCB MVI C,SRCHFST CALL BDOS ;CHECK FOR DIRECTORY MATCH WITH 'FCB CMP B JNC NXTUSR ;DO NEXT USER NUMBER IF ALL NOT DONE LDA ORIGCTU ;ELSE RESET USER # AND DO NEXT DRIVE STA CTU MVI C,RTNVER CALL BDOS ;SEE IF CP/M VERSION 1.4 OR 2.X MVI C,5 ;(IF CP/M 1.4, THEN BIOS MUST RETURN AN ORA A ;ERROR IF BAD DRIVE #, ELSE WON'T WORK) JZ FOUR ;IF 1.4 THEN FOUR DRIVES MAXIMUM ; IF DRVTYP MVI C,16+1 ;OTHERWISE 16 DRIVES MAXIMUM UNLESS ENDIF ;NO BIOS TRAP. ; IF NOT DRVTYP ;IF NO TRAP THEN MAX DRIVES NUMBER IS MVI C,MAET TO BASE ADDRESS OF YOUR CP/M BDOS: EQU BASE+5 ;CP/M BDOS ENTRY POINT CR: EQU 0DH ;ASCII RETURN FCB: EQU BASE+5CH ;CP/M FILE CONTROL BLOCK ADDRESS LF: EQU 0AH ;ASCII LINEFEED TBUF: EQU BASE+80H ;DMA BUFFER ADDRESS ;..... ; ; ; DEFINE SOME BDOS FUNCTIONS: ; CONIN: EQU 1 ;CONSOLE INPUT FUNCTION CONOUT: EQU 2 ;CONSOLE OUTPUT FUNCTION PRINT: EQU 9 ;PRINT STRING AT CONSOLE FUNCTION CONSTAT: EQU 11 ;GET CONSOLE STATUS FUNCTION RTNVER: EQU 12 ;RETURN VERSION NUMBER FUNCB+1 ;CHECK FOR FILENAME ON COMMAND LINE CPI ' ' JZ NONAME CALL ILPRT DB 'searching...',0 ; SETUP: LDA 0004H ;SAVE USER/DRIVE # STA UDNUM RRC ;1ST 4 BITS GIVE CURRENT USER # RRC RRC RRC ANI 0FH ;'AND' OFF THE DRIVE BITS STA CUN ;SAVE CURRENT USER # STA CTU ;SAVE AS CURRENT TRY #,TOO MOV B,A MVI A,MAXUSR CMP B JC OUTSIDE XRA A STA CTU ;SET CURRENT TRY USER TO 0: STA ORIGCTU ;SET ORIGINAL 'CTU' TO SAME MVI A,MAXUSR ALL BDOS ;SET DMA ADDRESS MVI A,0 ;START LOOKING ON 0 DRIVE ("A") STA TRYDRV ;SET UP TO TRY DRIVE '0' FIRST ; TRY: MOV C,A ;TRY TO SELECT DRIVE CALL DSKSEL MOV A,L ORA H JZ DONE ;IF 'HL' IS 0, THEN NO MORE DRIVES LDA TRYDRV INR A STA TRYDRV ;GET READY FOR NEXT DRIVE, TOO STA FCB ;STORE 1+DRIVE# IN FCB (1=A, 2=B, ETC.) ; NXTUSR: LDA CTU ;SET USER TO 'CTU' VIA A BDOS CALL MOV E,A MVI C,SETUSR CALL BDOS ; AVAIL: MVI C,CONSTAT ;CHECK TO SEE' CPI 0FFH ;A-REG. HAS 0-3 IF FILE FOUND ELSE 0FFH JZ NXT ;DO NEXT DRIVE IF NO MORE MATCHES FOUND CALL SHOFIL ;IF MATCH FOUND, DISPLAY THE FILENAME ; SNEXT: MVI C,SRCHNXT CALL BDOS ;CHECK FOR NEXT MATCH WITH FCB CPI 0FFH JZ NXT ;NO MORE MATCHES? THEN DO NEXT DRIVE CALL SHOFIL ;IF MATCH FOUND, DISPLAY THE FILENAME JMP SNEXT ;CONTINUE UNTIL NO MORE MATCHES FOUND ; NXT: LDA CTU ;INCREMENT CURRENT TRY USER NUMBER INR A STA CTU MOV B,A LDA MAXTEMP XDRV ;IS SET MANUALLY. ENDIF ; FOUR: LDA TRYDRV CMP C JC TRY ;CONTINUE UNTIL ALL DRIVES CHECKED... ; ; ; ALL DONE NOW, RETURN TO CP/M ; DONE: LDA MFLAG ;SEE IF ANY FILES FOUND ORA A JNZ DONE1 ;IF YES, THEN DONE, SO EXIT CALL ILPRT ;IF NO, THEN SAY NONE FOUND FIRST DB CR,LF,CR,LF,'++ FILE NOT FOUND ++',0 ; DONE1: CALL ILPRT DB CR,LF,0 ;TURN UP A LINE LHLD WBOOT ;RESTORE WARM-BOOT JUMP SHLD 1 LDA UDNUM ;RESTORE USER/DRIVE NUMBER STA 4     ANI 0FH MOV C,A ;PUT THE DRIVE INTO 'C' CALL DSKSEL ; EXIT: JMP 0000H ;THEN RETURN TO CP/M VIA WARM REBOOT ;..... ; ; NONAME: CALL ILPRT ;ELSE, PRINT HELP MESSAGE AND EXIT DB CR,LF DB ' You must specify the file(s) you',CR,LF DB ' want to find. Wildcards are ok.',CR,LF,LF DB ' EXAMPLE: FILE MODEM7.DOC',CR,LF DB ' FILE MOD*.*',CR,LF DB ' FILE *.ASM',CR,LF DB ' FILE *.*',CR,LF,0 ; EXITSPCL: LHLD STACK AME WITHIN DIRECTORY RECORD) DAD H DAD H DAD H ;MULTIPLY 'A' BY 32 TO POINT TO START OF LXI D,TBUF ;FILENAME DAD D ;NOW POINT TO FILENAME XCHG ;SAVE FILENAME POINTER IN 'DE' ; IF NOT SHOWSYS ;THEN IGNORE 'SYS' FILES LXI H,10 DAD D ;POINT TO 'SYS' FILE ATTRIBUTE MOV A,M ANI 80H ;CHECK FOR 'SYS' TYPE FILE RNZ ;DON'T DISPLAY IF 'SYS' ATTRIBUTE IS SET ENDIF ; LDAX D ;GET USER NUMBER INX D PUSH PSW ;SAVE THE USER NUMBER CPI 9+1 BINARY TO ASCII # CALL AOUT2 ;PRINT DIGIT ; NOUSR: MVI A,':' ;FENCE CHARACTER CALL AOUT2 ;DISPLAY A ':' TO LOOK NICE ;;; MVI A,' ' ;;; CALL AOUT2 ;SEPARATE IT FROM THE FILE NAME MVI B,8 ;(8 CHARACTERS OR LESS IN FILENAME) ; PFN: LDAX D ;NOW PRINT THE FILENAME.. INX D CALL AOUT2 ;..ONE CHARACTER AT A TIME DCR B JNZ PFN ;CONTINUE FOR ALL 8 CHARACTERS MVI A,'.' CALL AOUT2 ;DISPLAY THE '.' BEFORE THE FILETYPE MVI B,3 ;NOW DO THE SAME FOR THE FILETL AOUT2 MVI A,' ' JMP AOUT2 ; AOUT: MOV B,A ;SAVE THE CHARACTER FOR NOW LDA FIRST ORA A JNZ AOUT1 CALL ILPRT DB CR,LF,CR,LF,0 MVI A,1 STA FIRST ; AOUT1: MOV A,B ; AOUT2: PUSH B ;SEND A CHARACTER TO THE CONSOLE PUSH D PUSH H ;SAVE REGISTERS IN CASE BDOS EATS THEM ANI 7FH ;STRIP PARITY BIT MOV E,A MVI C,2 CALL BDOS ;PRINT THE CHAR. IN 'A' ON THE CONSOLE POP H POP D POP B ;RESTORE THE REGISTERS RET ;..... ; ; ; IN;FIRST TIME USE OF 'AOUT' (FOR CR/LF) MAXTEMP: DB 0 ;MAXIMUM TRY USER NUMBER MFLAG: DB 0 ;FLAG SET TO NON-ZERO IF FILE IS FOUND ORIGCTU: DB 0 ;ORIGINAL CURRENT TRY USER NUMBER TRYDRV: DB 0 ;NUMBER OF DRIVE BEING TRIED UDNUM: DB 0 ;USER/DRIVE NUMBER IS SAVED HERE ; DSKSEL: DB 0C3H ;'JMP' INSTRUCTION DW 00000H ;(BIOS'S DSKSEL ADDRESS IS STORED HERE) ;(BYPASSES BDOS TO AVOID "BDOS CALL") WBOOT: DW 0000H ;CP/M WARM-BOOT ADDRESS IS SAVED HERE ;..... ; ; DS 64 ;32 LEVE ;GET THE ORIGINAL 'CCP' STACK ADDRESS SPHL ;SET STACK POINTER FROM 'HL' ADDRESS RET ;RETURN TO THE 'CCP' STACK ;..... ; ; OUTSIDE: LDA CUN STA CTU ;SET CURRENT TRY USER TO CURRENT USER # STA ORIGCTU ;SET ORIGINAL 'CTU' TO SAME STA MAXTEMP ;SET MAXIMUM USER NUMBER TO CURRENT JMP SBOOT ;AND CONTINUE... ; SHOFIL: MOV L,A ;GET FILENAME TO DISPLAY FROM DIRECTORY MVI H,0 ;WHICH CP/M PUTS AT DMA ADDRESS DAD H ;("A" REGISTER HAS RELATIVE POSITION OF DAD H ;N;IS USER NUMBER = 0 THRU 9? JNC SHOFIL1 ;IF NOT, EXIT MVI A,' ' CALL AOUT ;PRINT THE EXTRA SPACE ; SHOFIL1: LDA TRYDRV ;GET THE DISK DRIVE ADI 'A'-1 ;CONVERT BINARY TO ASCII CALL AOUT ;DISPLAY DRIVE (A-P) POP PSW ;SAVE THE USER NUMBER CPI 9+1 ;0-9 ? JC USRL ;IF YES, EXIT ; SUI 10 ;USER NUMBER = 10 THRU 15 PUSH PSW ;REMAINDER IS <10 MVI A,'1' CALL AOUT2 ;PRINT A LEADING '1' POP PSW ;GET THE REMAINDER BACK ; USRL: ADI '0' ;CONVERT FROM YPE ; PXT: LDAX D INX D CALL AOUT2 DCR B JNZ PXT LDA COLUMN ;PRINT MAXCOL COLUMNS ACROSS THE SCREEN DCR A JZ DOCRLF STA COLUMN CALL TWOSPC ;PRINT TWO SPACES TO MAKE IT NEAT MVI A,0FFH ;SHOW THAT A FILE WAS FOUND STA MFLAG ;SUPPRESSES 'NOT FOUND' MESSAGE RET ;..... ; ; DOCRLF: MVI A,MAXCOL ;RESET COLUMN NUMBER AFTER LAST COLUMN STA COLUMN MVI A,CR CALL AOUT2 MVI A,LF CALL AOUT2 RET ;..... ; ; TWOSPC: MVI A,' ' CALLINE PRINT ROUTINE ; ILPRT: XTHL ;SET HL TO POINT TO MESSAGE ; ILPLP: MOV A,M ;GET A CHARACTER FROM MESSAGE CALL AOUT2 ;OUTPUT IT INX H ;POINT TO NEXT CHARACTER MOV A,M ;CHECK FOR END OF MESSAGE ORA A ; (00H MARKS END OF MESSAGE) JNZ ILPLP XTHL ;GET PROPER RETURN ADDRESS ONTO STACK RET ;THEN RETURN TO PROGRAM ;..... ; ; COLUMN: DB MAXCOL ;COLUMN COUNTER CTU: DB 0 ;CURRENT TRY USER NUMBER CUN: DB 0 ;CURRENTLY LOGGED-IN USER NUMBER FIRST: DB 0 L STACK SHOULD BE ENOUGH ROOM STACK: DS 2 ;..... ; ; END OOT ADDRESS IS SAVED HERE ;..... ; ; DS 64 ;32 LEVE FOUND ORIGCTU: DB 0 ;ORIGINAL CURRENT TRY USER NUMBER TRYDRV: DB 0 ;NUMBER OF DRIVE BEING TRIED UDNUM: DB 0 ;USER/DRIVE NUMBER IS SAVED HERE ; DSKSEL: DB 0C3H ;'JMP' INSTRUCTION DW 00000H ;(BIOS'S DSKSEL ADDRESS IS STORED HERE) ;(BYPASSES BDOS TO AVOID "BDOS CALL") WBOOT: DW 0000H ;CP/M WARM-BOOT ADDRESS IS SAVED HERE ;..... ; ; DS 64 ;32 LEVE    ; ; FILEFIND.ASM Originally written b R Rodma ; Version 12.0 ; ; ; This program will search all preset user areas of all drives for ; any files matching the command tail, then display those files in ; a DIR-like format. NOTE THAT A DRIVE NEED NOT BE ACTIVE (logged-in) ; TO BE SEARCHED. By setting the MINUSR and MAXUSR equates to 0 and ; 32, respectively, this program can be made to list ALL files in ; ALL user areas of ALL drives. ; ; Example: FILEFIND *.COM lists all .COM files on al3) 846-6127 (110, 300, 450, 600 Baud, 24 hours) so that we can ; keep the file properly updated and available to all. ; ; Modification history (in reverse order to minimize reading time): ; ;12/15/82 Modified to run in the 'secure' mode of NZCPR. If secure is set ; ture, then maxuser and maxdrive are taken from preset memory ; locations, except that it can never exceed the maxuser equate set ; in this source. This means, the program only gives information about ; those areas to which th, restored ; original author's name to the heading. ; By Thomas V. Churbuck ; ;07/31/81 Added tutorial to be printed if filename (FCB) ; field (fn.ft tail of the command line) is blank ; (omitted by the inexperienced user). ; By Thomas V. Churbuck ; ;07/31/81 Substituted IN-LINE PRINT ROUTINE where appro- ; priate for all printed messages. Prints message ; on exit if no files were found (matched). ; By Thomas V. Churbuck ; ;07/30/81 Modified AVAIutines to permit user #-drive OR ; drive-user # printout to match either MPM or USERLST ; by providing DRVFIRST conditional ; By Earl Bockenfeld ; ;07/12/81 Modified SHOFIL routines to always print leading zero ; when MULTUSR is TRUE so that multiple user number displays ; will align properly. ; By Dave Hardy ; ;07/08/81 Added MULTUSR routines to allow program to be conditionally ; assembled to check a preset range of user areas. With MINUSR ; and MAXUSR (belowl drives ; ; ; This program makes a direct call to the SELDSK routine of the CBIOS ; to determine a drive's existence without causing a BDOS error. ; ; NOTE: THIS PROGRAM ASSUMES THAT ANY CBIOS 'ILLEGAL DRIVE SELECT' ; TRAPS WILL CAUSE THE SYSTEM TO EXECUTE A WARM-BOOT BY JUMPING ; TO ADDRESS 0. If a select error bypasses the warm-boot jump ; at address 0, then the trap in this program will not work. ; ; PLEASE RETURN ANY UPDATES, REPAIRS, ETC. TO TECHNICAL CBBS, Dearborn, MI ; at (31e user has access. Joe Dietz WD5BUV ; ;12/10/82 Modified to make DE register be zero when Drive Select is called. ; This makes sure the CBIOS thinks the new drive needs to be logged in. ; May be necessary on some CBIOS's (like Godbout) Joe Dietz ; ;08/02/81 Cleaned up file and removed unnecessary code. Thanks to ; Tom and Shawn for adding some more goodies. ; By Dave Hardy ; ;07/31/81 Modified AVAIL routine to abort only on control-C ; from the console. Cleaned up the fileL routine to abort program if any ; character is typed from the console. ; By Shawn Everson ; ;07/29/81 Modifed user number routine to include leading ; 0 when printing user #'s 0-9 to line up printout. ; By Shawn Everson ; ;07/17/81 Removed DRVFIRST routines and replaced with DRV1ST ; routines to make code shorter and more efficient. ; Note that although these changes will make FILEFIND ; look MP/M compatible, it actually is NOT. ; By Dave Hardy ; ;07/17/81 Modified SHOFIL ro) set to 0 and 32, respectively, this program ; will produce a master directory of EVERY file on EVERY drive ; on its host system. If MULTUSR is set TRUE, then when program ; is executed, if current user number is within MINUSR and MAXUSR, ; program will check the set range of user areas from MINUSR to MAXUSR. ; But if current user number is not within set range, program will ; check only current user area. I did this so that remote callers ; could use program to check all remote user    areas, but a local ; SYSOP could use program for any user area, assuming that ; program was located in a public (common) user area. ; By Dave Hardy ; ;07/02/81 Fixed user number print routine to properly display ; user numbers 10-15. By Keith Petersen, W8SDZ ; ;07/01/81 Changed file name print routine so spaces are not printed ; after last filename on a line. By Keith Petersen, W8SDZ ; ;05/30/81 Removed stack save routines, so that now the program will ; warm-boot back, instead ofOS, ; this would cause a warm-boot as soon as the first illegal drive ; is selected, so a trap is used that replaces the warm-boot ; pointer at address 1 during execution of this program. After ; execution, the pointer is restored, and the program does a ; 'ret' to CP/M. In systems with no traps in the CBIOS (most ; systems), this program will finish and return to CP/M without ; encountering the warm-boot trap. In either case, the program ; should work properly. Thanks to Ron F; ;04/20/81 Renamed from FILE.ASM to FILEFIND.ASM to avoid ; confusion with CPMUG FIND.ASM ; By Dick Mead ; ; Define some miscellaneous values: BASE EQU 0 ;Set to base address of your CP/M (normally 0) BDOS EQU BASE+5 ;CP/M BDOS entry point FCB EQU BASE+5CH;CP/M file control block address DMABUF EQU BASE+80H;DMA buffer address CR EQU 0DH ;ASCII return LF EQU 0AH ;ASCII linefeed ; ; Define some BDOS functions: SETDMA EQU 26 ;Set DMA Address function SRCHFST EQU 17 ;Search For First functT EQU TRUE ;TRUE if want to print drive before user number ;FALSE if want to print user number before drive MAXCOL EQU 4 ;Set to number of columns desired in display MULTUSR EQU TRUE ;TRUE if want to search multiple user numbers ;FALSE if want to search only current user number SECURE EQU TRUE ;TRUE if MAXUSR and MAXDRV are stored in memory and are ;to be dynamically set at run time ; The following need to be set only if MULTUSR above is set TRUE: MINUSR EQU 0 ;Set to minimum user number t command line CPI ' ' JNZ SETUP ;If it's there, then continue CALL ILPRT ;Else, print help message and exit DB CR,LF,'Usage: FILEFIND ' DB CR,LF,CR,LF DB ' You must specify the file(s) you',CR,LF DB ' want to find. Ambiguous file names',CR,LF DB ' may be used.',CR,LF,CR,LF DB ' Example: FILEFIND MODEM.DOC',CR,LF DB ' FILEFIND *.ASM',CR,LF,0 JMP 0 ;Warm-boot back to CP/M ; SETUP LDA 4 ;Save USER/DRIVE number STA UDNUM RR 'RET'. This was necessary because ; the stack may be garbaged by the CBIOS when the warm-boot trap ; is encountered. Also added check in SHOFIL routine to check for ; proper user number before displaying a filename, in case of ; public user area (e.g. if BDOS-PAT.ASM is installed). ; By Dave Hardy ; ;05/12/81 Added automatic log-in feature, so that all drives will ; be selected, regardless of which were previously logged in. ; In systems with illegal drive select traps in their CBIowler for his suggestions. ; NOTE: This program will probably no longer work with CP/M ; 1.4, since most 1.4's don't check for illegal drive selects. ; By Dave Hardy ; ;05/06/81 Fixed BASE equates, added comments, added conditionals ; for SYS file and USER number display, added MAXCOL equate ; to set number of display columns, eliminated display of ; USER number when in USER 0 to make display easier to read, ; made miscellaneous changes to make file more readable. ; By Dave Hardy ion SRCHNXT EQU 18 ;Search For Next function CONOUT EQU 2 ;Console Output function RTNVER EQU 12 ;Return Version Number function SETUSR EQU 32 ;Set/Get User Code function CONSTAT EQU 11 ;Get Console Status function CONIN EQU 1 ;Console Input function PRINT EQU 9 ;Print String At Console function ; ; Define true and false FALSE EQU 0 TRUE EQU NOT FALSE ; ; Set the following as desired: SHOWSYS EQU FALSE ;TRUE if want to show SYS files SHOWUSR EQU TRUE ;TRUE if want to show user number DRV1So be checked MAXUSR EQU 13d ;Set to maximum user number to be checked ;Even in secure, maximum user cannot exceed this number IF SECURE MAXUSRL EQU 03Fh ;Memory location which holds maxuser+1 MAXDRVL EQU 03Dh ;Memory location which holds MAXDRV (0=A, 1=B, etc.) ENDIF ;NOT SECURE ; ; ORG BASE+100H ; LXI SP,STACK ;Set up local stack ; CALL ILPRT ;Print sign-on message ; DB CR,LF,'FILEFIND ver 12.0',CR,LF DB 'Type CTRL-C to abort',CR,LF,CR,LF,0 ; LDA FCB+1 ;Check for filename onC RRC RRC RRC ANI 0FH STA CUN ;Save current user number STA CTU ;Save as current try number, too ; IF MULTUSR ;then set up some boundaries MVI B,MINUSR CMP B ;Current user number within range? JC OUTSIDE ;No? then search only current user number MOV B,A IF NOT SECURE ;then MAXUSR is set by an equate MVI A,MAXUSR ELSE ;value of MAXUSR+1 is found at MAXUSRL LDA MAXUSRL DCR A CPI MAXUSR JC SETUP1 ;jmp if (MAXUSRL)<=MAXUSR ie, within range MVI A,MAXUSR SETUP1      ENDIF ;not secure CMP B JC OUTSIDE MVI A,MINUSR STA CTU ;Set Current Try User to MINUSR STA ORIGCTU ;Set original CTU to same IF NOT SECURE ;then MAXUSR is set by an equate MVI A,MAXUSR ELSE ;value of MAXUSR+1 is found at MAXUSRL LDA MAXUSRL DCR A CPI MAXUSR JC SETUP2 ;jmp if (MAXUSRL)<=MAXUSR ie, within range MVI A,MAXUSR SETUP2 ENDIF ;NOT SECURE STA MAXTEMP ;Set maximum user number ENDIF ; SBOOT LHLD 1 SHLD WBOOT ;Save warm-boot address LXI D,18H  ;jmp if TRYDRV > (MAXDRL). We're done. ENDIF ;multusr and secure PUSH D ;sav th register LXI D,0 ;make de=0 to cause cbios to log in new disk CALL DSKSEL POP D ;restore d register MOV A,L ORA H JZ DONE ;If HL=0 then no more drives LDA TRYDRV INR A STA TRYDRV ;Get ready for next drive, too STA FCB ;Store 1+drive# in FCB (1=A, 2=B, etc.) ; IF MULTUSR ;Then set user before each pass NXTUSR LDA CTU ;Set user to CTU via a BDOS call MOV E,A MVI C,SETUSR CALL BDOS" register has 0-3 if file found else 0FFH JZ NXT ;Do next drive if no more matches found CALL SHOFIL ;If match found, then display the filename ; SNEXT MVI C,SRCHNXT CALL BDOS ;Check for next match with FCB CPI 0FFH JZ NXT ;No more matches? Then do next drive CALL SHOFIL ;If match found, then display the filename JMP SNEXT ;Continue until no more matches found ; NXT EQU $ ; IF MULTUSR ;then see if any more user numbers to check LDA CTU ;Increment current try user number INll done now, return to CP/M ; DONE LDA MFLAG ;See if any files found CPI 0 JNZ DONE1 ;If yes, then done, so exit CALL ILPRT ;If no, then say none found first DB CR,LF,'+++ FILE NOT FOUND',CR,LF,0 DONE1 LHLD WBOOT ;Restore warm-boot jump SHLD 1 LDA UDNUM ;Restore USER/DRIVE number STA 4 ANI 0FH MOV C,A ;Select original drive before return so that CALL DSKSEL ; CP/M won't get confused... JMP 0 ;Then return to CP/M via a warm-boot... ; IF MULTUSR ;and current user number i H DAD H DAD H ;Multiply "A" by 32 to point to start of filename LXI D,DMABUF DAD D ;Now point to filename XCHG ;save filename pointer in de ; IF NOT SHOWSYS ;then ignore SYS files LXI H,10 DAD D ;Point to SYS file attribute MOV A,M ANI 80H ;Check for SYS type file RNZ ;Return if SYS attribute set (i.e. don't display) ENDIF ; ; The following code is needed only if BDOS-PAT.ASM is installed in ; your CP/M. It makes sure that this program only lists those files ; that are in DAD D SHLD DSKSEL+1 ;Get jump to CBIOS DSKSEL routine ; ; The following code sets a trap at the warm-boot jump, so that ; any 'illegal drive select' traps in the CBIOS will be defeated. LXI H,DONE ;Replace warm-boot pointer with trap SHLD 1 ; LXI D,DMABUF MVI C,SETDMA CALL BDOS ;set DMA address ; XRA A STA TRYDRV ;Set up to try drive '0' first TRY MOV C,A ;Try to select drive IF MULTUSR AND SECURE ;then see if TRYDRV exceeds value in MAXDRVL LDA MAXDRVL CMP C JC DONE  ENDIF ; AVAIL MVI C,CONSTAT ;Check to see if key pressed CALL BDOS ORA A JZ NOPRESS ;If no key pressed, then continue MVI C,CONIN ;If key pressed, then check for abort CALL BDOS CPI 'C'-40H ;Is it control-C? JNZ NOPRESS ;If no, then continue CALL ILPRT ;If yes, then print abort message DB CR,LF,LF,'+++ ABORTED',CR,LF,0 JMP DONE1 ;Then restore warm-boot jmp and UDNUM then exit ; NOPRESS LXI D,FCB MVI C,SRCHFST CALL BDOS ;Check for directory match with FCB CPI 0FFH ;"AR A STA CTU MOV B,A LDA MAXTEMP CMP B JNC NXTUSR ;Do next user number if all not done LDA ORIGCTU ;Else reset user number and do next drive STA CTU ENDIF ; MVI C,RTNVER CALL BDOS ;See if CP/M version 1.4 or 2.x MVI C,5 ; (if CP/M 1.4, then CBIOS must return an ORA A ; error if bad drive number, else won't work) JZ FOUR ;If 1.4 then four drives maximum MVI C,17 ;Otherwise 16 drives maximum ; FOUR LDA TRYDRV CMP C JC TRY ;Continue until all drives checked... ; ; as outside MIN/MAX OUTSIDE IF SECURE JMP DONE1 ;quit without any messages ENDIF ;secure LDA CUN STA CTU ;Set current try user to current user number STA ORIGCTU ;Set original CTU to same STA MAXTEMP ;Set maximum user number to current JMP SBOOT ;and continue... ENDIF ;multusr ; SHOFIL MOV L,A ;Get filename to display from directory record MVI H,0 ; which CP/M puts at DMA address DAD H ;("A" register has relative position of name DAD H ; within directory record) DAD the current user area (i.e. if you are in a non-zero ; user area, it won't list the files in user 0, too). LDA CTU ;Get current try USER number XCHG ;Point HL to user number byte of directory entry CMP M RNZ ;Return if wrong user number (i.e. don't show file) XCHG ;Get directory pointer back into DE ; IF DRV1ST ;then print drive number before user number LDA TRYDRV ADI 'A'-1 CALL AOUT ;Display drive (A-P) ENDIF ; IF SHOWUSR OR MULTUSR ;then display USER number (except 0) LD   AX D ;get USER number INX D ENDIF ; IF NOT MULTUSR ;then don't print leading 0 for user 0 ORA A ;USER 0 ? JZ NOUSR ;if USER 0 don't report ENDIF ; IF SHOWUSR OR MULTUSR ;continue displaying user numbers CPI 10 ;is USER number = 0 thru 9? JNC NEAT ;If no, then print a leading '1' PUSH PSW ;Save USER number MVI A,'0' ;If yes, then print a leading '0' CALL AOUT POP PSW ;Restore USER number JMP USRL ;Then print second digit of user number ; NEAT SUI 10 ;USER number = 10 thru 15 ;Continue until all 8 characters displayed MVI A,'.' CALL AOUT ;Display the '.' before the filetype ; MVI B,3 ;Now do the same for the filetype PXT LDAX D INX D CALL AOUT DCR B JNZ PXT ; LDA COLUMN ;Print MAXCOL columns across the screen DCR A JZ DOCRLF STA COLUMN CALL TWOSPC ;Print two spaces to make it neat MVI A,0FFH ;Set MFLAG to remember that a file was found STA MFLAG ; (so that 'NOT FOUND' message will be suppressed) RET ; DOCRLF MVI A,MAXCOL ;After last column: SMOV A,M ;Get a character from message CALL AOUT ;Output it INX H ;Point to next character MOV A,M ;Check for end of message ORA A ; (00H marks end of message) JNZ ILPLP XTHL ;Get proper return address onto stack RET ;Then return to program ; COLUMN DB MAXCOL ;Column counter TRYDRV DB 0 ;Number of drive being tried UDNUM DB 0 ;USER/DRIVE number is saved here CUN DB 0 ;Currently logged-in user number MFLAG DB 0 ;Flag set to non-zero if file is found WBOOT DW 0000H ;CP/M warm-boot addres; FLOPPY DISK COPY PROGRAM ; COPYRIGHT 1982, G. YOUNG, INC. ; UPDATED 1/8/82 * * TO EXECUTE, ENTER THE PROGRAM NAME FOLLOWED BY THE FILE MASK: * A>FLOPCOPY *.COM * * THE PRIMARY PURPOSE OF THIS PROGRAM IS TO COPY A FLOPPY DISK ON * SYSTEMS THAT HAVE ONLY ONE FLOPPY DISK AND A HARD DISK. THIS IS DONE * BY READING THE DIRECTORY ON THE FLOPPY AND CREATING A LIST OF FILES TO * TO BE COPIED, THEN COPY ALL THE FILES TO THE HARD DISK. A BLANK * DISK IS THEN INSERTED AND THE FILES ARE COPIED PUSH PSW MVI A,'1' CALL AOUT ;print a leading '1' POP PSW ; USRL ADI '0' ;make into ASCII number CALL AOUT ;print digit ENDIF ; NOUSR EQU $ ; IF NOT DRV1ST ;Then print drive number after user number LDA TRYDRV ADI 'A'-1 CALL AOUT ;Display drive (A-P) ENDIF ; MVI A,':' ;Fence character CALL AOUT ;Display a ':' to look nice ; MVI B,8 ;(8 characters or less in filename) PFN LDAX D ;Now print the filename... INX D CALL AOUT ; ... one character at a time DCR B JNZ PFN TA COLUMN ; Reset column number MVI A,CR ; Then print CRLF CALL AOUT MVI A,LF CALL AOUT RET ; TWOSPC MVI A,' ' CALL AOUT MVI A,' ' ;Fall into AOUT ; AOUT PUSH H ;Send a character to the console PUSH D PUSH B ;Save the registers in case BDOS eats them ANI 7FH ;Strip parity bit MOV E,A MVI C,2 CALL BDOS ;Print the character in 'A' on the console POP B POP D POP H ;Restore the registers RET ; ;INLINE PRINT ROUTINE ; ILPRT XTHL ;Set HL to point to message ; ILPLP s is saved here ; IF MULTUSR CTU DB 0 ;Current try user number ORIGCTU DB 0 ;Original current try user number MAXTEMP DB 0 ;Maximum try user number ENDIF ; DSKSEL DB 0C3H ;Jump to CBIOS's disk select routine DW 0000H ; (CBIOS's DSKSEL address is stored here) ; DS 64 ;32 level stack should be enough room STACK DS 2 ; END  DB 0 ;Currently logged-in user number MFLAG DB 0 ;Flag set to non-zero if file is found WBOOT DW 0000H ;CP/M warm-boot addres TO THE BLANK FLOPPY * AND DELETED OFF THE HARD DISK. THIS PROCEDURE IS USED INSTEAD OF * THE "SINGLE.COM" PROGRAM BECAUSE THERE IS MORE THAN 1 FILE SO "SINGLE" * CANNOT BE USED WITHOUT MODIFICATIONS AND EVEN THEN MANY, MANY DISKETTE * MOUNTS WOULD HAVE TO BE DONE. THIS WAY, ONLY 1 DISKETTE MOUNT NEEDS * TO BE DONE FOR EACH DISK THAT IS COPIED. * WRITTEN BY GARY YOUNG, BOX 3218, NO. HOLLYWOOD, CA 91609 TITLE '*** FLOPPY DISK COPY PROGRAM ***' BDOS EQU 5 RECSIZE EQU 12 FLOPPY EQU 4 ;FLOPPY     DISK IS DRIVE D: WHICH IS 4 IN BINARY HARDISK EQU 1 ;USE HARD DISK DRIVE A: WHICH IS 1 IN BINARY BOOT EQU 0 ORG 100H JMP START DB 'COPYRIGHT 1982, G. YOUNG, INC.' START LXI SP,STACK+80 LDA 5DH ;SEE IF A MASK WAS ENTERED CPI 20H ;BUFFER WILL BE BLANK IF NOT JZ NOMASK MVI C,0DH ;DISK RESET CALL BDOS LXI H,RAM ;SET UP TABLE ADDRESS SHLD TABADDR LXI H,0000H SHLD TABCNT XRA A ;THE TABLE REFERS TO THE REMAINING AREA STA ABORT ;OF RAM TO HOLD AS MANY DIRECTORY ENTRIES STA EOF CALL QUESTION MVI C,0DH CALL BDOS MVI A,HARDISK STA SRCE MVI A,FLOPPY STA DEST CALL CPYFILE MSG3 LXI D,ANOTHER CALL QUESTION ORA A JZ WIPEOUT LDA INREC CPI 'N' JZ WIPEOUT CPI 'Y' JNZ MSG3 JMP AGAIN WIPEOUT CALL ERASE JMP BOOT ;RESET AND RETURN TO CPM NOMASK LXI D,ERRNOMSK CALL OUTPUT JMP BOOT * * THE EXTRACT ROUTINE SCANS THE DIRECTORY ON THE FLOPPY DISK * AND CREATES A LIST OF FILES TO BE COPIED. AFTERS SORTING, * DUPLICATE ENTRIES RESULTING FROM MULTIPLE EX ;SET A DMA ADDRESS FOR DIRECTORY ENTRIES MVI C,1AH CALL BDOS ;SET DMA LXI D,DUMMYFCB ;GET FIRST DIRECTORY ENTRY MVI C,11H CALL BDOS ;GET DIRECTORY INR A RZ JMP GETFCB ;EXTRACT DATA FROM FCB NEXTFCB LXI D,DUMMYFCB ;GET NEXT ENTRY AFTER THE FIRST MVI C,12H CALL BDOS INR A RZ GETFCB LXI D,32 ;EACH ENTRY IS 32 BYTES LONG LXI H,DISKBUF ;DIRECTORY RECORD IS IN DISKBUF CPI 1 ;FIRST ENTRY IN RECORD??? JZ FORMREC ;YES DAD D ;ADD 32 TO ADDRESS IN RECORD CPI 2 ;SECOND ENTRYP MOV A,M ANI 07FH MOV M,A INX H DCR B JNZ STRIP LXI H,RTYPE ;SKIP OVER JUNK DISK ENTRIES MVI B,11 ;CONTAINING NONPRINTING CHARACTERS NONPRNT MOV A,M CPI 20H ;ANY CHAR LESS THAN A BLANK JC NEXTFCB ;GO TO NEXT ONE IF SO INX H DCR B JNZ NONPRNT FIRSTEXT EQU $ ;GOT THE FIRST EXTENT LHLD TABADDR ;GET MEMORY TABLE ADDRESS LXI D,RTYPE ;GET MEMORY RECORD ADDRESS XCHG ;RTYPE (HL) TO TABADDR (DE) MVI B,RECSIZE ;MOVE RECSIZE BYTES CALL MOVE LHLD TABADDR ;INCREMENT FOR NET RET * COPY THE FILE FROM ONE DISK TO ANOTHER * THIS CODE WAS TAKEN FROM BACKUP.ASM SO HDFCB REFERS TO THE SOURCE DISK * AND FPFCB REFERS TO THE DESTINATION DISK REGARDLESS OF FLOPPY OR HARD. CPYFILE EQU $ LHLD ADDR2 ;GET THE CURRENT END OF TABLE INX H ;PLUS ONE FOR THE START OF THE SHLD ADDR3 ;READ/WRITE BUFFER LXI H,RAM ;SET THE ADDRESS OF THE FIRST ENTRY SHLD ADDR1 JMP PASSMOVE NEXTFILE EQU $ LHLD ADDR1 LXI D,RECSIZE DAD D SHLD ADDR1 PASSMOVE LHLD ADDR1 MOV A,M CP ;AS POSSIBLE LXI D,SIGNON ;PRINT SIGNON MESSAGE CALL OUTPUT CALL EXTRACT ;GET DIRECTORY ENTRIES LDA ABORT ;SEE IF TOO MANY ENTRIES FOR MEMORY SIZE ORA A ;SHOULD BE ZERO TO BE OK JZ NOMORE LXI D,TABFULL ;REPORT WILL NOT BE COMPLETE CALL OUTPUT ;MEMORY FULL ERROR NOMORE CALL SORT CALL KILLDUPS ;REMOVE ENTRIES FROM MULTIPLE EXTENTS MVI A,FLOPPY ;FLOPPY IS THE SOURCE DRIVE STA SRCE MVI A,HARDISK ;HARD DISK IS THE DESTINATION STA DEST CALL CPYFILE AGAIN LXI D,MNTBLANK TENT ENTRIES WILL * BE REMOVED. * * THE DUMMYFCB SETS UP A SKELETON TO READ ALL FILES ON THE DIRECTORY * TO BE MODIFIED BY THE SKELATON SETUP IN THE CALL (EX: FLOPCOPY *.ASC). * DUMMYFCB DB 0,'????????????',0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 EXTRACT EQU $ LXI D,DUMMYFCB ;COPY THE MASK SET UP BY CCP LXI H,5CH ;OVER THE DUMMY FCB TO LIMIT WHAT IS COPIED MVI B,12 CALL MOVE MVI A,FLOPPY ;FORCE THE DRIVE TO BE FLOPPY DRIVE STA DUMMYFCB ORI 40H STA RDISK LXI D,DISKBUF IN RECORD??? JZ FORMREC DAD D ;ADD 64 TO ADDRESS OF RECORD CPI 3 ;THIRD ENTRY IN RECORD??? JZ FORMREC DAD D ;ADD 96 TO ADDRESS OF RECORD FORMREC INX H ;PASS DRIVE BYTE LXI D,RFILE ;MOVE FILE NAME MVI B,8 ;MOVE 8 CHARACTERS CALL MOVE LXI D,8 ;POSITION PAST NAME TO TYPE DAD D LXI D,RTYPE ;MOVE TYPE MVI B,3 ;MOVE 3 CHARACTERS CALL MOVE INX H ;POSITION TO THE EXTENT NUMBER INX H INX H LXI H,RTYPE ;STRIP OFF THE HIGH BIT SET BY MVI B,11 ;THE VERSION PROGRAM STRIXT ENTRY LXI D,RECSIZE ;RECSIZE BYTES IN RECORD DAD D SHLD TABADDR ;SAVE NEW ADDRESS MVI M,1AH ;SET AN END-OF-TABLE INDICATOR LHLD TABCNT ;GET RECORD COUNT INX H SHLD TABCNT ;INCREMENT RECORD COUNT LHLD TABADDR ;SEE IF NEW ADDRESS IS GREATER XCHG ;THAN THE TOP OF TPA-128 LHLD BDOS+1 ;HL=TOP...DE=TABLE+RECSIZE LXI B,-128 DAD B ;SUBTRACT 128 FROM TOP CALL COMPREG ;COMPARE REGISTER VALUES JNC NEXTFCB ;THERE IS ROOM FOR MORE MVI A,1 ;NO MORE ROOM...ABORT NOW STA ABORI 1AH RZ FORMFCB LXI D,HDFCB ;CLEAR THE FCB MVI B,36 XRA A ZEROFCB STAX D INX D DCR B JNZ ZEROFCB LHLD ADDR1 ;GET ADDRESS OF TABLE ENTRY LXI D,HDTYPE ;MOVE IN THE TYPE MVI B,3 CALL MOVE INX H INX H ;POSITION TO NAME INX H LXI D,HDFILE ;MOVE THE FILE NAME MVI B,8 CALL MOVE LXI D,8 DAD D ;POSITION TO DISK ID, A:, B: ETC LDA SRCE STA HDFCB LXI D,FPFCB ;COPY THE HDFCB TO THE FLOPPY FCB LXI H,HDFCB MVI B,36 CALL MOVE LDA DEST STA FPFCB LHLD ADDR1 CAL   L FORMAT LXI D,PRNTREC CALL OUTPUT LXI D,HDFCB ;OPEN THE SOURCE FILE DRIVE MVI C,0FH CALL BDOS INR A JZ NOTFOUND LXI D,FPFCB ;SEE IF THE FILE IS ON THE DESTINATION DRV MVI C,0FH CALL BDOS ;DUMMY OPEN INR A JZ MAKEIT ;NOT THERE...MAKE IT LHLD ADDR1 ;SET THE DRIVE BYTE (#12) TO '*' TO MARK LXI D,RECSIZE-1 ;THE FILE AS ALREADY BEING THERE SO THAT DAD D ;THE ERASE ROUTINE WILL NOT ERASE IT MVI A,'*' ;LATER WHEN REMOVING FILES MOV M,A HUH2 LXI D,ALRDYEXT ;FILE ALREADYL WRITEBUF ;WRITE MEMORY FILE LDA EOF CPI 1 JZ ENDOFFILE CPI 2 JZ DISKFULL JMP COPYLOOP ENDOFFILE LXI D,FPFCB ;CLOSE FLOPPY FILE MVI C,10H CALL BDOS ;CLOSE JMP NEXTFILE DISKFULL LXI D,FPFCB MVI C,13H ;DELETE FILE ON FLOPPY CALL BDOS LXI D,DSKFULL ;PRINT DISK FULL MESSAGE CALL OUTPUT RET NOTFOUND LHLD ADDR1 CALL FORMAT LXI D,NFMSG CALL OUTPUT LXI D,PRNTREC CALL OUTPUT RET ERASE EQU $ HUH LXI D,ERAMSG ;ASK IF YOU WANT THEM ERASED CALL QUESTION ORA A J ;CLEAR THE FCB MVI B,36 XRA A ZEROFCBX STAX D INX D DCR B JNZ ZEROFCBX LHLD ADDR1 LXI D,HDTYPE ;MOVE IN THE TYPE MVI B,3 CALL MOVE INX H INX H ;POSITION TO NAME INX H LXI D,HDFILE ;MOVE THE FILE NAME MVI B,8 CALL MOVE LXI D,8 DAD D ;POSITION TO DISK ID, A:, B: ETC MVI A,HARDISK STA HDFCB LHLD ADDR1 CALL FORMAT LXI D,PRNTREC CALL OUTPUT LXI D,HDFCB ;DELETE THE FILE ON FLOPPY IF IT MVI C,13H ;EXISTS CALL BDOS JMP ERANEXT * THE FOLLOWING ROUTINE ISORTED RETURN * *NOW THAT THIS LOGIC IS INTUITIVELY OBVIOUS, HERE'S THE NOT SO *OBVIOUS CODE: SORT LXI H,0000 ;INITIALIZE COUNT SHLD MAX1 ;SINCE IT WILL DECREMENT FIRST LXI D,-RECSIZE ;SUBTRACT RECSIZE FROM THE BEGINNING LXI H,RAM ;OF THE TABLE SINCE IT WILL ADD DAD D ;RECSIZE TO IT FIRST SHLD ADDR1 LOOP1 LHLD ADDR1 ;GET THE CURRENT ADDRESS LXI D,RECSIZE ;INCREMENT IT BY RECSIZE DAD D ;PAST THE NEXT ENTRY SHLD ADDR1 LHLD MAX1 ;SEE IF THE COUNT HAS REACHED THE LIMIT INX HLD MAX2 ;LIKEWISE SEE IF THE COUNTER FOR THE INX H SHLD MAX2 XCHG LHLD TABCNT CALL COMPREG JC LOOP1 ;WHEN FINISHED, INCREMENT OUTER LOOP LHLD ADDR2 XCHG ;ADDR2 NOW IN DE LHLD ADDR1 CALL COMPARE ;COMPARE STRINGS POINTED TO BY DE/HL JNC LOOP2 ;TABLE(HL) < TABLE (DE) * EXCHANGE THE TWO ENTRIES VIA A TEMPORARY RECORD LXI D,TEMP LHLD ADDR1 MVI B,RECSIZE CALL MOVE ;TEMP=TABLE(ADDR1) XCHG ;ADDR1=DESTINATION LHLD ADDR2 ;ADDR2=SOURCE CALL MOVE ;TABLE(ADDR1)=TABLE(ADDR2 EXISTS ON DESTINATION. ASK IF CALL QUESTION ;YOU WANT TO COPY THE NEW SOURCE OVER THE CPI 1 ;EXISTING COPY JNZ HUH2 LDA INREC CPI 'Y' JZ ERAIT ;ERASE IT CPI 'N' ;NO, USE THE COPY ALREADY ON THE DESTINATION JZ NEXTFILE JMP HUH2 ERAIT EQU $ LXI D,FPFCB ;DELETE THE FILE ON FLOPPY IF IT MVI C,13H ;EXISTS CALL BDOS MAKEIT EQU $ LXI D,FPFCB ;CREATE THE FILE ON FLOPPY MVI C,16H CALL BDOS ;MAKE FILE INR A JZ DISKFULL COPYLOOP CALL LOADBUFF ;LOAD MEMORY WITH FILE CALZ ERAALL LDA INREC CPI 'Y' JZ ERAALL CPI 'N' RZ JMP HUH ERAALL EQU $ LXI H,RAM ;SET THE ADDRESS OF THE FIRST ENTRY SHLD ADDR1 JMP PASSMOVEX ERANEXT EQU $ LHLD ADDR1 LXI D,RECSIZE DAD D SHLD ADDR1 PASSMOVEX LHLD ADDR1 MOV A,M CPI 1AH RZ LXI D,RECSIZE-1 ;SEE IF THE DRIVE INDICATOR IS SET TO '*' DAD D ;MEANING THE FILE WAS ALREADY ON THE HARD DISK MOV A,M ;SO IT WILL NOT BE DELETED CPI '*' JZ ERANEXT ;YES, IT WAS THERE, SO DO NOT ERASE IT FORMFCBX LXI D,HDFCB  A BUBBLE SORT. IN PSEUDOBASIC * IS WOULD BE DONE AS FOLLOWS: *SORT ADDR1=BOTTOM(RAM)-RECSIZE (RECSIZE IS COUNT OF BYTES IN ONE RECORD) * MAX1=0 *LOOP1 MAX1=MAX1+1 * ADDR1=ADDR1+RECSIZE (FIRST TIME THIS WOULD BE THE BOTTOM) * IF MAX1>TABCNT-1 THEN GO TO SORTED * ADDR2=ADDR1 * MAX2=MAX1 *LOOP2 MAX2=MAX2+1 * ADDR2=ADDR2+RECSIZE * IF MAX2>TABCNT THEN GO TO LOOP1 * IF TABLE(ADDR1) TABCNT - 1 ??? CALL COMPREG ;COMPARE DE (CURRENT COUNT) TO HL (TABCNT-1) JC SORTED ;FINISHED WHEN MAX1 > TABCNT-1 LHLD ADDR1 ;SETUP FOR THE INNER LOOP SHLD ADDR2 LHLD MAX1 SHLD MAX2 LOOP2 LHLD ADDR2 ;START WITH ONE ENTRY GREATER THEN LXI D,RECSIZE ;THE OUTER LOOP AND INCREMENT DAD D ;BY RECSIZE EACH TIME PAST THE NEXT RECORD SHLD ADDR2 ;POINTER TO THE CURRENT RECORD LH) XCHG ;ADDR2 = DESTINATION LXI H,TEMP CALL MOVE ;TABLE(ADDR2)=TEMP JMP LOOP2 SORTED RET ;FINISHED SORTING KILLDUPS EQU $ ;KILL DUPLICATE ENTRIES FROM MULTIPLE EXTENTS LXI H,RAM SHLD ADDR1 ;SET THE START OF THE TABLE NEXTEQUAL LHLD ADDR1 ;CHECK EACH ENTRY AGAINST THE NEXT LXI D,RECSIZE DAD D SHLD ADDR2 NEXTCHK MOV A,M ;CHECK FOR END OF TABLE CPI 1AH RZ XCHG LHLD ADDR1 ;COMPARE ADDR1 WITH ADDR2 MVI B,RECSIZE CALL COMPARE JNZ SAVELAST PUSH H ;SAVE CUR    RENT POSITION LHLD ADDR2 ;SET UP FOR MOVING LIST SHLD ADDR1 ;DOWN ONE ENTRY LXI D,RECSIZE DAD D ;MOVE THIRD ENTRY TO THE SECOND SHLD ADDR2 CALL MOVELIST LHLD TABCNT DCX H SHLD TABCNT POP H ;RESTORE CURRENT POSITION SHLD ADDR1 ;NOW COMPARE 1ST & 3RD JMP NEXTEQUAL SAVELAST LHLD ADDR2 ;MAKE NEW ONE THE CURRENT ONE SHLD ADDR1 JMP NEXTEQUAL ;COMPARE MOVELIST LHLD ADDR2 ;MOVE THE TABLE FROM ADDR2 DOWN XCHG ;TO ADDR1 THEREBY ELIMINATING LHLD ADDR1 ;UNWANTED ENTRECORD COUNT SHLD MAX1 LHLD TEMP ;SEE IF NEXT RECORD WOULD EXCEED THE LXI D,128 ;TPA AREA DAD D SHLD TEMP DAD D ;WILL THE NEXT RECORD OVERWRITE BDOS? XCHG LHLD BDOS+1 ;FIND THE TOP OF MEMORY CALL COMPREG ;COMPARE REGISTERS RC ;RETURN IF MEMORY ALREADY FULL JMP LOADNEXT ;GET ANOTHER RECORD HDEOF MVI A,1 ;SET FILE EOF STA EOF RET WRITEBUF EQU $ ;WRITE FROM THE MEMORY BUFFER LHLD ADDR3 SHLD TEMP LHLD MAX1 ;ALLOW FOR FILES THAT HAVE NO LXI D,0000 ;RECORDS SUCH ASB,3 ;FORMAT TO THE PRINT FORMAT CALL MOVE ;THE TABLE ADDRESS IS ASSUMMED TO BE LXI D,3 ;IN HL. FIRST MOVE THE TYPE DAD D ;NOW POSITION TO THE FILE NAME LXI D,PRNFILE ;MOVE THE FILE NAME MVI B,8 CALL MOVE LXI D,8 ;POSITION TO THE DISK ID DAD D LDA SRCE ORI 40H STA PRNTREC MVI A,':' STA PRNTREC+1 MVI A,'.' STA PRNTYPE-1 RET COMPREG MOV A,H ;COMPARE HL TO DE CMP D RNZ MOV A,L CMP E RET OUTPUT PUSH D ;PUT OUT A CRLF LXI D,CRLF MVI C,09 CALL BDOS POPMENT POP D POP H RET COMPARE PUSH H ;COMPARE THE STRINGS POINTED TO IN HL PUSH D ;TO THE STRING POINTED TO IN DE PUSH B ;FOR A LENGTH OF B CHARACTERS COMP1 LDAX D ; JC IF HL > DE CMP M ; JZ IF HL = DE JNZ COMP2 ;JNC IF HL < DE INX H INX D DCR B JNZ COMP1 COMP2 POP B POP D POP H RET SIGNON DB 'FLOPPY DISK COPY PROGRAM ' DB '1/8/82A$' ERRNOMSK DB 'ERROR...NO FILE MASK IN COMMAND' DB CR,LF,'COMMAND MUST BE IN THE FORMAT "FLOPCOPY *.*"' DB CR,LF,'$' TABFULL DB PRNTYPE DS 3 DB ' $' CRLFLFLF DB 0DH,0AH,0AH,0AH,'$' CRLF DB 0DH,0AH,'$' BIGMSG DB 0DH,0AH,'FILE TOO LARGE TO FIT ON ONE DISKETTE ' DB 'SO NOT BACKED UP **** $' HDFCB DS 1 HDFILE DS 8 HDTYPE DS 3 DS 24 FPFCB DS 36 SRCE DS 1 DEST DS 1 INBUF DB 30 INCNT DS 1 INREC DS 30 STACK DS 80 EOF DS 1 ABORT DS 1 LINECNT DS 1 LASTTYPE DS 3 LASTFILE DS 8 TABADDR DS 2 TABCNT DS 2 SELFLAG DS 1 TOOBIG DS 1 ADDR1 DS 2 ADDR2 DS 2 ADDR3 DS 2 MAX1 DS 2 MAX2 DS 2 RTYPE DS 3 RFILE DS 8 RIES MOVENEXT LDAX D ;AND MAKING MORE ROOM FOR THE MOV M,A CPI 1AH RZ INX H INX D JMP MOVENEXT * ASSORTED ROUTINES LOADBUFF EQU $ ;THIS ROUTINE LOADS AS MUCH OF LXI H,0000 ;MEMORY WITH THE FILE AS POSSIBLE SHLD MAX1 LHLD ADDR3 ;NEW TOP OF TABLE +2 SHLD TEMP XRA A STA EOF ;CLEAR EOF FLAG LOADNEXT LHLD TEMP XCHG ;SET DMA ADDRESS MVI C,1AH CALL BDOS LXI D,HDFCB ;READ HARD DISK MVI C,14H CALL BDOS ORA A JNZ HDEOF ;EOF? LHLD MAX1 INX H ;INCREMENT  RESTART CALL COMPREG RZ WRITENEXT LHLD TEMP XCHG ;SET DMA ADDRESS MVI C,1AH CALL BDOS LXI D,FPFCB MVI C,15H ;WRITE SEQUENTIAL CALL BDOS ORA A JNZ FPFULL ;FLOPPY DISK FULL LHLD MAX1 ;DECREASE RECORD COUNT DCX H SHLD MAX1 LXI D,0000 ;CHECK FOR NO MORE TO WRITE CALL COMPREG RZ LHLD TEMP LXI D,128 ;INCREMENT WRITE ADDRESS DAD D SHLD TEMP JMP WRITENEXT FPFULL MVI A,2 ;FULL DISKETTE STA EOF RET FORMAT LXI D,PRNTYPE ;FORMAT THE ENTRY FROM THE TABLE MVI  D ;NOW PUT OUT THE MESSAGE OUT1 MVI C,09 JMP BDOS QUESTION CALL OUTPUT ;PUT OUT THE QUESTION LXI D,INBUF MVI C,0AH ;INPUT THE REPLY CALL BDOS LDA INCNT ;SEE IF ANYTHING WAS ENTERED RET MOVE PUSH H ;MOVE DATA POINTED TO IN HL PUSH D ;TO THE AREA POINTED TO IN DE PUSH B ;BY THE BYTE COUNT IN B MOVE1 MOV A,M ANI 7FH ;RESET THE HIGH ORDER BIT BECAUSE IT ;MAY HAVE BEEN TURNED ON FOR THE TYPE STAX D INX H INX D DCR B JNZ MOVE1 POP B ;RESTORE THE TOTAL ENVIRON 'MEMORY FULL...REPORT NOT COMPLETE$' NFMSG DB 'FILE NOT FOUND...ABORTING$' DMNTMSG DB 'DISMOUNT DISKETTE AND ENTER RETURN$' ERAMSG DB 'ERASE COPIES ON THE HARD DISK (Y/N)? $' MNTBLANK DB 'MOUNT A FORMATTED BLANK DISKETTE AND ENTER RETURN$' ANOTHER DB 'WANT TO COPY THE SAME FILES ON TO ANOTHER DISKETTE (Y/N)? $' ALRDYEXT DB 'FILE ALREADY EXISTS ON DESTINATION DISK.' DB ' ENTER Y TO COPY OVER IT: $' DSKFULL DB 'DISKETTE FULL...REMAINING FILES IGNORED$' PRNTREC DS 1 DB ':' PRNFILE DS 8 DB '.'RDISK DS 3 DB '$' TEMP DS RECSIZE DISKBUF DS 128 COMPSIZE DS 1 CR EQU 0DH LF EQU 0AH RAM EQU $ END 100H NE DISKETTE ' DB 'SO NOT BACKED UP **** $' HDFCB DS 1 HDFILE DS 8 HDTYPE DS 3 DS 24 FPFCB DS 36 SRCE DS 1 DEST DS 1 INBUF DB 30 INCNT DS 1 INREC DS 30 STACK DS 80 EOF DS 1 ABORT DS 1 LINECNT DS 1 LASTTYPE DS 3 LASTFILE DS 8 TABADDR DS 2 TABCNT DS 2 SELFLAG DS 1 TOOBIG DS 1 ADDR1 DS 2 ADDR2 DS 2 ADDR3 DS 2 MAX1 DS 2 MAX2 DS 2 RTYPE DS 3 RFILE DS 8     FLOPCOPY.ASM FLOPPY DISK COPY PROGRAM USING 1 DRIVE AND A HARD DISK WRITTEN BY G. YOUNG, PO BOX 3218, NORTH HOLLYWOOD, CA 91609 FLOPCOPY IS A PROGRAM USED TO COPY ONE FLOPPY DISKETTE TO ANOTHER FLOPPY IN SYSTEMS THAT HAVE ONLY ONE FLOPPY DRIVE BUT HAVE A HARD DISK. IT WORKS AS FOLLOWS: READ THE DIRECTORY OF THE FLOPPY DISK USING THE MASK IN THE COMMAND TO CREATE A LIST OF FILES TO BE COPIED (EXAMPLE: FLOPCOPY *.ASC TO COPY ALL THE ASC FILES FROM ONE FLOPPY TO ANOTHER). THENILL ASK IF ADDITIONAL COPIES ARE TO BE MADE. IF NOT, THE FILES ARE DELETED FROM THE HARD DISK. IF THE FILE WAS ALREADY ON THE HARD DISK AS DETERMINED BY INDICATOR SET PREVIOUSLY, THE FILE WILL NOT BE DELETED. THE PROGRAM IS SMART ENOUGH TO DETECT A FULL DISKETTE CONDITION AND A COMMAND WITHOUT A MASK. W IN MEMORY, THE FILES ARE THEN COPIED FROM THE HARD DISK TO THE BLANK FLOPPY. WHEN ALL FILES HAVE BEEN COPIED, THE PROGRAM W .TITLE 'Sorted directory map program 2.1' ; ; ;15/08/82 Converted for use with MAC by Steven Engel. ; ; ORG 0100H BDOS EQU 5 ;bdos call address FCB EQU 05CH ;default fcb ; JMP START ; DB 'FMAP version 2.1 as of 15/08/82' ; ; GOOD FOR DIRECTORIES TO 256 ENTRIES ; START: LXI H,0 ;0 offset for stack DAD SP ;add to stack pointer SHLD STACK ;and save that spack LXI SP,STACK ;make a new stack LDA FCB+16 ;2ND UNIT PARAM. ORA A JZ NODEST STA MYFCB ;CHG OUTPUT DRIVE NODEST H INX H MOV A,M ;GET BLM INR A ;MAKE SECTORS/BLOCK RRC RRC RRC ;DIVIDE BY 8 FOR KB/BLK ANI 1FH STA BLKSIZ ;SIZE IN KBYTES INX H MOV A,M ;EXTENT MASK STA EXTMSK LDA BLKSIZ ;RESTORE SIZE INX H MOV E,M INX H MOV D,M ;DSM XCHG INX H ;TOTAL BLOCK COUNT SHLD BLKCNT ; OLDCPM: MVI C,17 ;SRCH FIRST LXI D,FCB CALL BDOS INR A PUSH PSW LXI D,TTL CALL WRCON CALL CR POP PSW JMP SOME ; TTL: DB 'Filename typ U EX RC -----extent-----' DB 'Ver. 2.1 1/18SPRINT: LHLD COUNT SHLD OCOUNT SHLD SCOUNT MOV A,H ORA L JZ NFEXIT LXI H,ORDER LXI D,TABLE LXI B,32 BLDORD: MOV M,E INX H MOV M,D INX H XCHG DAD B XCHG PUSH H LHLD OCOUNT DCX H SHLD OCOUNT MOV A,H ORA L POP H JNZ BLDORD LHLD COUNT DCX H MOV A,H ORA L JZ DONE SORT: XRA A STA SWITCH LHLD SCOUNT DCX H SHLD TEMP SHLD SCOUNT MOV A,H ORA L JZ DONE LXI H,ORDER SORTLP: CALL COMPR CM SWAP INX H INX H PUSH H LHLD TEMP DCX H SHLD , USING THE LIST IN MEMORY, COPY THE FILES FROM THE FLOPPY TO THE HARD DISK. IF THE FILE ALREADY EXISTS ON THE HARD DISK, ASK IF YOU WANT THE FILE COPIED OVER WITH THE FLOPPY VERSION AND SET AN INDICATOR IN THE FILE LIST THAT THIS FILE WAS ALREADY THERE. THEN THE PROGRAM WILL REQUEST THE BLANK DISKETTE THAT WILL BE THE DESTINATION DISK TO BE MOUNTED. USING THE FILE LIST NOW IN MEMORY, THE FILES ARE THEN COPIED FROM THE HARD DISK TO THE BLANK FLOPPY. WHEN ALL FILES HAVE BEEN COPIED, THE PROGRAM W: LDA FCB+17 STA FILESW ;FLAG FOR FILE WRITE MVI C,25 ;FIND LOGGED DISK CALL BDOS STA CDSK LDA FCB ORA A JNZ FSPEC2 ;NO DRIVE SPEC'D LDA CDSK INR A FSPEC2: DCR A ;ADJ FOR INPUT RNG MOV E,A MVI C,14 ;SELECT DRIVE WANTED CALL BDOS LXI H,FCB MVI M,'?' ;MATCH ALL ENTRIES MVI C,27 ;GET ALLOC VECT CALL BDOS SHLD ALLADR ;SAVE ALLOC PNTR. MVI C,12 ;FIND REVISION CALL BDOS ORA A JZ OLDCPM ;BEFORE 2.0 USE DFLTS MVI C,31 ;GET DPB ADDRESS CALL BDOS INX H INX/81$' MORDIR: MVI C,12H LXI D,FCB CALL BDOS INR A JZ SPRINT SOME: DCR A ANI 3 ADD A ADD A ADD A ADD A ADD A LXI H,80H ADD L MOV L,A MOV A,M CPI 0E5H JZ MORDIR MOV C,A ;SAVE USER INX H XCHG LHLD NEXTT MVI B,11 ; NAME TMOVE1: LDAX D ANI 7FH MOV M,A INX D INX H DCR B JNZ TMOVE1 MOV M,C ;USER INX H MVI B,20 ;OTHER BYTES TMOVE2: LDAX D MOV M,A INX D INX H DCR B JNZ TMOVE2 SHLD NEXTT LHLD COUNT INX H SHLD COUNT JMP MORDIR ; TEMP MOV A,H ORA L POP H JNZ SORTLP LDA SWITCH ORA A JNZ SORT DONE: LXI H,ORDER SHLD NEXTT LDA CDSK MOV E,A MVI C,14 ;SEL DSK CALL BDOS ;ORIG DRIVE LDA FILESW CPI 'F' ;46H JNZ ENTRY LXI D,MYFCB MVI C,13H CALL BDOS LXI D,MYFCB MVI C,16H CALL BDOS INR A JNZ ENTRY CALL ERXIT DB '++FILE MAKE ERROR$' ENTRY: MVI C,11 ;CONS STAT CALL BDOS DCR A JZ ABORT LHLD NEXTT MOV E,M INX H MOV D,M ;DE=ADDR OF ENTRY INX H SHLD NEXTT LXI H,11 ;USER OF   FSET DAD D MOV A,M ;USER BYTE ADI 90H DAA ACI 40H DAA MOV M,A ;NOW ASCII INX H MOV A,M ANA A JZ ENTRY2 LXI H,FILESW MOV A,M ORI 1 MOV M,A ENTRY2: XCHG JMP PTONE3 ; WRDEXT: INX H INR B MOV A,M CALL XOB JMP NXCLUS ; PTONE3: MVI B,8 CALL TYPEIT CALL PERIOD MVI B,3 CALL TYPEIT CALL SEMIC MVI B,1 CALL TYPEIT CALL FILECR MOV A,M CALL XOB INX H INX H INX H MOV A,M CALL XOB INX H LXI B,16<8+0 ;BYTES & SPACE FLG EXTLP: MOV A,M MOV E2: RLC ;BIT TO CY JNC LP1 ;UNUSED BLK DCX H ;COUNT OFF LP1: DCX D ;DECR TOTAL MOV C,A MOV A,D ORA E JZ CNTDUN ;FINISHED SCAN MOV A,C ;RESTORE DCR B JNZ LP2 XTHL INX H ;STEP TBL PTR JMP LP3 ; CNTDUN: XCHG ;COUNT IN DE POP H ;CLEAR UP STACK LDA BLKSIZ CALL MPY8 ;CALC IN KB CALL OUTNUM MVI B,8 LXI H,ROOM2 CALL TYPEIT CALL FILECR CALL CR LDA NFILE MOV L,A MVI H,0 CALL OUTNUM LXI D,NMSG CALL WRCON LDA FILESW ANI 0FEH CPI 'F' ;46H STA FTN01 MOV B,D OUTN02: POP PSW CALL NIBBL DCR B JNZ OUTN02 RET ; XOB: CALL XO JMP SPACE ; XO: PUSH PSW RAR RAR RAR RAR CALL NIBBL POP PSW ; NIBBL: ANI 0FH ADI 90H DAA ACI 40H DAA JMP FILC ; TYPE: PUSH B PUSH D PUSH H MOV E,A MVI C,2 CALL BDOS POP H POP D POP B RET ; WRCON: MVI C,9 JMP BDOS ; TYPEIT: MOV A,M CALL FILCHR CALL TYPE INX H DCR B JNZ TYPEIT RET ; SPACE: MVI A,' ' ;20H JMP TYPE ; SPACF: MVI A,' ' ;20H FILC: CALL  JZ WROK CALL ERXIT DB '++ Write error$' WROK: LXI H,80H SHLD BUFAD POP D POP B RET ; PERIOD: MVI A,'.' ;2EH CHCOM: CALL FILCHR JMP SPACE ; SEMIC: MVI A,';' JMP CHCOM ; FILECR: MVI A,0DH CALL FILCHR MVI A,0AH CALL FILCHR LDA FILESW ORI 1 STA FILESW JMP SPACE ; COMPR: PUSH H MOV E,M INX H MOV D,M INX H MOV C,M INX H MOV B,M XCHG CMPLP: LDAX B CMP M INX H INX B JZ CMPLP POP H RET ; SWAP: MVI A,1 STA SWITCH MOV C,M INX H PUSH H M,A CALL XO LDA EXTMSK ORA A JNZ WRDEXT INR C MOV A,C ANI 1 MOV C,A CZ SPACE NXCLUS: INX H DCR B JNZ EXTLP PUSH H LXI H,NFILE INR M CALL CR LDA FILESW ANI 0FEH STA FILESW LHLD COUNT DCX H SHLD COUNT MOV A,H ORA L POP H JNZ ENTRY ; DFEXIT: MVI B,2 LXI H,ROOM1 CALL TYPEIT LHLD BLKCNT MOV D,H MOV E,L ;TOTAL COUNTER IN DE PUSH H ;LEFT COUNTER ON STK LHLD ALLADR LP3: MVI B,8 ;BIT COUNT MOV A,M ;ALLOC BYTE XTHL ;SAVE PTR,GET LEFT CNT LPILESW JNZ EXIT MVI A,1AH CALL FILCHR CALL WRSEC LXI D,MYFCB MVI C,10H CALL BDOS JMP EXIT ; NMSG: DB ' Direct. Entries used$' ; NFEXIT: XRA A STA FILESW JMP DFEXIT ; DIVIDE: XRA A MVI B,10H DIV01: DAD H RAL CMP C JC DIV02 SUB C INX H DIV02: DCR B JNZ DIV01 RET ; MPY8: LXI H,0 MPY81: ORA A RZ RAR JNC MPY01 DAD D MPY01: XCHG DAD H XCHG JMP MPY81 ; OUTNUM: MVI D,0 MVI C,10 ;RADIX OUTN01: CALL DIVIDE PUSH PSW INR D MOV A,H ORA L JNZ OUFILCHS JMP TYPE ; CR: MVI E,0DH MVI C,2 CALL BDOS MVI E,0AH MVI C,2 JMP BDOS ; TEMP: DS 2 ; ERXIT: POP D MVI C,9 JMP CALLB ; ABORT: MVI C,1 CALLB: CALL BDOS EXIT: LHLD STACK SPHL RET ; FILCHR: CPI ' ' ;20H RZ FILCHS: PUSH PSW LDA FILESW CPI 'F' ;46H JNZ NOFILE POP PSW PUSH PSW PUSH H LHLD BUFAD MOV M,A INX H SHLD BUFAD MOV A,H DCR A CZ WRSEC POP H NOFILE: POP PSW RET ; WRSEC: PUSH B PUSH D LXI D,MYFCB MVI C,15H CALL BDOS ORA A OV B,M INX H MOV E,M MOV M,C INX H MOV D,M MOV M,B POP H MOV M,D DCX H MOV M,E RET ; DS 30 STACK: DS 2 NFILE: DB 0 ALLADR: DW 0 ;ALLOC VECT PTR BLKCNT: DW 0 BLKSIZ: DB 1 ;1.4 DEFAULT NEXTT: DW TABLE COUNT: DW 0 EXTMSK: DB 7 ;1.4 DEFAULT ROOM1: DB '[[' ROOM2: DB ']].LFT;0' SCOUNT: DW 0 OCOUNT: DW 0 CDSK: DB 0 SWITCH: DB 0 FILESW: DB 0C9H BUFAD: DW 80H MYFCB: DB 1 ;DRIVE A DEFAULT DB 'NAMES SUB' DB 0 DS 19 DB 0 ORDER: DS 512 ; TABLE EQU $ END    ; I/O-CAP.ASM Version 1.0 as of September 13, 1981 ; ; By: Kelly Smith, CP/M-Net ; ; Version 1.0: Initial release by Kelly Smith ; Version 1.1: modified size for LF ; added Apple ][ equates ; by Bill McGee (613-828-9130) ; Note: Please append any changes to I/O-CAP with a ; 'Version Log' and change comments (your name would be nice ; too) top-down from the initial Version 1.0 release. ; ; Running I/O-CAP (the first time) will relo unusually LARGE amount of ; relocation memory, because it must buffer the entire CP/M ; system image to high memory to save and restore all CCP and ; BDOS pointers as it captures each 16 sector block of console ; input or output...crude, but the ONLY other wait to do this ; would be to 'hot-patch' the CCP and BDOS 'on-the-fly' and ; that get's just a bit gruesome from a UNIVERSAL ; applications standpoint...It's much easier to just SYSGEN a ; smaller CP/M sys the BDOS stack was not saved and ; restored when saving the console buffer to disk. ; ; - Applications - ; ; (1) Don't have a printer, and want 'Hard Copy' of a user ; dialog with the system? Use I/O-CAP to creat it as a disk ; file...for instance, when making patches into 'uncertain' ; areas of the system with DDT (or SID, or whatever) you can ; keep a running history on disk of the patches AND their ; effects. ; ; (2) Need to show example of -CAP to record user console ; input, and check in from time-to-time to look at the system ; activity. Used in conjunction with BYE on a remote CP/M ; system, you can finally figure-out how that 'twit' clobbers ; your system from 3000 miles away...and NOT fill a room full ; of paper by logging all input to your printer. Note: Run ; I/O-CAP first, then BYE.COM to 'grab' the vectors set-up by ; the I/O-CAP program.The capture of incoming data will appear ; to be transparent to thg options: ; ; (1) DEBUG - I/O-CAP runs at 8000 Hex...about right for ; most small applications programs that use memory from 100 to ; 7FFF Hex in a 56K CP/M system. If FALSE, I/O-CAP runs above ; a 48K CP/M system (C800 Hex), with no restrictions on ; applications programs. ; ; (2) QUIET - If FALSE, rings the console bell just before it ; writes 2048 bytes of captured console INPUT or OUTPUT. ; ; (3) ERRDISP - If TRUE, I/O-CAP will display an 'OOPS...' ; message on tcate the ; CONIN, and CONOUT jump vectors to high memory and then ALL ; subsequent input or output (depending on conditional ; assembly switches) will be buffered (16 sectors) for ; eventual output to disk with a filename and type called ; USER.LOG. This file will then be updated as long as I/O-CAP ; is active in the system. Note: I/O-CAP may be made ; inactive by just type I/O-CAP again, to toggle it off (or ; on). ; ; I/O-CAP requires an tem than your actual maximum available ; memory, and then have I/O-CAP relocate itself above your ; BIOS. If anyone has a better way to do this WITHOUT this ; relocation crap, I would be eager to see it...I just got ; frustrated with trying to figure out what CP/M was doing ; internally to pursue it further...local stacks, pointers, ; etc.,...ARGH...so I took the easy way out. ; ; Thanks to Mike Karas for discovering the BDOS CALL ; contention problems whenconsole dialog for an article ; or book and you don't want to 'hand type' it in? Use I/O-CAP ; to creat the examples for you, and edit the dialog to suit ; your needs. ; ; (3) Need to know all the events in 'history form' leading ; to some bizarre system blow-up? Use I/O-CAP to record that ; history for you (but only if the blow-up is recoverable by ; NOT COLD BOOTING the system). ; ; (4) Want to (secretly) monitor the activities of other ; users of the system? Use I/Oe user, with a slight pause when it ; updates the USER.LOG file...but this only happens every 2048 ; character entrys, so it should generally go un-noticed. ; ; - Using I/O-CAP - ; ; Examine the various conditional assembly switches and ; set TRUE or FALSE depending on your requirements with your ; editor (ED.COM). Then assemble with ASM.COM (or MAC.COM), ; load it to creat a .COM file and then run. The conditional ; assembly switches allow the followinhe console if the disk or directory is full. ; ; (4) INPUT - If TRUE, only console keyboard INPUT is ; captured. Note: OUTPUT must be FALSE if INPUT is TRUE. ; ; (5) OUTPUT - If TRUE, both console keyboard INPUT and ; OUTPUT will be captured...uses 'gobs' of disk storage if you ; let I/O-CAP run for any length of time. Note: INPUT must be ; FALSE if OUTPUT is TRUE. ; ; (6) QUIT - If TRUE, when a Control-Z and Carriage Return are ; entered at the console keyboard, I/O-C   AP will append the ; USER.LOG file with a physical end-of-file (i.e., no further ; data will be displayed in USER.LOG although it may be ; physically appended to it)...Note: You must type I/O-CAP ; to CLOSE the current USER.LOG, and reset the disk to normal ; R/W status. Failure to do so will result in a R/O BDOS ; Error on any subsequent attempt to write to the disk by ; means other than I/O-CAP. ; ; (7) SYSLOG - If TRUE, creates USER.LOG as a $SYS (invisible ;  Kelly Smith, CP/M-Net ; ; ; ; define TRUE/FALSE assembly parameters ; true equ -1 ; define TRUE false equ not true; define FALSE debug equ true ; define DEBUG quiet equ false ; define QUIET (ring BELL, if not true) errdisp equ true ; define ERRDISP (display errors, if true) quit equ true ; define QUIT (EOF, if Control-Z found) syslog equ false ; define SYSLOG (make USER.LOG a $SYS file) APPLE equ true ; for Apple ][ with 56K Softcard CP/M ; >>> Note: only one of tse+5 resdsk equ 13 ; reset disk system offc equ 15 ; open file cffc equ 16 ; close file dffc equ 19 ; delete file rrfc equ 20 ; read record wrfc equ 21 ; write record mffc equ 22 ; make file sdma equ 26 ; set dma address ; ; secondary FCB field definitions ; fn equ 1 ; file name field (rel) ft equ 9 ; file type field (rel) ex equ 12 ; file extent field (rel) frc equ 15 ; file record count (rel) nr equ 32 ; next record field (rel) ; ; ASCII control characters ; cr equ 0dh ; carriage rl ; ending address of the program. The error message will not ; affect the assembly. make sure you have memory available up ; to the address shown. ; org base+100h ; ; Move 'I/O-CAP' program up to high ram and jump to it ; lxi h,0 ; save old stack pointer dad sp shld oldstk lxi sp,stack; make a new stack pointer lxi h,tbuf ; set pointer to tbuf shld ptr lxi h,0 ; set size = 0 shld size lhld base+1 ; get BIOS pointer lxi d,5 ; add bias to console status address dad d mu $ ; boundary memory marker ; offset equ dest-source ; relocation amount ; ; The following code gets moved to high ram located at "dest", ; where it is executed. C A U T I O N : if modifying anything ; in this program from here on: ALL labels must be of the form: ; ; label equ $+offset ; ; ...in order that the relocation to high ram work ; successfully. Forgetting to specify '$+offset' will cause ; the program to jmp into whatever is currently in low memory, ; with unpreto directory) file, so that 'secrecy' is maintained when ; capturing user input...be sure and rename USER.LOG to your ; 'private' name, or replace the TYPE command with MLIST.COM. ; ; Please send any changes, 'bug' reports, suggestions, ; comments, gripes or bitches to the CP/M-Net system, (805) ; 527-9321...have fun with this program. It's in the public ; domain, but NOT TO BE USED for COMMERCIAL BENEFIT. ; ; Best regards, ; ; he following two assembly switches may be true <<< ; input equ true ; define INPUT (I/O-CAP console input) output equ false ; define OUTPUT (I/O-CAP console output) ; if DEBUG dest equ 08000h ; running location of code endif ; DEBUG if not DEBUG dest equ 0c800h ; running location of code endif ; DEBUG ; ; BDOS entry point and function codes ; base equ 0 ; <<-- set to offset of CP/M for your ; system, standard systems are 0, some ; 'alternate' systems are 4200H ; bdos equ baeturn lf equ 0ah ; line feed bel equ 07h ; bell signal ; ; This program runs up in high ram. It gets there, by being ; moved there when 'I/O-CAP' is typed. Change the following ; equate to an area in your high memory where this program may ; patch itself in. Approximate memory requirements: 2k bytes ; or more, depending upon the options selected. a marker has ; been placed at the end to deliberately print an error ; message during assembly in order to determine the actuaov d,m ; save in [d] lhld newjtbl+1 ; see if vector addresses active mov a,h ; been patched by previous execution? cmp d jz unpatch ; un-patch, if so lxi b,pend-start+1 ; number of bytes to move lxi h,dest+pend-start+1 ; end of moved code lxi d,source+pend-start ; end of source code ; mvlp ldax d ; get byte dcx h ; bump pointers mov m,a ; new home dcx d dcx b ; bump byte count mov a,b ; check if zero ora c jnz mvlp ; if not, do some more pchl ; do it, to it... ; source eqdictable results. Be careful.... ; start equ $+offset ; ; patch in the new jump table (saving the old) ; patch equ $+offset call tbladdr ; calc [hl] = CP/M jmp table lxi d,vcstat ; point to save location call move ; move it ; ; now move new jump table to CP/M ; call tbladdr ; calc [hl] = CP/M's jmp table xchg ; move to de lxi h,newjtbl ; point to new call move ; move it lxi h,active$message call msgout lhld oldstk ; get old CP/M stack pointer sphl ret ; unpatch    equ $+offset call reset ; reset disk in case it's R/O lxi h,inactive$message call msgout call tbladdr ; [hl] = CP/M's jmp table xchg ; move to de lxi h,vcstat ; get saved table call move ; move orig back lhld oldstk ; get old CP/M stack pointer sphl ret ; ; calculate [hl] = CP/M's jump table, [b] = length ; tbladdr equ $+offset lhld base+1 ; get BIOS pointer inx h ; ..skip inx h ; ..to inx h ; ..console status mvi b,9 ; move console jump vectors ret ; ; movm ; get character from message string ora a ; all of string displayed? rz ; return, if so inx h ; no, bump pointer for next character mov c,a ; pass character to 'old' BIOS vector call conout jmp msgout ; display next character in message string ; ; This area is used for vectoring calls to the user's CBIOS, ; but saving the registers first in case they are destroyed. ; constat equ $+offset push b push d push h call vcstat pop h pop d pop b ret ; conin equ $+offset ut routine endif ; INPUT if OUTPUT jmp capture ; console I/O-CAP output routine endif ; OUTPUT ; capture equ $+offset push h push d push b lxi h,0 ; save old stack pointer dad sp shld oldstk lxi sp,stack; make a new stack pointer if INPUT call vcin ; get console input mov c,a ; save in [c] for 'save' push psw ; and save on the stack endif ; INPUT call save ; save characters in buffer if INPUT pop psw ; get console input of the stack endif ; INPUT l lhld ptr ; here endif ; INPUT notcr equ $+offset; make label for next instruction... if QUIT mov a,c cpi 'Z'-40h ; control-Z? jz wtb ; write buffer, if so endif ; QUIT shld ptr lxi d,endmark ; get 'endmark' for buffer top address mov a,d cmp h ; getting near the end of buffer yet? rnz ; if not, just return mov a,e ; very near the top now, final address loaded? cmp l rnz ; if not, just return if not QUIET mvi c,bel ; warn user that we need to write to disk calln case it's R/O call open ; attempt to open USER.LOG inr a ; check CP/M return code jnz makeok ; USER.LOG already exist? ; nolog: equ $+offset ; call make ; make new file inr a ; check CP/M return code jnz makeok if ERRDISP lxi h,dirful; oops...can't make file, return to CP/M call msgout endif ; ERRDISP jmp base ; ; USER.LOG exists, so set the FCB entry for next append to file ; makeok: equ $+offset ; lda fcb+frc ; get record count sta fcb+nr ; make next record lhld e [hl] to [de], length in [b] ; move equ $+offset mov a,m ; get a byte stax d ; put at new home inx d ; bump pointers inx h dcr b ; decrement byte count jnz move ; if more, do it ret ; if not, return ; ; move [hl] to [de], length in [bc] ; movecpm equ $+offset mov a,m ; get a byte stax d ; put at new home inx d ; bump pointers inx h dcx b ; decrement byte count mov a,b ora c jnz movecpm ; if more, do it ret ; if not, return ; msgout equ $+offset mov a, push b push d push h call vcin pop h pop d pop b ret ; conout equ $+offset push b push d push h call vcout pop h pop d pop b ret ; ; This is the jump table which is copied on top of the one ; pointed to by location 1 in CP/M ; newjtbl equ $+offset jmp constat ; console status test if INPUT jmp capture ; console input I/O-CAP routine endif ; INPUT if OUTPUT jmp conin ; console input routine endif ; OUTPUT if INPUT jmp conout ; console outphld oldstk ; get old CP/M stack pointer sphl pop b pop d pop h if OUTPUT jmp vcout endif ; OUTPUT if INPUT ret endif ; INPUT ; save: equ $+offset lhld size ; size = size + 1 inx h shld size lhld ptr mov m,c inx h if INPUT mov a,c cpi cr ; carriage return? jnz notcr mvi m,lf ; yes, so add line feed because CP/M does not inx h ; bump pointer, for next time thru shld ptr ; added for 1.1 to lhld size ; / inx h ; / shld size ; /  conout endif ; QUIET ; ; wtb - write text buffer to disk ; wtb: equ $+offset IF NOT APPLE lhld base+6 ; get warm boot address for next bias to CCP lxi d,0fffah; make bias to CCP dad d ; add bias to [hl] lxi b,1600h ; make quantity to move lxi d,cpmbuf; buffer all of CP/M system call movecpm ; move it... ENDIF IF APPLE lxi h,0CC00h lxi b,1400h lxi d,cpmbuf call movecpm lxi h,0F000h lxi b,1000h lxi d,cpmbuf1 call movecpm ENDIF ; APPLE call reset ; reset disk isize ; [de] = tbuf size xchg lxi h,dbuf ; top of stack points to dbuf push h lxi h,tbuf ; [hl] points to tbuf ; wtb1: equ $+offset mvi c,128 ; disk buffer size ; wtb2: equ $+offset mov a,m ; fetch next byte of tbuf inx h xthl mov m,a ; store in dbuf inx h xthl dcx d ; size = size - 1 mov a,d ; exit loop if size = 0 ora e jz wtb3 dcr c ; loop until dbuf full jnz wtb2 call setdma ; set dma to dbuf call write ; write full dbuf to disk push psw ; save possible error    code lda fcb+frc ; get record count sta fcb+nr ; make next record pop psw ; get possible error code ora a ; check CP/M return code jz nextbuf if ERRDISP lxi h,dskful; oops...disk is full call msgout endif ; ERRDISP jmp base ; nextbuf equ $+offset ; xthl ; top of stack points to dbuf lxi h,dbuf xthl jmp wtb1 ; loop until end of tbuf ; wtb3: equ $+offset pop h ; [hl] points to current place in dbuf ; wtb4: equ $+offset mvi m,'Z'-40h ; store eof code inx h dc h,0 shld size wtb5: equ $+offset IF NOT APPLE lhld base+6 ; get warm boot address for next bias to CCP lxi d,0fffah; make bias to CCP dad d ; add bias to [hl] lxi b,1600h ; make quantity to move lxi d,cpmbuf; buffer all of CP/M system xchg ; swap call movecpm ; move it... ENDIF IF APPLE lxi h,0CC00h lxi b,1400h lxi d,cpmbuf xchg call movecpm lxi h,0F000h lxi b,1000h lxi d,cpmbuf1 xchg call movecpm ENDIF ; APPLE ret ; ; reset - reset disk ; reset: equ $+bdos pop b pop d pop h ret ; ; delt - delete disk file ; delt: equ $+offset push h push d push b lxi d,fcb mvi c,dffc call bdos pop b pop d pop h ret ; ; write - write record to disk ; write: equ $+offset push h push d push b lxi d,fcb mvi c,wrfc call bdos pop b pop d pop h ret ; ; make - make new disk file ; make: equ $+offset push h push d push b lxi d,fcb mvi c,mffc call bdos pop b pop d pop h ret ; ; setdma - set dm+80h,'G' endif ; SYSLOG if not SYSLOG db 'USER LOG' endif ; SYSLOG db 0,0,0,0,0,0,0,0,0,0 ; pend equ $+offset; end of relocated code ; ; data area ; ds 128 ; 64 level stack stack equ $+offset;local stack ; ptr: equ $+offset ds 2 ; text buffer pointer ; size: equ $+offset ds 2 ; text buffer size ; ; Save the CP/M jump table here ; vcstat equ $+offset ds 3 ; vcin equ $+offset ds 3 ; vcout equ $+offset ds 3 ; oldstk equ $+offset ds 2 ; storage for old CP/M r c ; loop thru rest if dbuf jnz wtb4 call setdma ; set dma to dbuf call write ; write last sector to disk push psw ; save possible error code lda fcb+frc ; get record count sta fcb+nr ; make next record pop psw ; get possible error code ora a ; check CP/M return code jz closeup if ERRDISP lxi h,dskful; oops...disk is full call msgout endif ; ERRDISP jmp base ; closeup equ $+offset ; call close ; clean up act and go home lxi h,tbuf ; clear text buffer shld ptr lxioffset push h push d push b mvi c,resdsk call bdos pop b pop d pop h ret ; ; open - open disk file ; open: equ $+offset push h push d push b lxi d,fcb mvi c,offc call bdos pop b pop d pop h ret ; ; read - read record from disk file ; read: equ $+offset push h push d push b lxi d,fcb mvi c,rrfc call bdos pop b pop d pop h ret ; ; close - close disk file ; close: equ $+offset push h push d push b lxi d,fcb mvi c,cffc call a address for disk file ; setdma: equ $+offset push h push d push b lxi d,dbuf mvi c,sdma call bdos pop b pop d pop h ret ; if ERRDISP dskful: equ $+offset db cr,lf,bel,'OOPS...disk is full!',0 ; dirful: equ $+offset db cr,lf,bel,'OOPS...directory is full!',0 endif ; ERRDISP ; active$message equ $+offset db ' (Active)',0 ; inactive$message equ $+offset db ' (Inactive)',0 ; fcb equ $+offset db 0 ; default drive specifier if SYSLOG db 'USER L','O'stack pointer ; IF NOT APPLE cpmbuf equ $+offset ds 1600h ; storage CP/M system image ENDIF IF APPLE cpmbuf equ $+offset ds 1400h cpmbuf1 equ $+offset ds 1000h ENDIF ;APPLE ; dbuf equ $+offset ds 128 ; secondary disk buffer address ; tbuf: equ $+offset ds 16*128 ; I/O-CAP storage for 16 sectors (2048 bytes) ; endmark equ $+offset;! ignore error - this marks end of program ; end    ; ; Program: XLATE2 ; Author: Richard Conn ; Derivation: Disassembled XLATE.COM of Cromemco's CDOS and Modified ; into XLATE2; XLATE.COM was Version 2.40 ; Version: 1.1 ; Date: 21 July 82 ; Previous Versions: 1.0 (3 May 82) ; ; XLATE2 inputs an Intel-Standard 8080 Assembly Language Source File ; and converts it into a Zilog-Standard Z80 Assembly Language Source File. ; VERS EQU 11 ;VERSION NUMBER ; ; USE ZILOG MNEMONICS AND ABSOLUTE SEGMENTS ; .Z80 ASEG ; ; CP/M CONST NEW OP = 5) CALL CMPOP ;SCAN FOR MATCH IN INLN BUFFER JP Z,DOOCS1 ;PROCESS IF FOUND ; LD HL,OCS2 ;PROCESS OP CODE SET 2 LD BC,10 ;10 CHARS/DUAL ENTRY CALL CMPOP ;SCAN FOR MATCH JP Z,DOOCS2 ;PROCESS ; LD HL,OCS3 ;PROCESS OP CODE SET 3 LD BC,10 ;10 CHARS/DUAL ENTRY CALL CMPOP ;SCAN FOR MATCH JP Z,DOOCS3 ;PROCESS ; LD HL,OCS4 ;PROCESS (EXTENDED RET) OP CODE SET 4 LD BC,5 ;5 CHARS/SINGLE ENTRY CALL CMPOP ;SCAN FOR MATCH CALL Z,DOOCS4 ;CONVERT INTO STANDARD RET FORMS IF MATCH ; ESS ; ; NO MATCH IN OP CODE SETS -- PASS TARGET OP CODE AS IS ; LD B,5 ;5 CHARS IN TARGET LD HL,TARGOP ;POINT TO TARGET POPS1: LD A,(HL) ;GET CHAR CP ' ' ;END OF OP? JR Z,POPS2 ;OUTPUT TAB CHAR IF SO CP 9 ;END OF OP? JR Z,POPS2 ;OUTPUT TAB CHAR IF SO CALL DOUTCHAR ;OUTPUT OP CHAR INC HL ;PT TO NEXT DJNZ POPS1 ;CONTINUE FOR 5 CHARS MAX POPS2: LD A,9 ;END OP WITH CALL DOUTCHAR ;OUTPUT TO DISK ; ; COPY REST OF INPUT LINE AS-IS ; COPYARGS: LD HL,(INLNPTR) ;PT TO NEXT C PUSH HL CALL SKIPWHITE ;SKIP TO NEXT NON-WHITE CHAR POP HL CP 0DH ;END OF LINE? JR Z,FLUSHLINE ;FLUSH IF SO CP ';' ;COMMENT? JR Z,CARGS5 ;PROCESS COMMENT IF SO CALL OUTWHITE ;OUTPUT A TAB JR CARGS2 ;RESTART PROCESSING CARGS5: DEC C INC C JR NZ,CARGS3 CALL SKIPWHITE LD B,41 CARGS6: LD A,(OBUFLPOS) ;CHECK POSITION IN OUTPUT LINE CP B JR NC,FLUSHLINE DEC A ;BACK UP IN OUTPUT LINE AND 0F8H ;ARTIFICALLY TAB ADD A,9 CP B JR Z,FLUSHLINE JR C,CARGS7 LD A,' ' JR CALL PMSG LD A,60 ;RESET COUNTER LD (NLCOUNT),A RET ; ; OUTPUT STRING PTED TO BY HL TO DISK (STRING ENDS IN 0) ; OUTSTR: LD A,(HL) ;GET CHAR AND A ;DONE? RET Z ;RET IF SO CALL DOUTCHAR INC HL ;PT TO NEXT CHAR JR OUTSTR ; ; OUTPUT ALL AND CHARS FOUND UNTIL A NON- AND NON- ; ENCOUNTERED ; OUTWHITE: LD A,(HL) ;GET CHAR CP ' ' ;? JR Z,OW1 ;OUTPUT IT CP 9 ;? RET NZ ;DONE IF NOT OW1: CALL DOUTCHAR ;OUTPUT CHAR IN A TO DISK INC HL ;PT TO NEXANTS ; WBOOT EQU 0 BDOS EQU 5 DEFFCB EQU 5CH FCB2 EQU 6CH ; ; START OF PROGRAM ; ORG 100H CALL HCHECK ;CHECK FOR HELP REQUEST LD SP,OBUFLPOS ;INIT STACK PTR CALL INIT ;INIT THE PROGRAM LOOP: CALL BUILDLINE ;BUILD THE NEXT INPUT LINE CALL PROCESSOPS ;CONVERT THE OP CODES JR LOOP ; ; MAIN PROCESSING MODULE ; PROCESSOPS: CALL GETOP ;EXTRACT THE NEXT OP CODE JP Z,FLUSHLINE ;IF NONE, FLUSH ; LD HL,OCS1 ;PROCESS OP CODE SET 1 LD BC,10 ;10 CHARS/DUAL ENTRY (OLD OP = 5, LD HL,RETS ;PROCESS (NORMAL RET) OP CODE SET 5 LD BC,5 ;5 CHARS/SINGLE ENTRY CALL CMPOP ;SCAN FOR MATCH JP Z,DORETS ;PROCESS ; LD HL,CALLS ;PROCESS (CALL) OP CODE SET 6 LD BC,5 ;5 CHARS/SINGLE ENTRY CALL CMPOP ;SCAN FOR MATCH JP Z,DOCALLS ;PROCESS ; LD HL,JMPS ;PROCESS (JMP) OP CODE SET 7 LD BC,5 ;5 CHARS/SINGLE ENTRY CALL CMPOP ;SCAN FOR MATCH JP Z,DOJMPS ;PROCESS ; LD HL,OCS8 ;PROCESS OP CODE SET 8 LD BC,12 ;12 CHARS/DUAL ENTRY CALL CMPOP ;SCAN FOR MATCH JP Z,DOOCS8 ;PROCHAR CARGS1: LD C,0 CARGS2: LD A,(HL) ;GET CHAR CP ' ' ;END OF OPERANDS? JR Z,CARGS4 ;SKIP WHITE SPACE AND OUTPUT REST IF SO CP 9 ;END OF OPERANDS? JR Z,CARGS4 ;SKIP WHITE SPACE AND OUTPUT REST IF SO CP 0DH ;END OF LINE? JR Z,FLUSHLINE ;FLUSH IF SO CP ';' ;BEGINNING OF COMMENT = END OF OPERANDS? JR Z,CARGS5 ;COPY REST IF SO CP '''' ;SINGLE QUOTE? JR NZ,CARGS3 DEC C JR Z,CARGS3 LD C,1 CARGS3: CALL DOUTCHAR ;OUTPUT CHAR IN A TO DISK INC HL ;PT TO NEXT JR CARGS2 CARGS4: RGS8 CARGS7: LD A,9 CARGS8: CALL DOUTCHAR JR CARGS6 ; ; WRITE REST OF INLN TO DISK ; FLUSHLINE: CALL OUTSTR LD A,1 ;RESET POSITION COUNTER LD (OBUFLPOS),A RET ; ; PRINT PDOT FOR EVERY TEN LINES ; PDOT: LD A,(LCOUNT) ;GET LINE COUNT DEC A ;COUNT DOWN LD (LCOUNT),A ;PUT LINE COUNT RET NZ ;DONE IF NOT ZERO LD A,'.' ;PRINT PDOT CALL PCHAR LD A,10 ;RESET COUNT LD (LCOUNT),A LD A,(NLCOUNT) ;NEW LINE? DEC A LD (NLCOUNT),A RET NZ LD DE,CRLFSTR ;PRINT NEW LINE CAT CHAR JR OUTWHITE ;CONTINUE ; ; EXTRACT OP CODE FOR INPUT LINE AND PLACE IN BUFFER ; GETOP: LD HL,INLN ;PT TO INPUT LINE LD A,(HL) ;GET 1ST CHAR IN LINE CP ' ' ;NO LABEL? JR Z,GOP3 ;SKIP TO OP CODE CP 9 ;NO LABEL? JR Z,GOP3 ;SKIP TO OP CODE CP ';' ;COMMENT? RET Z ;DONE IF SO ; ; LINE BEGINS WITH A LABEL -- PROCESS IT ; GOP1: LD C,0 ;SET LABEL CHAR CNT GOP2: LD A,(HL) ;GET NEXT CHAR OF LABEL CP ':' ;END OF LABEL? JR Z,GOP4 CP 9 ;END OF LABEL? JR Z,GOP5 CP 0DH ;END    OF LABEL AND NO FURTHER PROCESSING? JR Z,GOP5 CP ';' ;END OF LABEL AND NO FURTHER PROCESSING? JR Z,GOP5 CP ' ' ;END OF LABEL? JR Z,GOP5 CALL DOUTCHAR ;OUTPUT LABEL CHAR TO DISK INC HL ;PT TO NEXT CHAR INC C ;INCR LABEL CHAR CNT JR GOP2 ; ; NO LABEL -- SKIP TO OP CODE ; GOP3: CALL SKIPWHITE ;SKIP OVER WHITE SPACE PUSH HL CALL FTODLM CP ':' POP HL JR Z,GOP1 JR GOP7 ; ; END OF LABEL BY ':' CHAR ; GOP4: INC HL ;SKIP ':' CALL DOUTCHAR ;OUTPUT THE ':' LD A,(HL) ;CHECHAR LD A,0AH ; CALL DOUTCHAR ; ; OUTPUT AFTER LABEL TO DISK ; GOP7: LD A,9 ; CALL DOUTCHAR ; ; SKIP TO OP CODE FIELD AND EXTRACT IT IF PRESENT ; GOP8: CALL SKIPWHITE ;SKIP TO OP CODE FIELD LD A,(HL) ;GET FIRST NON-WHITE CHAR CP ';' ;NO OP CODE IF COMMENT RET Z ;DONE IF COMMENT CP 0DH ;NO OP CODE IF EOL RET Z ;DONE IF EOL LD (ILTOP),HL ;SAVE PTR TO TARGET OP CODE LD B,5 ;5 CHARS MAX IN OP CODE LD DE,TARGOP ;COPY TO TARGOP BUFFER CALL COPYTODELIM ;COPY UNT JR CMPOP CMPOP1: INC A ;A=1 AND NZ RET ; ; PROCESS OP CODES IN SET 1 -- OPERAND AND COMMENTS FIELDS ARE UNCHANGED ; HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK ; DOOCS1: CALL OUTNEWOP5CH ;OUTPUT NEW OP CODE JP COPYARGS ;COPY OPERAND AND COMMENT FIELDS AS-IS ; ; OUTPUT 2ND 5-CHAR-MAX OP CODE FIELD PTED TO BY HL TO DISK AND END IN ; OUTNEWOP5CH: LD BC,5 ;SKIP FIRST 5 CHARS ADD HL,BC ;PT TO 2ND 5-CHAR FIELD ; ; ENTRY PT TO COPY 5-CHAR-MAX FIELD PD HL,(INLNPTR) ;PT TO OPERAND FIELD ATHLCHECK: LD A,(HL) ;CHECK FOR '(HL)' REFERENCE CP 'M' ;TAKES THE FORM OF 'M' IN 8080 MNEMONICS JP NZ,CARGS1 ;OUTPUT NORMALLY IF NOT INC HL ;PT TO CHAR AFTER PUSH HL ;SAVE PTR LD HL,ATHL ;OUTPUT '(HL)' CALL OUTSTR ;OUTPUT TO DISK POP HL ;GET PTR JP CARGS1 ;PROCESS REST OF LINE NORMALLY ATHL: DB '(HL)',0 ; ; PROCESS OP CODES IN SET 3 - OPERAND IS BC, DE, HL, OR PSW REG PAIR ; HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DRE IF NOT POP HL ;IT IS 'PSW', SO CLEAR STACK AND PT INC HL ; ... TO CHAR AFTER 'PSW' INC HL PUSH HL LD HL,AFSTR ;PRINT 'AF' JR PRREGPAIR ;DO PRINT PRBC: LD HL,BCSTR ;PRINT 'BC' JR PRREGPAIR PRDE: LD HL,DESTR ;PRINT 'DE' JR PRREGPAIR PRHL: LD HL,HLSTR ;PRINT 'HL' PRREGPAIR: CALL OUTSTR ;PRINT STRING PTED TO BY HL AND MAKE HL ON STACK POP HL ; ... PT TO NEXT CHAR INC HL PUSH HL L0309: POP HL ;PRINT WHATEVER OTHER OPERAND IT IS JP CARGS1 ;PRINT THE OPERAND AFSTR: DBCK FOR EOL CP 0DH ;DON'T DOUBLE NEW LINE (SKIP NEW LINE AFTER GOP6) JR Z,GOP8 ;JUST CONTINUE PROCESSING WITH NO TAB JR GOP6 ;NOT NEW LINE, SO PROCESS FOR NEW LINE IF LONG LABEL ; ; OUTPUT ':' AT END OF LABEL ; GOP5: LD A,':' ;OUTPUT THE ':' CALL DOUTCHAR ; ; SEE IF LABEL IS LESS THAN 7 CHARS LONG ; IF <7, THEN TERMINATE WITH ; IF >6, THEN NEW LINE AND ; GOP6: LD A,C ;GET LABEL CHAR CNT CP 7 ;LESS THAN 7? JR C,GOP7 ;JUST TAB IF LESS THAN 7 LD A,0DH ; CALL DOUTIL DELIMITER ENCOUNTERED CALL SKIPWHITE ;SKIP OVER WHITE SPACE WHICH FOLLOWS LD (INLNPTR),HL ;SAVE PTR SUB A INC A ;A=1 AND NZ RET ; ; COMPARE OP CODE PTED TO BY HL WITH TARGET OP CODE; RET WITH Z SET IF ; MATCH, NZ IF NO MATCH ; CMPOP: LD A,(HL) ;NO OP CODE TO COMPARE? AND A ;A=0 IF SO JR Z,CMPOP1 ;FAILURE IF SO PUSH BC LD B,5 ;COMPARE 5 BYTES LD DE,TARGOP ;PT TO TARGET OP CODE CALL COMPHLDE ;COMPARE POP BC RET Z ;DONE IF MATCH ADD HL,BC ;PT TO NEXT OP CODE IN TABLE TED TO BY HL ; ONO5C0: LD B,5 ONO5C1: LD A,(HL) ;GET NEXT CHAR CP ' ' ;? JR Z,ONO5C2 ;DONE IF SO CP 9 ;? JR Z,ONO5C2 ;DONE IF SO CALL DOUTCHAR ;OUTPUT CHAR TO DISK INC HL ;PT TO NEXT DJNZ ONO5C1 ;COUNT DOWN ONO5C2: LD A,9 ;OUTPUT TO DISK JP DOUTCHAR ;OUTPUT TO DISK ; ; PROCESS OP CODES IN SET 2 - OPERAND IS 1 REG OR '(HL)' ; HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK ; DOOCS2: CALL OUTNEWOP5CH ;OUTPUT NEW 5-CHAR-MAX OP CODE LISK ; DOOCS3: CALL OUTNEWOP5CH ;OUTPUT NEW OP CODE RPCHECK: LD HL,(INLNPTR) ;PT TO OPERAND FIELD PUSH HL ;SAVE PTR LD A,(HL) ;GET OPERAND CP 'B' ;FOR BC? JR Z,PRBC ;OUTPUT BC IF SO CP 'D' ;FOR DE? JR Z,PRDE ;OUTPUT DE IF SO CP 'H' ;FOR HL? JR Z,PRHL ;OUTPUT HL IF SO CP 'P' ;FOR PSW? JR NZ,L0309 ;OUTPUT WHATEVER'S THERE IF NOT INC HL ;MAKE SURE IT IS 'PSW' LD A,(HL) CP 'S' JR NZ,L0309 ;OUTPUT WHAT'S THERE IF NOT INC HL LD A,(HL) CP 'W' JR NZ,L0309 ;OUTPUT WHAT'S THE 'AF',0 BCSTR: DB 'BC',0 DESTR: DB 'DE',0 HLSTR: DB 'HL',0 ; ; PROCESS OP CODE SET 4 - EQ, NE, LT, GE RETS, CALLS, AND JMPS ; HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK ; DOOCS4: LD A,(TARGOP+1) ;LOOK AT 2ND LETTER OF TARGET OP LD HL,ZFLG ;PREP FOR ZERO CP 'E' ;IF 'E', THEN FORM IS 'EQ' JR Z,ZCPUT ;CHANGE FORM TO 'XZ ', WHERE X=R,C,J LD HL,NZFLG ;PREP FOR NOT ZERO CP 'N' ;IF 'N', THEN FORM IS 'NE' JR Z,ZCPUT LD HL,CFLG ;PREP FOR CARRY CP 'L' ;   IF 'L', THEN FORM IS 'LT' JR Z,ZCPUT LD HL,NCFLG ;FORM MUST BE 'GE', SO NO CARRY ZCPUT: LD A,(HL) ;GET FIRST CHAR LD (TARGOP+1),A ;STORE IT INC HL ;PT TO 2ND CHAR LD A,(HL) ;GET IT LD (TARGOP+2),A ;STORE IT RET ZFLG: DB 'Z ' NZFLG: DB 'NZ' CFLG: DB 'C ' NCFLG: DB 'NC' ; ; PROCESS OP CODE SET 5 -- RETURN FORMS ; HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK ; DORETS: LD HL,RETSTR ;PT TO STR TO COPY CALL COPY5 ;COPY WITH OPTIONAL COND JP COWED BY AND 2-CHAR COND ; COPY5: CALL ONO5C0 ;COPY 5-CHAR-MAX STRING PTED TO BY HL LD A,(TARGOP+1) ;OUTPUT FIRST CHAR OF COND CALL DOUTCHAR LD A,(TARGOP+2) ;OUTPUT 2ND CHAR OF COND IF NOT CP ' ' RET Z JP DOUTCHAR ; ; PROCESS OP CODE SET 8 - THIS TABLE CONTAINS THE SERVICE ROUTINE ADR ; EMBEDDED IN IT AFTER EACH OP CODE PAIR; ; HL PTS TO OP CODE TABLE ENTRY, 2ND ELT OF WHICH IS TO BE OUTPUT TO DISK ; DOOCS8: PUSH HL ;SAVE PTR TO OLD (1ST) OP LD BC,10 ;PT TO ADR OF S>' LD HL,DO82S ;OUTPUT 'A,' JP DO8F1 ;04C7H DO82S: DB 'A,',0 ; ; THIS CONVERTS 'LDA ' TO 'LD A,()' ; AND 'IN ' TO 'IN A,()' ; DO83: CALL OUTNEWOP5CH LD HL,DO83S JR OUTCLP DO83S: DB 'A,(',0 ; ; THIS CONVERTS 'LDAX ' TO 'LD A,()' ; DO84: CALL OUTNEWOP5CH ;OUTPUT OP CODE LD HL,(INLNPTR) ;PT TO OPERAND LD A,(HL) ;GET 1ST CHAR OF OPERAND CP 'B' ;BC REG PAIR? JR Z,DO841 ;PROCESS IT CP 'D' ;DE REG PAIR? JR Z,DO842 ;PROCESS IT JP CARGS1 ;SOME DO85S: DB 'HL,(',0 ; ; THIS CONVERTS 'MOV R,R' TO 'LD R,R' ; DO86: CALL OUTNEWOP5CH LD HL,(INLNPTR) ;PT TO 1ST CHAR OF OPERAND FIELD LD A,(HL) ;GET IT CP 'M' ;CONVERT 'M' TO '(HL)'? JR NZ,DO862 ;NO CONVERSION NECESSARY PUSH HL LD HL,ATHL ;OUTPUT '(HL)' CALL OUTSTR POP HL ; ; OUTPUT ',' FOLLOWED BY '(HL)' OR 'R' ; DO861: INC HL ;OUTPUT COMMA AND THEN 2ND R LD A,(HL) ;GET COMMA CALL DOUTCHAR INC HL ;PT TO 2ND R JP ATHLCHECK ;OUTPUT '(HL)' OR R ; ; OUTPUT 'R,' FOLLOWD PUSH HL LD HL,DO8AS ;OUTPUT '),HL' JR DO8C2 DO8AS: DB '),HL',0 ; ; THIS CONVERTS 'SPHL' TO 'LD SP,HL' ; DO8B: CALL OUTNEWOP5CH LD HL,DO8BS JR DO8F1 DO8BS: DB 'SP,HL',0 ; ; THIS CONVERTS 'STA ' TO 'LD (),A' ; AND 'OUT ' TO 'OUT (),A' ; DO8C: CALL OUTNEWOP5CH LD A,'(' ;OUTPUT '(' ; ; THIS OUTPUTS '),A' ; DO8C1: CALL DOUTCHAR ;OUTPUT CHAR IN A CALL OUTOPER ;OUTPUT OPERAND FIELD PUSH HL LD HL,DO8CS ;OUTPUT '),A' DO8C2: CALL OUTSTPYARGS ;COPY REST OF OPERAND FIELD AND COMMENTS AS-IS RETSTR: DB 'RET ',0 DOCALLS: LD HL,CALLSTR JR CP5WITHCOMMA ;COPY AND FOLLOW WITH COMMA CALLSTR: DB 'CALL ',0 DOJMPS: LD HL,JPSTR ;FALL THRU TO DO JP FORMS ; ; COPY STRING AT HL FOLLOWED BY CONDITION CODE, A COMMA, AND REST OF ; OPERAND FIELD ; CP5WITHCOMMA: CALL COPY5 LD A,',' CALL DOUTCHAR ;OUTPUT COMMA TO DISK JP COPYARGS ;COPY REST OF OPERAND FIELD JPSTR: DB 'JP ',0 ; ; COPY 5-CHAR-MAX STRING PTED TO BY HL FOLLOERVICE ROUTINE ADD HL,BC LD C,(HL) ;BC=ROUTINE ADDRESS INC HL LD B,(HL) POP HL ;PT TO OLD (1ST) OP PUSH BC ;ROUTINE ADDRESS ON STACK RET ;JMP TO ROUTINE ; ; THIS CONVERTS 'DAD ' TO 'ADD HL,' ; DO81: CALL OUTNEWOP5CH ;OUTPUT 'ADD' LD HL,DO81S ;OUTPUT 'HL,' CALL OUTSTR JP RPCHECK ;OUTPUT DO81S: DB 'HL,',0 ; ; THIS CONVERTS 'ADD R' TO 'ADD A,R' ; AND 'ADC R' TO 'ADC A,R' ; AND 'SBC R' TO 'SBC A,R' ; DO82: CALL OUTNEWOP5CH ;OUTPUT THE 'IN' TO 'LD HL,()' ; DO85: CALL OUTNEWOP5CH LD HL,DO85S ; ; THIS OUTPUTS THE STRING PTED TO BY HL, OUTPUTS THE REST OF THE OPERAND ; FIELD, OUTPUTS A CLOSING ')', AND OUTPUTS THE REST OF THE INPUT LINE ; OUTCLP: CALL OUTSTR ;01F9H CALL OUTOPER ;04D5H LD A,')' ;29H CALL DOUTCHAR ;0631H JP CARGS1 ;0198H ED BY '(HL)' OR 'R' ; DO862: CALL DOUTCHAR ;OUTPUT 'R' JR DO861 ;OUTPUT REST ; ; THIS CONVERTS 'PCHL' TO 'JP(HL)' ; DO88: CALL OUTNEWOP5CH LD HL,ATHL ;OUTPUT THE '(HL)' JP DO8F1 ; ; THIS CONVERTS 'RST N' TO 'RST NNH' ; DO89: CALL OUTNEWOP5CH LD HL,DO89S JP DO8F1 DO89S: DB '8*',0 ;MULTIPLY RESTART NUMBER BY 8 FOR Z80 ; ; THIS CONVERTS 'SHLD ' TO 'LD (),HL' ; DO8A: CALL OUTNEWOP5CH LD A,'(' ;OUTPUT OPENING '(' CALL DOUTCHAR CALL OUTOPER ;OUTPUT OPERANR ;OUTPUT STRING PTED TO BY HL POP HL ;CLEAR STACK JP CARGS1 ;OUTPUT REST OF INPUT LINE DO8CS: DB '),A',0 ; ; THIS CONVERTS 'STAX ' TO 'LD (),A' ; DO8D: CALL OUTNEWOP5CH LD HL,(INLNPTR) ;PT TO 1ST CHAR OF OPERAND LD A,(HL) ;GET IT CP 'B' ;BC REG PAIR? JR Z,DO8D1 ;OUTPUT IT IF SO CP 'D' ;DE REG PAIR? JR Z,DO8D2 ;OUTPUT IT IF SO JP CARGS1 ;ELSE, OUTPUT WHAT'S THERE DO8D1: LD HL,DO8D1S JR DO8D3 DO8D2: LD HL,DO8D2S DO8D3: CALL OUTSTR LD HL,(INLNPTR) ;PT TO AFTER    'B' OR 'D' INC HL JP CARGS1 DO8D1S: DB '(BC),A',0 DO8D2S: DB '(DE),A',0 ; ; THIS CONVERTS 'XCHG' TO 'EX DE,HL' ; DO8E: CALL OUTNEWOP5CH LD HL,DO8ES JR DO8F1 DO8ES: DB 'DE,HL',0 ; ; THIS CONVERTS 'XTHL' TO 'EX (SP),HL' ; DO8F: CALL OUTNEWOP5CH LD HL,DO8FS DO8F1: CALL OUTSTR ;01F9H JP COPYARGS ;0195H DO8FS: DB '(SP),HL',0 ; ; OUTPUT REST OF OPERAND FIELD UP TO WHITE SPACE BEFORE ENDING COMMENT ; OR END OF LINE ; OUTOPER: LD HL,(INLNPTR) ;PT TO NEXT CHAR IN I LD A,D ;ALL OF OPERAND FIELD FLUSHED? CP H ;CHECK FOR PTR MATCH JR NZ,OOL4 ;NO MATCH, SO FLUSH NEXT CHAR LD A,E ;REST OF MATCH? CP L RET Z ;DONE IF ALL MATCH OOL4: LD A,(HL) ;OUTPUT OPERAND CHAR TO DISK CALL DOUTCHAR INC HL ;PT TO NEXT OPERAND CHAR JR OOL3 ;CONTINUE UNTIL OPERAND ALL OUT ; ; THE FOLLOWING TURNS ON VARIOUS MESSAGES FOR MANUAL TRANSLATION ; DO91: LD A,9 ;ENDIFS LD (XLT1ON),A ;STORE TO ENABLE JR DO941 DO92: LD A,9 ;INCLUDES LD (XLT2ON),A JR DO941 DAM BANNER CALL PMSG LD DE,HMSG1 ;PRINT HELP MESSAGE CALL PMSG LD C,1 ;GET ANY CHAR CALL BDOS LD DE,HMSG2 ;PRINT REST OF HELP MESSAGE CALL PMSG POP DE ;CLEAR STACK RET ;RETURN TO CP/M ; ; THE FOLLOWING INITIALIZES THE PROGRAM FOR EXECUTION ; INIT: LD DE,HEADER ;PRINT PROGRAM BANNER CALL PMSG LD A,10 ;INIT PDOT PRINT (LINE) COUNT LD (LCOUNT),A LD A,60 ;INIT NEW LINE PRINT COUNT LD (NLCOUNT),A LD A,1 ;INITIALIZE OUTPUT BUFFER LINE POSITION LD (OBUFLPOS),A CALL MAN FOR IFC, ICL, MAC, LST RET ; ; SET UP FILE NAMES ; MAKEFNS: LD HL,DEFFCB ;COPY INPUT FILE NAME FROM COMMAND LD DE,FCBASM ;INTO THIS FCB FOR USE LD BC,9 ;9 BYTES LDIR ;COPY LD A,(HL) ;FILE TYPE SPECIFIED? CP ' ' ;NONE IF JR Z,MFN1 LD BC,3 ;3 MORE BYTES LDIR MFN1: LD HL,FCB2+1 ;2ND FILE SPECIFIED? LD A,(HL) ;GET FIRST BYTE OF FILE NAME DEC HL ;PT TO FIRST BYTE OF FCB CP ' ' ;NO 2ND FILE NAME? JR NZ,MFN2 ;SKIP RELOAD OF HL IF THERE IS A 2ND FILE NAME LD HL LD DE,CRLFSTR ;END LINE CALL PMSG RET ; ; PRINT FILE NAME MESSAGE ; PRFNAME: LD A,(HL) ;GET DISK NUMBER ADD A,'@' ;ADD IN ASCII BIAS CALL PCHAR LD A,':' ;PRINT COLON CALL PCHAR INC HL ;PT TO FIRST CHAR OF FILE NAME LD B,8 ;8 CHARS CALL PRFNC LD A,'.' ;DOT CALL PCHAR LD B,3 ;3 CHARS CALL PRFNC RET PRFNC: LD A,(HL) ;GET NEXT CHAR INC HL ;PT TO NEXT CALL PCHAR ;PRINT CHAR DJNZ PRFNC RET ; ; OPEN INPUT FILE FOR PROCESSING ; OPENIN: LD DE,FCBASM NPUT LINE BUFFER OOL1: LD A,(HL) ;GET NEXT CHAR CP ';' ;BEGINNING OF COMMENT? JR Z,OOL2 ;CHECK FOR REST OF OPERAND CP 0DH ;END OF LINE? JR Z,OOL2 ;CHECK FOR REST OF OPERAND INC HL ;CONTINUE UNTIL EITHER COMMENT OR EOL FOUND JR OOL1 OOL2: DEC HL ;BACK UP (OVER WHITE SPACE?) LD A,(HL) ;GET CHAR CP ' ' ;WHITE? JR Z,OOL2 ;CONTINUE BACKING CP 9 ;WHITE? JR Z,OOL2 ;CONTINUE BACKING INC HL ;PT TO FIRST WHITE CHAR EX DE,HL ;SAVE PTR IN DE LD HL,(INLNPTR) ;PT TO START OF SCAN OOL3: O93: LD A,9 ;LISTS LD (XLT3ON),A JR DO941 DO94: LD A,9 ;MACROS LD (XLT4ON),A DO941: CALL OUTNEWOP5CH ;OUTPUT NEW CODE LD A,0DH ;TURN ON PRINTED ERR MESSAGE LD (ERR5ON),A ;TURN ON FLAG BY STARTING WITH JP COPYARGS ;COPY REST OF CODE ; ; THE FOLLOWING CHECKS FOR THE SPECIFICATION OF A HELP OPTION AND ; PRINTS THE HELP MESSAGE IF SO ; HCHECK: LD A,(DEFFCB+1) ;GET FIRST CHAR OF FILE NAME CP '/' ;OPTION? RET NZ ;NO HELP REQUESTED IF NOT OPTION LD DE,HEADER ;PRINT PROGRKEFNS ;SET UP FILE NAMES CALL OPENIN ;OPEN INPUT FILE CALL OPENOUT ;OPEN OUTPUT FILE LD HL,FHDR ;OUTPUT '.Z80' AND 'ASEG' TO MAC FILE INIT1: LD A,(HL) ;GET CHAR OR A ;DONE? JR Z,INIT2 CALL DOUTCHAR ;OUTPUT TO DISK INC HL ;PT TO NEXT JR INIT1 INIT2: LD A,(FCB2+1) ;2ND FILE NAME PRESENT? CP ' ' ; IF NOT RET NZ ;DONE IF SO XOR A ;A=0 LD (OCS4),A ;TURN OFF WEIRD OP CODE SCAN (REQ, ETC) LD (NOXLT),A ;TURN OFF SCAN FOR ENT, NAME, RAM, ROG LD (NOXLT2),A ;TURN OFF SCA,DEFFCB ;COPY FILE NAME INTO OUTPUT FCB MFN2: LD DE,FCBZ80 ;OUTPUT FCB LD BC,9 ;9 BYTES LDIR ;COPY LD HL,FCB2+9 ;PT TO FILE TYPE LD A,(HL) ;CHECK FOR A FILE TYPE CP ' ' ;NONE IF JR Z,MFN3 LD BC,3 ;THERE IS ONE, SO COPY IT OVER LDIR MFN3: LD DE,PRFNM1 ;PRINT PART 1 OF FILE NAME MESSAGE CALL PMSG LD HL,FCBASM ;PRINT NAME OF SOURCE FILE CALL PRFNAME LD DE,PRFNM2 ;PRINT PART 2 OF FILE NAME MESSAGE CALL PMSG LD HL,FCBZ80 ;PRINT NAME OF DESTINATION FILE CALL PRFNAME ;OPEN FILE FOR INPUT LD C,0FH CALL BDOS CP 0FFH ;ERROR? JR Z,OIERR ;ABORT WITH ERROR MESSAGE IF SO LD A,80H ;INIT CHAR COUNT FOR BUFFER LD (IBUFCNT),A RET OIERR: LD DE,ERR2 ;INPUT FILE ERROR MESSAGE JP ENDERR ;ABORT ; ; OPEN FILE FOR OUTPUT ; OPENOUT: LD DE,FCBZ80 ;OPEN OUTPUT FILE LD C,0FH CALL BDOS CP 0FFH ;ERROR? JR NZ,OOERR2 ;ABORT IF NO ERROR (OVERWRITE OLD FILE) OPENO1: LD DE,FCBZ80 ;ELSE CREATE OUTPUT FILE LD C,16H CALL BDOS CP 0FFH ;ERROR? JR Z,OOE   RR1 LD DE,FCBZ80 ;NOW OPEN OUTPUT FILE (REDUNDANT WITH MAKE) LD C,0FH CALL BDOS LD A,80H ;INIT COUNT OF BYTES REMAINING LD (OBUFBACKCNT),A ;SET COUNT LD HL,OBUF ;INIT ADDRESS OF NEXT BYTE LD (OBUFPTR),HL ;SET PTR RET OOERR1: LD DE,ERR3 ;DISK FULL JP ENDERR ;ABORT ERROR OOERR2: LD DE,ERR4 ;ATTEMPT TO OVERWRITE EXISTING FILE CALL PMSG LD C,1 ;GET RESPONSE CALL BDOS CALL CAPS ;CAPITALIZE CP 'Y' ;CONTINUE IF YES LD DE,ERR4A ;PREP FOR ABORT JP NZ,ENDERR ;ABORT ERROR LD DPYTODELIM: LD C,B ;LET BC=OLD B (FOR LDI INSTR) LD B,0 PUSH BC ;SAVE REGS PUSH DE PUSH HL CALL SPFILL ;FILL DESTINATION BUFFER WITH SPACES (PTED TO BY DE) POP HL ; ... AND C BYTES LONG POP DE POP BC CTD1: PUSH BC ;SAVE COUNT CALL DLIMSCAN ;SCAN FOR DELIMITER IF ENCOUNTERED POP BC RET Z ;DONE IF SO LDI ;COPY NEXT CHAR INTO DESTINATION BUFFER JP PO,DLIMSCAN ;FINAL DELIMITER SCAN IF DONE JR CTD1 ; ; ADVANCE BUFFER POINTER HL UNTIL NON-WHITE (NON-, NON-) ; ENCOUAND SKIP 1 BYTE IF NO MATCH DB ',' ;DELIMITERS ... DB ':' DB '+' DB '-' DB '/' DB '*' DB ' ' DB ')' DB ';' DB 0DH DB 9 ; ... TO HERE DB 0 ;END OF TABLE ; ; SCAN FOR DELIMITER -- RETURN WITH NZ IF NOT FOUND OR PT TO DELIMITER ; WITH Z IF FOUND; ON INPUT, TABLE PTED TO BY HL WITH 1ST 2 BYTES ; GIVING NUMBER OF BYTES TO CHECK AND NUMBER OF BYTES TO SKIP, RESP, ; ON EACH PARTIAL SCAN ; DELIMCHS: CALL SPCHSCAN ;DO SCAN OF TABLE RET NZ ;NOT FOUND LD C,B ;CHAR OFFSET HECK FOR END OF TABLE AND A ;ZERO? JR Z,SPCH2 ;DONE IF SO CALL COMPHLDE ;DO COMPARE RET Z ;RETURN IF MATCH LD A,C ;POINT TO NEXT TABLE ENTRY CALL ADDHLA ;HL=HL+(SIZE OF TABLE ENTRY) JR SPCH1 ; ; NO MATCH -- RETURN NZ ; SPCH2: INC A ;A=1 AND NZ RET ; ; COMPARE CHARS PTED TO BY DE WITH THAT PTED TO BY HL FOR B BYTES ; RET WITH ZERO FLAG SET IF COMPLETE MATCH, NZ IF NO MATCH; ; HL, DE, BC NOT AFFECTED ; COMPHLDE: PUSH HL ;SAVE REGS PUSH DE PUSH BC CMPHD1: LD A,(DE) USING LDIR RET ; ; OUTPUT CHAR IN A TO DISK FILE ; DOUTCHAR: PUSH HL ;SAVE REGS PUSH DE PUSH BC PUSH AF LD HL,(OBUFPTR) ;GET ADDRESS OF NEXT CHAR POS IN OUT BUFFER LD (HL),A ;STORE CHAR INTO OUT BUFFER CP 9 ;CHECK FOR TAB JR NZ,NOTABOUT ;NOT TAB -- DON'T UPDATE COUNT LD A,(OBUFLPOS) ;TAB -- UPDATE LOCATION IN LINE DEC A ;A=OUT BUFFER LINE POSITION - 1 AND 0F8H ;MASK FOR TAB ADD A,9 ;AND ADD 9 JR DOUT1 ; NOT A TAB -- JUST INCR POSITION COUNT NOTABOUT: LD A,(OBUFLPOE,CRLFSTR ;NEW LINE CALL PMSG LD DE,FCBZ80 ;DELETE OLD FILE LD C,19 ;BDOS DELETE FILE CALL BDOS JR OPENO1 ;CREATE NEW FILE AND CONTINUE ; ; CHECK TO SEE IF CHAR PTED TO BY HL IS A DELIMITER AND FLUSH CHARS UNTIL ; IT IS; RET WITH ZERO FLAG SET WHEN DONE ; FTODLM: ;Flush TO DeLiMiter PUSH BC CALL DLIMSCAN ;DO SCAN POP BC RET Z ;MATCH, SO ABORT INC HL ;PT TO NEXT CHAR JR FTODLM ;CONTINUE SCAN ; ; COPY (HL) TO (DE) FOR B BYTES OR UNTIL A DELIMITER IS ENCOUNTERED ; CONTERED ; SKIPWHITE: LD A,(HL) ;GET CHAR CP ' ' ;? JR Z,SKPWH1 ;SKIP IF SO CP 9 ;? RET NZ ;DONE IF NOT SKPWH1: INC HL ;PT TO NEXT CHAR JR SKIPWHITE ; ; CHECK TO SEE IF CHAR PTED TO BY HL IS A DELIMITER ; DLIMSCAN: PUSH DE EX DE,HL ;PT TO CHAR WITH DE LD HL,DLIMS ;PT TO TABLE OF DELIMITERS CALL DELIMCHS ;DO SCAN IN GENERAL EX DE,HL ;PT TO CHAR WITH HL LD A,(HL) ;GET CHAR IN A POP DE RET ; ; TABLE OF VALID DELIMITERS ; DLIMS: DB 1,1 ;SCAN 1 BYTE AT A TIME, COUNT IN BC LD B,0 ADD HL,BC ;PT TO CHAR SUB A ;SET ZERO FLAG RET ; ; SCAN SPECIAL CHAR TABLE PTED TO BY HL FOR STRING PTED TO BY DE; ; NUMBER OF SIGNIFICANT BYTES TO SCAN AS FIRST ENTRY IN TABLE, ; NUMBER OF BYTES TO SKIP ON FAILURE AS 2ND ENTRY IN TABLE; ; TABLE ENDS IN A BINARY 0 ; SPCHSCAN: LD B,(HL) ;B=NUMBER OF BYTES TO SCAN INC HL LD C,(HL) ;C=NUMBER OF BYTES TO SKIP ON FAILURE INC HL ;PT TO FIRST VALID BYTE IN TABLE ; ; MAIN SCANNING LOOP ; SPCH1: LD A,(HL) ;C;GET DE CHAR CP (HL) ;COMPARE TO HL CHAR JR NZ,CMPHD2 ;NO MATCH INC HL ;PT TO NEXT INC DE DJNZ CMPHD1 ;COUNT DOWN -- ZERO FLAG SET ON END CMPHD2: POP BC ;RESTORE REGS POP DE POP HL RET ; ; HL=HL+A ; ADDHLA: ADD A,L ;DO IT LD L,A RET NC INC HL RET ; ; FILL MEMORY PTED TO BY DE WITH SPACES FOR BC BYTES ; SPFILL: LD A,' ' ; LD (DE),A ;STORE FIRST LD H,D ;MAKE HL PT TO 1ST LD L,E INC DE ;DE PTS TO NEXT BYTE DEC BC ;BC IS 1 BYTE LESS LDIR ;COPY S) ;GET ADDRESS OF NEXT CHAR POS IN OUT BUFFER INC A ;ADD 1 TO IT DOUT1: LD (OBUFLPOS),A ;UPDATE OUT BUFFER LINE POSITION INC HL ;INCREMENT BUFFER PTR LD A,(OBUFBACKCNT) ;GET BUFFER BYTE COUNT DEC A ;BUFFER NOW FULL? JR NZ,DOUT2 ;CONTINUE IF NOT LD DE,OBUF ;WRITE BUFFER TO DISK IF SO LD C,1AH ;SET DMA ADDRESS CALL BDOS LD DE,FCBZ80 ;WRITE BLOCK CALL WRITEBLK LD HL,OBUF ;RESET OUTPUT BUFFER PTR TO 1ST BYTE LD A,80H ;RESET BUFFER BYTE COUNT DOUT2: LD (OBUFPTR),HL ;UPDATE O   UTPUT BUFFER PTR LD (OBUFBACKCNT),A ;UPDATE BUFFER BYTE COUNT POP AF ;RESTORE REGS POP BC POP DE POP HL RET ; ; WRITE BLOCK WHOSE FCB IS PTED TO BY DE TO DISK ; WRITEBLK: LD C,15H ;CP/M BDOS WRITE BLOCK CALL BDOS AND A ;ERROR? RET Z ;OK IF NONE LD DE,ERR1 ;ELSE PRINT ERROR MESSAGE AND ABORT JP ENDERR ; ; FILL LAST BLOCK WITH ^Z AND CLOSE OUTPUT FILE ; CTRLZFILL: LD A,(OBUFBACKCNT) ;GET REMAINING COUNT CP 80H ;FULL? JR Z,CLOSEOUT ;CLOSE FILE THEN LD A,1AH ;ELSE WRNEXT CHAR IN FILE LD A,(IBUFCNT) ;CHECK TO SEE IF BUFFER EMPTY CP 80H ;80H IF SO JR NZ,PUTCHAR ;NOT EMPTY, SO PLACE CHAR IN LINE EXX ;SAVE REGS LD DE,IBUFFER ;READ NEXT BLOCK FROM INPUT FILE LD C,1AH ;SET DMA ADDRESS CALL BDOS LD DE,FCBASM ;READ THE BLOCK LD C,14H CALL BDOS DEC A ;ERROR? JP Z,ENDALL ;DONE IF SO (ASSUME EOF) EXX ;GET REGS BACK LD DE,IBUFFER ;SET PTR TO 1ST BYTE OF BLOCK SUB A ;CHAR COUNT = 0 ; ; PLACE CHAR PTED TO BE DE INTO INLN ; PUTCHAR: LD (IBR NZ,NXTLCHAR ;CONTINUE PROCESSING IF NOT FULL INC B ;WRITE OVER LAST CHAR FOR REST OF LINE DEC HL JR NXTLCHAR ;CONTINUE ; ; OPTIONALLY CAPITALIZE CHAR IN A ; PCAPS: PUSH AF ;SAVE CHAR LD A,(INCMT) ;IN A COMMENT? OR A ;0=NO JR NZ,PCAPS5 ;DONE IF SO AND DON'T CAPITALIZE LD A,(INQUOTE) ;IN A QUOTE? OR A ;0=NO JR NZ,PCAPS1 ;DON'T CAPITALIZE IF SO POP AF ;NOT IN COMMENT OR QUOTE, SO CAPITALIZE CALL CAPS JR PCAPS2 PCAPS1: POP AF ;GET CHAR PCAPS2: CP ';' ;COMING INTO A COMMENT LD (INQUOTE),A PCAPS5: POP AF ;GET CHAR RET ;DONE ; ; STORE ENDING AND ; ENDBLINE: INC HL ;PT TO NEXT POSITION LD (HL),0AH ;STORE INC HL LD (HL),0 ;STORE LD (IBUFPTR),DE ;SAVE INPUT FILE PTR ; ; IF LINE STARTS WITH AN ASTERISK (COMMENT LINE), MAKE IT START WITH A ; SEMICOLON ; LD A,(INLN) ;LOOK AT FIRST CHAR CP '*' ;ASTERISK? JR NZ,ENDBL1 LD A,';' ;REPLACE WITH SEMICOLON LD (INLN),A ; ; CHECK FOR EMPTY LINE AND JUST OUTPUT NEW LINE IF SOE,ERR5ON ;OPTIONALLY PRINT EACH ERROR MESSAGE IF SET CALL PMSG LD DE,XLT1ON CALL PMSG LD DE,XLT2ON CALL PMSG LD DE,XLT3ON CALL PMSG LD DE,XLT4ON CALL PMSG LD DE,MSG2 ; ; PRINT MESSAGE PTED TO BY DE WITH PRECEEDING AND FINISH UP ; ENDERR: PUSH DE ;SAVE PTR LD DE,CRLFSTR ;PRINT CALL PMSG POP DE CALL PMSG ;PRINT MESSAGE JP WBOOT ;DONE ; ; PRINT STRING PTED TO BY DE AND ENDING IN 0 ; PMSG: LD A,(DE) ;GET CHAR AND A ;ENDING 0? RET Z ;DONE IF SO CALLITE ^Z CALL DOUTCHAR JR CTRLZFILL ; ; CLOSE OUTPUT FILE ; CLOSEOUT: LD DE,FCBZ80 ;OUTPUT FCB LD C,10H ;CLOSE FILE JP BDOS ; ; EXTRACT NEXT INPUT LINE FOR DISK FILE AND PLACE IT AS A 0-TERMINATED ; STRING IN BUFFER 'INLN' ; BUILDLINE: CALL PDOT ;PRINT ACTIVITY DOT XOR A ;A=FALSE OR 0 LD (INCMT),A ;TURN IN COMMENT FLAG OFF LD (INQUOTE),A ;TURN IN QUOTE FLAG OFF LD HL,INLN ;PT TO INLN BUFFER LD B,80 ;80 CHARS MAX ; ; MAIN BUILD LOOP ; NXTLCHAR: LD DE,(IBUFPTR) ;PT TO UFCNT),A ;SAVE CHAR COUNT LD A,(DE) ;GET CHAR INC DE ;PT TO NEXT LD (IBUFPTR),DE ;SAVE PTR PUSH HL LD HL,IBUFCNT ;INCR CHAR COUNT INC (HL) POP HL CALL PCAPS ;CAPITALIZE CHAR OPTIONALLY LD (HL),A ;SAVE CHAR FROM FILE INTO INLN CP 0DH ;END OF LINE? JR Z,ENDBLINE ;DONE IF SO CP 9 ;TAB EXPAND? JR Z,CONTBLINE ;PROCESS AS NORMAL CHAR IF SO CP ' ' ;LESS THAN ? JR C,NXTLCHAR ;DON'T PROCESS IF SO CONTBLINE: DEC B ;IS BUFFER FULL? INC HL ;PT TO NEXT CHAR IN INLN BUFFER J? JR NZ,PCAPS3 PUSH AF ;SAVE CHAR LD A,0FFH ;SET INCMT FLAG LD (INCMT),A JR PCAPS5 ;DONE PCAPS3: PUSH AF ;SAVE CHAR LD A,(INQUOTE) ;IN A QUOTE? OR A ;0=NO JR Z,PCAPS4 POP AF ;GET CHAR -- WE ARE IN A QUOTE PUSH AF ;SAVE IT AGAIN CP '''' ;ARE WE LEAVING THE QUOTE? JR NZ,PCAPS5 XOR A ;A=0 LD (INQUOTE),A ;YES, SO SET NOT IN QUOTE JR PCAPS5 PCAPS4: POP AF ;GET CHAR PUSH AF ;SAVE CHAR ONE LAST TIME CP '''' ;COMING INTO A QUOTE? JR NZ,PCAPS5 LD A,0FFH ;SET INQUOTE FLAG ; ELSE RETURN ; ENDBL1: LD A,B ;LINE EMPTY? SUB 80 ;START OVER IF SO RET NZ ;DONE IF NOT EMPTY LD A,0DH ;OUTPUT TO FILE FOR EMPTY LINE CALL DOUTCHAR LD A,0AH CALL DOUTCHAR JP BUILDLINE ;DO NEXT LINE ; ; CAPITALIZE CHAR IN A ; CAPS: AND 7FH ;MASK OUT MSB CP 61H ;DO NOTHING IF LESS THAN SMALL A RET C CP 7AH+1 ;CAP IF BETWEEN SMALL A AND Z, RESP RET NC AND 5FH ;CAPITALIZE RET ; ; END OF PROCESSING ; ENDALL: CALL CTRLZFILL ;FILL BUFFER WITH ^Z LD D PCHAR ;OUTPUT CHAR IN A INC DE ;PT TO NEXT CHAR JR PMSG ;CONTINUE ; ; PRINT CHAR IN A ON CON: ; PCHAR: PUSH AF ;SAVE REGS PUSH BC PUSH DE PUSH HL LD E,A ;CHAR IN E LD C,2 ;CON: OUTPUT CALL BDOS POP HL ;RESTORE REGS POP DE POP BC POP AF RET ; ; **** OP CODE TABLE, MESSAGE, AND BUFFER AREA **** ; ; ; OP CODE TABLES ; OCS1: DB 'ANI AND ' DB 'CMA CPL ' DB 'CMC CCF ' DB 'CPI CP ' DB 'HLT HALT ' DB 'JMP JP ' DB 'ORI OR ' DB 'RAL RLA    ' DB 'RAR RRA ' DB 'RLC RLCA ' DB 'RRC RRCA ' DB 'STC SCF ' DB 'SUI SUB ' DB 'XRI XOR ' POPS: DB 'DB DEFB ' DB 'DS DEFS ' DB 'DW DEFW ' DB 'SET DEFL ' NOXLT: DB 'ENT ENTRY' DB 'NAM NAME ' DB 'RAM DATA ' DB 'ROG REL ' DB 0 ;END OF TABLE FOR OCS 1 OCS2: DB 'ANA AND ' DB 'CMP CP ' DB 'DCR DEC ' DB 'INR INC ' DB 'MVI LD ' DB 'ORA OR ' DB 'SUB SUB ' DB 'XRA XOR ' DB 0 ;END OF TABLE FOR OCS 2 OCS3: DB 'DCX DEC ' D8: DB 'DAD ADD ' DW DO81 DB 'ADD ADD ' DW DO82 DB 'ADC ADC ' DW DO82 DB 'SBB SBC ' DW DO82 DB 'ADI ADD ' DW DO82 DB 'ACI ADC ' DW DO82 DB 'SBI SBC ' DW DO82 DB 'IN IN ' DW DO83 DB 'LDA LD ' DW DO83 DB 'LDAX LD ' DW DO84 DB 'LHLD LD ' DW DO85 DB 'MOV LD ' DW DO86 DB 'PCHL JP ' DW DO88 DB 'RST RST ' DW DO89 DB 'SHLD LD ' DW DO8A DB 'SPHL LD ' DW DO8B DB 'STA LD ' DW DO8C DB 'OUT OUT ' DW DO8C DB DB 'code into Zilog-Standard Z80 assembly language',0DH,0AH DB 'source code. It is invoked by a command of the',0DH,0AH DB 'following form:',0DH,0AH,0AH DB ' XLATE2 d:SRCFILE.typ d:destfile.typ',0DH,0AH,0AH DB ' All characters in lower case are optional, and,',0DH,0AH DB 'if omitted, the following values are assumed:',0DH,0AH,0AH DB ' . The Source File will have a type of ASM',0DH,0AH DB ' . The Destination File will have the same name',0DH,0AH DB ' as the Source File',0DH,0 . The M80 Pseudo-Ops .Z80 and ASEG will be inserted ' DB 'at the front',0DH,0AH DB ' of the MAC File',0DH,0AH DB ' . The text in the Destination File will be ' DB 'capitalized',0DH,0AH DB ' . All comment lines beginning with an asterisk will ' DB 'begin with',0DH,0AH DB ' a semicolon instead',0DH,0AH,0AH DB 0 ; FILE NAME MESSAGES PRFNM1: DB 'Source File: ',0 PRFNM2: DB ' Destination File: ',0 ; FIRST TWO LINES OF MAC FILE FHDR: DB 9,'.Z80',0DH,0AH ;USE ZILOG MNfollowing pseudo-ops ' DB 'have been used in your source ' DB 'and have not',0DH,0AH DB 'been ' DB 'fully translated. You must ' DB 'complete the translation ' DB 'using an editor.',0DH,0AH DB 9,'Original:',9,9,'Must Be Translated To:',0DH,0AH DB 0 ;END OF STRING XLT1ON: DB 0 ;THIS BYTE IS SET TO IF STRING ENABLED XLT1: DB '#ENDIF',9,9,9,'ENDIF',0DH,0AH,0 XLT2ON: DB 0 ;THIS BYTE IS SET TO IF STRINGENABLED XLT2: DB 'ICL',9,9,9,'*INCLUDE',0DH,0AH,0 XLT3ON: DB 0 ;THIB 'INX INC ' DB 'LXI LD ' DB 'POP POP ' DB 'PUSH PUSH ' DB 0 ;END OF TABLE FOR OCS 3 OCS4: DB 'REQ RNE RLT RGE CEQ ' DB ' CNE CLT CGE JEQ JNE ' DB ' JLT JGE ' DB 0 ;END OF TABLE FOR OCS 4 RETS: DB 'RC RNC RZ RNZ RP ' DB ' RM RPE RPO ' DB 0 ;END OF TABLE FOR RETS CALLS: DB 'CC CNC CZ CNZ CP ' DB ' CM CPE CPO ' DB 0 ;END OF TABLE FOR CALLS JMPS: DB 'JC JNC JZ JNZ JP ' DB ' JM JPE JPO ' DB 0 ;END OF TABLE FOR JMPS OCS'STAX LD ' DW DO8D DB 'XCHG EX ' DW DO8E DB 'XTHL EX ' DW DO8F NOXLT2: DB 'IFC IF ' DW DO91 DB 'ICL *INCL' DW DO92 DB 'LST LIST ' DW DO93 DB 'MAC MACRO' DW DO94 DB 0 ;END OF TABLE FOR OCS8 AND NOXLT2 ; ; VARIOUS MESSAGES AND PROGRAM HEADER ; HEADER: DB 'XLATE2 -- 8080-to-Z80 Translator, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB 0DH,0AH,0 ; HELP MESSAGES HMSG1: DB 0DH,0AH,0AH DB ' XLATE2 translates 8080 assembly language source',0DH,0AH AH DB ' . The Destination File will have a type of MAC',0DH,0AH,0AH DB 'Type to Continue - ',0 HMSG2: DB 0DH,0AH,0AH DB 'The following are examples of its use:',0DH,0AH,0AH DB ' XLATE2 DEMO1 <-- Translates DEMO1.ASM to DEMO1.MAC' DB 0DH,0AH DB ' XLATE2 DEMO1 DEMO2 <-- DEMO1.ASM to DEMO2.MAC' DB 0DH,0AH DB ' XLATE2 DEMO1.TXT DEMO2.GGG <-- DEMO1.TXT to DEMO2.GGG' DB 0DH,0AH,0AH DB 'The following functions are also performed by XLATE2:' DB 0DH,0AH,0AH DB ' EMONICS DB 9,'ASEG',0DH,0AH ;USE ABSOLUTE SEGMENTS DB 0 ERR1: DB 'Output File Write Error',0DH,0AH,7,0 ERR2: DB 'No Source File Found',0DH,0AH,7,0 ERR3: DB 'No Directory Space',0DH,0AH,7,0 ERR4: DB 'Output File Already Exists -- Delete It and Continue (Y/N)? ' DB 0 ERR4A: DB 'XLATE2 Aborting to CP/M',0 MSG2: DB 'XLATE2 Processing Complete',0 CRLFSTR: DB 0DH,0AH,0 ; ; VARIOUS ERROR MESSAGES ; ERR5ON: DB 0 ;THIS BYTE IS SET TO IF STRING ENABLED ERR5: DB 0AH DB 'The S BYTE IS SET TO IF STRING ENABLED XLT3: DB 'LST ',9,9,'LIST ' DB 0DH,0AH,0 XLT4ON: DB 0 ;THIS BYTE IS SET TO IF STRING ENABLED XLT4: DB 'MAC <$parameters>',9,'MACRO <#parameters>',0DH,0AH DB 9,'[ ... ]',9,9,9,'MEND',0DH,0AH DB 9,'#macro-call',9,9,'macro-call',0DH,0AH,0 ; ; INPUT FILE FCB ; FCBASM: DB 0,0,0,0,0,0,0,0,0,'ASM',0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ; ; OUTPUT FILE FCB ; FCBZ80: DB 0,0,0,0,0,0,0,0,0,'MAC',0     DB 0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0 ; ; BUFFERS ; ; STACK AREA DS 128 ; CURRENT POSITION IN LINE OF OUTPUT BUFFER OBUFLPOS: DS 1 ; COUNTER FOR EVERY 10 LINES LCOUNT: DS 1 ; COUNTER FOR EVERY 60*10 LINES NLCOUNT: DS 1 ; IN COMMENT FLAG -- 0 MEANS NOT INCMT: DS 1 ; IN QUOTE FLAG -- 0 MEANS NOT INQUOTE: DS 1 ; PTR TO TARGET OP CODE IN INPUT LINE ILTOP: DS 2 ; OP CODE TO MATCH AGAINST TARGOP: DS 5 ; PTR TO CURRENT POSITION IN CURRENT INPUT LINE INLNPTR:M1%ly1! ͮ!m  ͮ!  ͮ! ͮO!. ͮ|!W ͮʋ! ͮʖ!  ͮʼ!,~ ( (#> *1~ ( ( (I;(!'  (#ͳ (-;(# ͳ):%0= ( 8> > >2%:&=2&>.́> 2&:'=2'x><2'~#~ ( #!~ (% (!;~:(% (, ((;($ ( # ͳ͑:(#~ (>:y8 > > > ͳ~; "*,͚ͳ"1<~(, <Ð ~ ( (#> *1~M“#!Ó(HL);( (#+~ ( (#*1z {~#> 2> 2 > 2> 2> 2Ð:]/ x x x x> 2&><2'>2%ͨ!9!9~(#:m 2 2D 2 !\c ~ (!m~+ !\ !u~ (x!c"x!x~@́>:́#>.́~#́c(>2 cj &(>25!6"3{jx;Yjx;#H ;~ ( #!~,:+-/* ); H F#N#~( y< #C SCF SUI SUB XRI XOR DB DEFB DS DEFS DW DEFW SET DEFL ENT ENTRYNAM NAME RAM DATA ROG REL ANA AND CMP CP DCR DEC INR INC MVI LD ORA OR SUB SUB XRA XOR DCX DEC INX INC LXI LD POP POP PUSH PUSH REQ RNE RLT RGE CEQ CNE CLT CGE JEQ JNE JLT JGE RC RNC RZ RNZ RP RM RPE RPO CC CNC CZ CNZ CP CM CPE CPO JC JNC JZ JNZ JP JM JPE JPO DAD ADD ADD ADD ADC ADC SBB SBC ADI ADD ACI ADC SBI SBC IN optional, and, if omitted, the following values are assumed: . The Source File will have a type of ASM . The Destination File will have the same name as the Source File . The Destination File will have a type of MAC Type to Continue - The following are examples of its use: XLATE2 DEMO1 <-- Translates DEMO1.ASM to DEMO1.MAC XLATE2 DEMO1 DEMO2 <-- DEMO1.ASM to DEMO2.MAC XLATE2 DEMO1.TXT DEMO2.GGG <-- DEMO1.TXT to DEMO2.GGG The following functions are DS 2 ; PTR TO CURRENT POSITION IN OUTPUT BUFFER (BLOCK) OBUFPTR: DS 2 ; COUNT OF CHARS REMAINING IN OUTPUT BUFFER OBUFBACKCNT: DS 1 ; OUTPUT BUFFER (BLOCK) OBUF: DS 128 ; CURRENT INPUT LINE BUFFER INLN: DS 80 ;80 CHARS IN LINE DS 3 ;3 EXTRA FOR ; PTR TO CURRENT POSITION IN INPUT BUFFER IBUFPTR: DS 2 ; COUNT OF NUMBER OF CHARS LEFT IN INPUT BUFFER IBUFCNT: DS 1 ; INPUT BUFFER (BLOCK) IBUFFER: DS 128 END *1~B(!D("H(#P (#~S "#~W ##!C !F!I!L#ÓAFBCDEHL:-!tE(!vN( !xL(!z~2-#~2.Z NZC NC!ͪÐRET ! CALL !ͪ>,ÐJP :-:.  N#F!HL,!A,!6A,(*1~B(D( Ó! !A,(BC)A,(DE)!/>)ÓHL,(*1~M !#~#!!g8*>(!{"),HL!fSP,HL>(!Ó),A*1~B(D(Ó!!*1#Ó(BC),A(DE),A! DE,HL!Ð(SP),HL*1~Ʌo#> bk *3w :%= :%<2%#:5= 6V!6>"325Hj:5(>2(2)!P[ :   c=F 2 S ! 4w (P ( 8# +:( 7:) ;; >2(:)( ' 2) ' >2)#6 #6S :* >;2xP> > ya{_cxxxxxxx́_ANI AND CMA CPL CMC CCF CPI CP HLT HALT JMP JP ORI OR RAL RLA RAR RRA RLC RLCA RRC RRCA ST IN LDA LD LDAX LD LHLD LD MOV LD 4PCHL JP URST RST ^SHLD LD jSPHL LD STA LD OUT OUT STAX LD XCHG EX XTHL EX IFC IF (ICL *INCL/LST LIST 6MAC MACRO=XLATE2 -- 8080-to-Z80 Translator, Version 1.1 XLATE2 translates 8080 assembly language source code into Zilog-Standard Z80 assembly language source code. It is invoked by a command of the following form: XLATE2 d:SRCFILE.typ d:destfile.typ All characters in lower case are  also performed by XLATE2: . The M80 Pseudo-Ops .Z80 and ASEG will be inserted at the front of the MAC File . The text in the Destination File will be capitalized . All comment lines beginning with an asterisk will begin with a semicolon instead Source File: Destination File: .Z80 ASEG Output File Write Error No Source File Found No Directory Space Output File Already Exists -- Delete It and Continue (Y/N)? XLATE2 Aborting to CP/MXLATE2 Processing Complete    The following pseudo-ops have been used in your source and have not been fully translated. You must complete the translation using an editor. Original: Must Be Translated To: #ENDIF ENDIF ICL *INCLUDE LST LIST MAC <$parameters> MACRO <#parameters> [ ... ] MEND #macro-call macro-call ASMMACsFILE : XCAT37 DATE : 20 SEPT 82 TOPIC : HOW TO USE XCAT37 uses the CP/M catalog file called MAST.CAT. It makes a new cross-reference file which it can then immediately print in paginated format, or can put the new file directly to disk. It loads in as much of MAST.CAT as available memory permits, then rearranges the file in a cross-reference manner so duplicate copies of the same program show what disks they are on. Here is a small sample: CAT .ASM - 106 mbering. XCAT37 uses only disk volume numbers and discards any disk volume names that might be on the same line. This can affect the sequence in which the volume numbers are displayed. There is a simple remedy for this -- do not put volume names on the same line as the volume number. Here is an alternate possibility: A>SAVE 0 B:-.023 A>SAVE 0 B:-EDITORS A>SAVE 0 B:-08AUG82 All three of these examples may be placed on the same disk to give additional information. T (5) Start on page : (6) Stop on page : (7) 1) User option of including 'space remaining' lines added by NCAT 2) Any key other than 'Y' makes a disk file instead of printing 3) A 'Y' puts tear tabs for roll paper every 11 inches, any other key defaults to fanfold paper with no tear tabs 4) A RET leaves the left margin at the normal position 5) A RET leav CAT .COM - 033 034 092 093 106 123 147 CAT .DOC - 033 034 106 CAT2 .COM - 033 034 CATALOG .HLP - 051 CBAS2 .COM - 031 032 040 CCP .ASM - 059 CCP .DOC - 059 CHECKERS.BAS - 082 Among other things this allows you to quickly determine how many copies of each file you have, and delete unneeded extra copies. Up to ten disk ID numbers are shown per line. If more exist, a new line is started to continue the nuhey use no disk space at all, but do use disk file names (slightly reducing the number of available remaining names.) XCAT37 paginates when printing to the list device. It asks several questions for the operator to answer: Do you want to include any '.FRE' files? (Y/N): (1) Do you want hard copy instead of a file? (Y/N): (2) Do you want tear tabs to use roll paper? (Y/N): (3) Number of spaces to augment left margin? (0-9): (4) Current date is: es the date area blank 6) A RET starts on page 1 7) A RET prints all remaining pages Not all printers have adjustable left margins. You can readily insert up to 9 extra spaces, faking an adjustable left margin. Any number of file names may be handled by XCAT37. With a 64k system using a typical size BIOS, around 3200 names may be handled each pass. It can handle up to 999 pages on the pagination before it starts over. This should handle at least 50,000 file names.     XCAT37 is based on a 1979 program by Lewis Moseley called CROSSREF. (This was called CRSREF on the Compuserve system which limits names to six chars.) It did not offer hard copy print. It was limited to only the number of file names that could be held in memory at one time. If too many for the available memory size, it just bombed CP/M by over- writing BDOS with no warning. It also was very slow, taking as long as 15 minutes to process the maximum length file it could handle. (XCAT37 takes ab CATALOG X-REFERENCE PGM v3.7 - 09/20/82 Do you want to include any ".FRE" files? (Y/N): Do you want hard copy instead of a file? (Y/N): Do you want tear tabs to use roll paper? (Y/N): Number of spaces to augment left margin? (0-9): Current date is: Start at page : Quit at page : ++ UNABLE TO OPEN MAST.CAT ++ ** READING MAST.CAT ** ++ READ ERROR OR EARLY EOF ++ ++ MAST.CAT FILE TOO LONG. LAST ENTRY THIS SECTION: " " WORKING ON NEXT SECTION ** WRITING OUTPUT MAST LST"o1 !, _Y,2!, ! "! "  Ͳ> ":m>2*}o|g  !, :!"#":K*x<2:7:] :e !\  2hB. !  >22q ~V :P*"#" *zK{K:2*<2K: V > <2> *   *#" *n~# )))) !~ % >0 K !`, _Y6 2!, i !, 1ڔ :Ҕ 0!G> w#Œ !, !, ! ¸ vå w#x#ڥ ͈̀å !, !, !!  v w#x ͈̀ !, !, !' 6 $ v w#x ͈̀ !,  *|\ !dY! ~#"!, _Yž >!2>2!6 "!2"" " !"" !, :4 > > :<26ڱ !+6    : _out one minute to handle a file with 3000 names.) XCAT37 also shows the total number of files handled as well as the number of "unique file names", since a great many of the total number are duplicates. This information gives the true count of different files in the catalog. You can abort XCAT37 with a Control-C at any time (unless it says: "Now writing to disk"). Irvin M. Hoff Los Altos Hills, CA 94022 FILE ** ++ UNABLE TO MAKE OUTPUT FILE ++ ++ DISK OR DIRECTORY FULL ++ DONE: 0 FILE NAMES 1 UNIQUE NAMES ++ PROGRAM ABORTED ++ FINAL PAGE IS: - Master Catalog as of Page 1 1 - -  MAST CAT z{:>2x"* 42*   ! ">2 m!~4bw!M6 ͋:h2ͥ hx€> Ê+> w > !!#~ ”+»+ ¡2!6 !'#~ ++ 2! ! :W6#|\!.Y* * 52# ":2V P\\@ , !, !M, ![ !u :> *:ʩ6#<Ý͚ = .I ,I I ²= ::h _: ͚ ! "<2*w#"~ #, ~ #6 > > > > :g :̎!6 K ::<26د2 !+6 Ϳ!6 \!.Y!, !, !' 6 $ v w#x ͈̀ !,  *|\ !dY! ~#"!, _Yž >!2>2!6 "!2"" " !"" !, :4 > > :<26ڱ !+6    : _   ; MACRO LIBRARY FOR PEDESTRIAN PUSHBUTTONS ; CWINP EQU 00H ;INPUT PORT FOR CROSSWALK ; PUSH? MACRO IFTRUE ;; "PUSH?" JUMPS TO LABEL "IFTRUE" WHEN ANY ONE ;; OF THE CROSSWALK SWITCHES IS DEPRESSED. THE ;; VALUE HAS BEEN LATCHED, AND READING THE PORT ;; CLEARS THE LATCHED VALUES IN CWINP ;;READ THE CROSSWALK SWITCHES ANI (1 SHL CWCNT) - 1 ;;BUILD MASK JNZ IFTRUE ;;ANY SWITCHES SET? ;; CONTINUE ON FALSE CONDITION ENDM ; MACRO LIBRARY FOR 8-BIT COMPARISON OPERATION ; TEST? MACRO X,Y ;; UTILTITY MACRO TO GENERATE CONDITION CODES IF NOT NUL X ;;THEN LOAD X LDA X ;;X ASSUMED TO BE IN MEMORY ENDIF IRPC ?Y,Y ;;Y MAY BE CONSTANT OPERAND TDIG? SET '&?Y'-'0' ;;FIRST CHAR DIGIT? EXITM ;;STOP IRPC AFTER FIRST CHAR ENDM IF TDIG? <= 9 ;;Y NUMERIC? SUI Y ;;YES, SO SUB IMMEDIATE ELSE LXI H,Y ;;Y NOT NUMERIC SUB M ;;SO SUB FROM MEMORY ENDM ; LSS MACRO X,Y,TL ;; X LSS THAN Y TEST, ;; TRANSFER TO TL (TRUE  JNC TL FL: ENDM HAN OR EQUAL TO Y TEST LSS X,Y,TL JZ TL ENDM ; EQL MACRO X,Y,TL ;; X EQUAL TO Y TEST TEST? X,Y JZ TL ENDM ; NEQ MACRO X,Y,TL ;; X NOT EQUAL TO Y TEST TEST? X,Y JNZ TL ENDM ; GEQ MACRO X,Y,TL ;; X GREATER THAN OR EQUAL TO Y TEST TEST? X,Y JNC TL ENDM ; GTR MACRO X,Y,TL ;; X GREATER THAN Y TEST LOCAL FL ;;FALSE LABEL TEST? X,Y JC FL DCR A ; MACRO LIBRARY FOR "DOWHILE" CONSTRUCT ; GENDTST MACRO TST,X,Y,NUM ;; GENERATE A "DOWHILE" TEST TST X,Y,,ENDD&NUM ENDM ; GENDLAB MACRO LAB,NUM ;; PRODUCE THE LABEL LAB & NUM ;; FOR DOWHILE ENTRY OR EXIT LAB&NUM: ENDM ; GENDJMP MACRO NUM ;; GENERATE JUMP TO DOWHILE TEST JMP DTEST&NUM ENDM ; DOWHILE MACRO XV,REL,YV ;; INITIALIZE COUNTER DOCNT SET 0 ;NUMBER OF DOWHILES ;; DOWHILE MACRO X,R,Y ;; GENERATE THE DOWHILE ENTRY GENDLAB DTEST,%DOCNT ;; GENERATE THE CONDITIONAL TEST GELABEL) IF TRUE, ;; CONTINUE IF TEST IS FALSE TEST? X,Y ;;SET CONDITION CODES JC TL ENDM ; LEQ MACRO X,Y,TL ;; X LESS THAN OR EQUAL TO Y TEST LSS X,Y,TL JZ TL ENDM ; EQL MACRO X,Y,TL ;; X EQUAL TO Y TEST TEST? X,Y JZ TL ENDM ; NEQ MACRO X,Y,TL ;; X NOT EQUAL TO Y TEST TEST? X,Y JNZ TL ENDM ; GEQ MACRO X,Y,TL ;; X GREATER THAN OR EQUAL TO Y TEST TEST? X,Y JNC TL ENDM ; GTR MACRO X,Y,TL ;; X GREATER THAN Y TEST LOCAL FL ;;FALSE LABEL TEST? X,Y JC FL DCR A NDTST R,X,Y,%DOCNT DOLEV SET DOCNT ;;NEXT ENDD TO GENERATE DOCNT SET DOCNT+1 ENDM DOWHILE XV,REL,YV ENDM ; ENDDO MACRO ;; GENERATE THE JUMP TO THE TEST GENDJMP %DOLEV ;; GENERATE THE END OF A DOWHILE GENDLAB ENDD,%DOLEV DOLEV SET DOLEV-1 ENDM F DOWHILES ;; DOWHILE MACRO X,R,Y ;; GENERATE THE DOWHILE ENTRY GENDLAB DTEST,%DOCNT ;; GENERATE THE CONDITIONAL TEST GE   ; MACRO LIBRARY FOR A ZERO ADDRESS MACHINE ; ***************************************** ; * BEGIN TRACE/DUMP UTILITIES * ; ***************************************** BDOS EQU 0005H ;SYSTEM ENTRY RCHAR EQU 1 ;READ A CHARACTER WCHAR EQU 2 ;WRITE CHARACTER WBUFF EQU 9 ;WRITE BUFFER TRAN EQU 100H ;TRANSIENT PROGRAM AREA DATA EQU 1100H ;DATA AREA CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; DEBUGT SET 0 ;;TRACE DEBUG SET FALSE DEBUGP SET 0 ;;PRINT DEBUG SET FALSE ; PRN MACRO PR ;; PRINT MESEG-A MOV E,A MVI C,WCHAR JMP BDOS ;;RETURN THRU BDOS ;; @NB: ;;WRITE NIBBLE IN REG-A ADI 90H DAA ACI 40H DAA JMP @CH ;;RETURN THRU @CH ;; @HX: ;;WRITE HEX VALUE IN REG-A PUSH PSW ;;SAVE LOW BYTE RRC RRC RRC RRC ANI 0FH ;;MASK HIGH NIBBLE CALL @NB ;;PRINT HIGH NIBBLE POP PSW ANI 0FH JMP @NB ;;PRINT LOW NIBBLE ;; @AD ;;WRITE ADDRESS VALUE IN HL PUSH H ;;SAVE VALUE MVI A,' ' ;;LEADING BLANK CALL @CH ;;AHEAD OF ADDRESS POP H ;;HIGH BYTE TO A MOV A,H PUSH H ;16 ;;A THROUGH F? RNC ;;RETURN WITH ASSUMED CR @IN1: ;;IN RANGE, MULTIPLY BY 4 AND ADD REPT 4 DAD H ;;SHIFT 4 ENDM ORA L ;;ADD DIGIT MOV L,A ;;AND REPLACE VALUE JMP @IN0 ;;FOR ANOTHER DIGIT ;; PSUB: UGEN MACRO ;; REDEF TO INCLUDE ONCE ENDM UGEN ;;GENERATE FIRST TIME ENDM ; ***************************************** ; * END OF TRACE/DUMP UTILITIES * ; * BEGIN TRACE(ONLY) UTILITIES * ; ***************************************** TRACE MACRO CODE,MNAME ;; TRACE MACRO GIVEN BY MNAME LHLD @T2 ;;TOP-1 CALL @AD ;;PRINTED POP PSW ;;FLAGS RESTORED POP D ;;RETURN ADDRESS LHLD @T2 ;;TOP-1 PUSH H ;;RESTORED PUSH D ;;RETURN ADDRESS LHLD @T1 ;;TOP OF STACK RET ;; PSUB: ;;PAST SUBROUTINES ;; TRACE MACRO C,M ;; REDEFINED TRACE, USES @TR LOCAL PMSG,MSG JMP PMSG MSG: DB CR,LF ;;CR,LF DB '&M$' ;;MAC NAME PMSG: LXI B,C ;;CODE ADDRESS LXI D,MSG ;;MACRO NAME CALL @TR ;;TO TRACE IT ENDM ;; BACK TO ORIGINAL MACRO LEVEL TRACE CODE,MNAME ENDM ; TRT MACRO F ;; TSAGE 'PR' AT CONSOLE IF DEBUGP ;;PRINT DEBUG ON? LOCAL PMSG,MSG ;;LOCAL MESSAGE JMP PMSG ;;AROUND MESSAGE MSG: DB CR,LF ;;RETURN CARRIAGE DB '&PR$' ;;LITERAL MESSAGE PMSG: PUSH H ;;SAVE TOP ELEMENT OF STACK LXI D,MSG ;;LOCAL MESSAGE ADDRESS MVI C,WBUFF ;;WRITE BUFFER 'TIL $ CALL BDOS ;;PRINT IT POP H ;;RESTORE TOP OF STACK ENDIF ;;END TEST DEBUGP ENDM ; UGEN MACRO ;; GENERATE UTILITIES FOR TRACE OR DUMP LOCAL PSUB JMP PSUB ;;JUMP PAST SUBROUTINES @CH: ;;WRITE CHARACTER IN R;COPY BACK TO STACK CALL @HX ;;WRITE HIGH BYTE POP H MOV A,L ;;LOW BYTE JMP @HX ;;WRITE LOW BYTE ; @IN: ;;READ HEX VALUE TO HL FROM CONSOLE MVI A,' ' ;;LEADING SPACE CALL @CH ;;TO CONSOLE LXI H,0 ;;STARTING VALUE @IN0: PUSH H ;;SAVE IT FOR CHAR READ MVI C,RCHAR ;;READ CHARACTER FUNCTION CALL BDOS ;;READ TO ACCUMULATOR POP H ;;VALUE BEING BUILT IN HL SUI '0' ;;NORMALIZE TO BINARY CPI 10 ;;DECIMAL? JC @IN1 ;;CARRY IF 0,1,...,9 ;; MAY BE HEXADECIMAL A,...,F SUI 'A'-'0'-10 CPI , ;; AT LOCATION GIVEN BY CODE LOCAL PSUB UGEN ;;GENERATE UTILITIES JMP PSUB @T1: DS 2 ;;TEMP FOR REG-1 @T2: DS 2 ;;TEMP FOR REG-2 ;; @TR: ;;TRACE MACRO CALL ;; BC=CODE ADDRESS, DE=MESSAGE SHLD @T1 ;;STORE TOP REG POP H ;;RETURN ADDRESS XTHL ;;REG-2 TO TOP SHLD @T2 ;;STORE TO TEMP PUSH PSW ;;SAVE FLAGS PUSH B ;;SAVE RET ADDRESS MVI C,WBUFF ;;PRINT BUFFER FUNC CALL BDOS ;;PRINT MACRO NAME POP H ;;CODE ADDRESS CALL @AD ;;PRINTED LHLD @T1 ;;TOP OF STACK CALL @AD ;;PRINTED URN ON FLAG "F" DEBUG&F SET 1 ;;PRINT/TRACE ON ENDM ; TRF MACRO F ;; TURN OFF FLAG "F" DEBUG&F SET 0 ;;TRACE/PRINT OFF ENDM ; ?TR MACRO M ;; CHECK DEBUGT TOGGLE BEFORE TRACE IF DEBUGT TRACE %$,M ENDM ; ***************************************** ; * END TRACE (ONLY) UTILITIES * ; * BEGIN DUMP(ONLY) UTILITIES * ; ***************************************** DMP MACRO VNAME,N ;; DUMP VARIABLE VNAME FOR ;; N ELEMENTS (DOUBLE BYTES) LOCAL PSUB ;;PAST SUBROUTINES UGEN ;;GEN INLINE ROUTIN   ES JMP PSUB ;;PAST LOCAL SUBROUTINES @DM: ;;DUMP UTILITY PROGRAM ;; DE=MSG ADDRESS, C=ELEMENT COUNT ;; HL=BASE ADDRESS TO PRINT PUSH H ;;BASE ADDRESS PUSH B ;;ELEMENT COUNT MVI C,WBUFF ;;WRITE BUFFER FUNC CALL BDOS ;;MESSAGE WRITTEN @DM0: POP B ;;RECALL COUNT POP H ;;RECALL BASE ADDRESS MOV A,C ;;END OF LIST? ORA A RZ ;;RETURN IF SO DCR C ;;DECREMENT COUNT MOV E,M ;;NEXT ITEM (LOW) INX H MOV D,M ;;NEXT ITEM (HIGH) INX H ;;READY FOR NEXT ROUND PUSH H ;;SAVE PRINT ADDRESS AGE PMSG: ADR ?V ;;HL=ADDRESS ACTIVE SET 0 ;;CLEAR ACTIVE FLAG LXI D,MSG ;;MESSAGE TO PRINT IF NUL ?N ;;USE LENGTH 1 MVI C,1 ELSE MVI C,?N ENDIF CALL @DM ;;TO PERFORM THE DUMP ENDM ;;END OF REDEFINITION DMP VNAME,N ENDM ; ; ***************************************** ; * END DUMP (ONLY) UTILITIES, * ; * BEGIN STACK MACHINE OPCODES * ; ***************************************** ACTIVE SET 0 ;ACTIVE REGISTER FLAG ; SIZ MACRO SIZE ORG TRAN ;;SET TO TRANSIENT AREA ;; CREATE A STAC ;;ENSURE ACTIVE ACTIVE SET 0 ;;CLEARED ENDM ; DCL MACRO VNAME,SIZE ;; LABEL THE DECLARATION VNAME: IF NUL SIZE DS 2 ;;ONE WORD REQ'D ELSE DS SIZE*2 ;;DOUBLE WORDS ENDM ; LIT MACRO VAL ;; LOAD LITERAL VALUE TO TOP OF STACK SAVE ;;SAVE IF ACTIVE LXI H,VAL ;;LOAD LITERAL ?TR LIT ENDM ; ADR MACRO BASE,INX,CON ;; LOAD ADDRESS OF BASE, INDEXED BY INX, ;; WITH CONSTANT OFFSET GIVEN BY CON SAVE ;;PUSH IF ACTIVE IF NUL INX&CON LXI H,BASE ;;ADDRESS OF BASE EXITM ;;SIMPLE AD;;ADDRESS IN HL MOV E,M ;;LOW ORDER BYTE INX H MOV D,M ;;HIGH ORDER BYTE XCHG ;;BACK TO HL ENDIF ?TR VAL ;;TRACE SET? ENDM ; STO MACRO B,I,C ;; STORE THE VALUE OF THE TOP OF STACK ;; LEAVING THE TOP ELEMENT ACTIVE IF NUL I&C REST ;;ACTIVATE STACK SHLD B ;;STORED DIRECTLY TO B ELSE ADR B,I,C POP D ;;VALUE IS IN DE MOV M,E ;;LOW BYTE INX H MOV M,D ;;HIGH BYTE ENDIF CLEAR ;;MARK EMPTY ?TR STO ;;TRACE? ENDM ; SUM MACRO REST ;;RESTORE IF SAVED ;; ADD THE TOP TXRA A ;;CLEAR CARRY MOV A,H RAR ;;ROTATE WITH HIGH 0 MOV H,A MOV A,L RAR MOV L,A ;;BACK WITH HIGH BIT ENDM ENDM ; GEQ MACRO LAB ;; JUMP TO LAB IF (TOP-1) IS GREATER OR ;; EQUAL TO (TOP) ELEMENT. DIF ;;COMPUTE DIFFERENCE CLEAR ;;CLEAR ACTIVE ?TR GEQ JNC LAB ;;NO CARRY IF GREATER ORA H ;;BOTH BYTES ZERO? JZ LAB ;;ZERO IF EQUAL ;; DROP THROUGH IF NEITHER ENDM ; DUP MACRO ;; DUPLICATE THE TOP ELEMENT IN THE STACK REST ;;ENSURE ACTIVE PUSH H ?TR DUP ENDM ; BRN PUSH B ;;SAVE COUNT XCHG ;;DATA READY CALL @AD ;;PRINT ITEM VALUE JMP @DM0 ;;FOR ANOTHER VALUE ;; @DT: ;;DUMP TOP OF STACK ONLY PRN <(TOP)=> ;;"(TOP)=" PUSH H CALL @AD ;;VALUE OF HL POP H ;;TOP RESTORED RET ;; PSUB: ;; DMP MACRO ?V,?N ;; REDEFINE DUMP TO USE @DM UTILITY LOCAL PMSG,MSG ;; SPECIAL CASE IF NULL PARAMETERS IF NUL VNAME ;; DUMP THE TOP OF THE STACK ONLY CALL @DT EXITM ENDIF ;; OTHERWISE DUMP VARIABLE NAME JMP PMSG MSG: DB CR,LF ;;CRLF DB '&?V=$' ;;MESSK WHEN "XIT" ENCOUNTERED @STK SET SIZE ;;SAVE FOR DATA AREA LXI SP,STACK ENDM ; SAVE MACRO ;; CHECK TO ENSURE "ENTER" PROPERLY SET UP IF STACK ;;IS IT PRESENT? ENDIF SAVE MACRO ;;REDEFINE AFTER INITIAL REFERENCE IF ACTIVE ;;ELEMENT IN HL PUSH H ;;SAVE IT ENDIF ACTIVE SET 1 ;;SET ACTIVE ENDM SAVE ENDM ; REST MACRO ;; RESTORE THE TOP ELEMENT IF NOT ACTIVE POP H ;;RECALL TO HL ENDIF ACTIVE SET 1 ;;MARK AS ACTIVE ENDM ; CLEAR MACRO ;; CLEAR THE TOP ACTIVE ELEMENT REST DRESS ENDIF ;; MUST BE INX AND/OR CON IF NUL INX LXI H,CON*2 ;;CONSTANT ELSE LHLD INX ;;INDEX TO HL DAD H ;;DOUBLE PRECISION INX IF NOT NUL CON LXI D,CON*2 ;;DOUBLE CONST DAD D ;;ADDED TO INX ENDIF ;;NOT NUL CON ENDIF ;;NUL INX LXI D,BASE ;;READY TO ADD DAD D ;;BASE+INX*2+CON*2 ENDM ; VAL MACRO B,I,C ;; GET VALUE OF B+I+C TO HL ;; CHECK SIMPLE CASE OF B ONLY IF NUL I&C SAVE ;;PUSH IF ACTIVE LHLD B ;;LOAD DIRECTLY ELSE ;; "ADR" PUSHES ACTIVE REGISTERS ADR B,I,C WO STACK ELEMENTS POP D ;;TOP-1 TO DE DAD D ;;BACK TO HL ?TR SUM ENDM ; DIF MACRO ;; COMPUTE DIFFERENCE BETWEEN TOP ELEMENTS REST ;;RESTORE IF SAVED POP D ;;TOP-1 TO DE MOV A,E ;;TOP-1 LOW BYTE TO A SUB L ;;LOW ORDER DIFFERENCE MOV L,A ;;BACK TO L MOV A,D ;;TOP-1 HIGH BYTE SBB H ;;HIGH ORDER DIFFERENCE MOV H,A ;;BACK TO H ;; CARRY FLAG MAY BE SET UPON RETURN ?TR DIF ENDM ; LSR MACRO LEN ;; LOGICAL SHIFT RIGHT BY LEN REST ;;ACTIVATE STACK REPT LEN ;;GENERATE INLINE MACRO ADDR ;; BRANCH TO ADDRESS JMP ADDR ENDM ; XIT MACRO ?TR XIT ;;TRACE ON? JMP 0 ;;RESTART AT 0000 ORG DATA ;;START DATA AREA DS @STK*2 ;;OBTAINED FROM "SIZ" STACK: ENDM ; ; ***************************************** ; * MEMORY MAPPED I/O SECTION * ; ***************************************** ; INPUT VALUES WHICH ARE READ AS IF IN MEMORY ADC0 EQU 1080H ;A-D CONVERTER 0 ADC1 EQU 1082H ;A-D CONVERTER 1 ADC2 EQU 1084H ;A-D CONVERTER 2 ADC3 EQU 1086H ;A-D CONVERTER 3 ; DAC0 EQU 1090H    ;D-A CONVERTER 0 DAC1 EQU 1092H ;D-A CONVERTER 1 DAC2 EQU 1094H ;D-A CONVERTER 2 DAC3 EQU 1096H ;D-A CONVERTER 3 ; RWTRACE MACRO MSG,ADR ;; READ OR WRITE TRACE WITH MESSAGE ;; GIVEN BY "MSG" TO/FROM "ADR" PRN ENDM ; RDM MACRO ?C ;; READ A-D CONVERTER NUMBER "?C" SAVE ;;CLEAR THE STACK IF DEBUGP ;;STOP EXECUTION IN DDT RWTRACE ,% ADC&?C UGEN ;;ENSURE @IN IS PRESENT CALL @IN ;;VALUE TO HL SHLD ADC&?C ;;SIMULATE MEMORY INPUT ELSE ;; READ FROM MEMORY MAPP; INTEL 8085 MACRO LIBRARY ; ; THE SIM (SET INTERRUPT MASK), ; AND RIM (READ INTERRUPT MASK) ; ARE DEFINED BY THE FOLLOWING MACROS: ; SIM MACRO ;; SET INTERRUPT MASK FROM REG-A VALUE DB 30H ;;OPCODE FOR SIM ENDM ; RIM MACRO ;; READ INTERRUPT MASK TO REG-A DB 20H ;;OPCODE FOR RIM ENDM ; ; MACRO LIBRARY FOR BASIC INTERSECTION ; ; GLOBAL DEFINITIONS FOR DEBUG PROCESSING TRUE EQU 0FFFFH ;VALUE OF TRUE FALSE EQU NOT TRUE;VALUE OF FALSE DEBUG SET FALSE ;INITIALLY FALSE BDOS EQU 5 ;ENTRY TO CP/M BDOS RCHAR EQU 1 ;READ CHARACTER FUNCTION WBUFF EQU 9 ;WRITE BUFFER FUNCTION CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; ; INPUT/OUTPUT PORTS FOR LIGHT AND CLOCK LIGHT EQU 00H ;TRAFFIC LIGHT CONTROL CLOCK EQU 03H ;24 HOUR CLOCK (0,1,...,23) ; ; BIT POSITIONS FOR TRAFFIC LIGHT CONTNG TO &COLOR$' PASTMSG: EXITM ENDIF MVI A,COLOR SHL DIR&BITS ;;READIED OUT LIGHT ;;SENT IN PROPER BIT POSITION ENDM ; TIMER MACRO SECONDS ;; CONSTRUCT INLINE TIME-OUT LOOP LOCAL T1,T2,T3 ;;LOOP ENTRIES MVI D,4*SECONDS ;;BASIC LOOP CONTROL T1: MVI B,250 ;;250MSEC *4 = 1 SEC T2: MVI C,182 ;;182*5.5USEC = 1MSEC T3: DCR C ;;1 CY = .5 USEC JNZ T3 ;;+10 CY = 5.5 USEC DCR B ;;COUNT 250,249... JNZ T2 ;;LOOP ON B REGISTER DCR D ;;BASIC LOOP CONTROL JNZ T1 ;;LOOP ON D REGISTER ;; ARRIVED INPUT ADDRESS LHLD ADC&?C ENDIF ?TR RDM ;;TRACING? ENDM ; WRM MACRO ?C ;; WRITE D-A CONVERTER NUMBER "?C" REST ;;RESTORE STACK IF DEBUGP ;;TRACE THE OUTPUT RWTRACE ,% DAC&?C UGEN ;;INCLUDE SUBROUTINES CALL @AD ;;WRITE THE VALUE ENDIF SHLD DAC&?C ?TR WRM ;;TRACING OUTPUT? CLEAR ;;REMOVE THE VALUE ENDM ; ***************************************** ; * END OF MACRO LIBRARY * ; ***************************************** ROL NSBITS EQU 4 ;NORTH SOUUTH BITS EWBITS EQU 0 ;EAST WEST BITS ; ; CONSTANT VALUES FOR THE LIGHT CONTROL OFF EQU 0 ;TURN LIGHT OFF RED EQU 1 ;VALUE FOR RED LIGHT YELLOW EQU 2 ;VALUE FOR YELLOW LIGHT GREEN EQU 3 ;GREEN LIGHT ; SETLITE MACRO DIR,COLOR ;; SET LIGHT GIVEN BY "DIR" TO COLOR GIVEN BY "COLOR" IF DEBUG ;;PRINT INFO AT CONSOLE LOCAL SETMSG,PASTMSG MVI C,WBUFF ;;WRITE BUFFER FUNCTION LXI D,SETMSG CALL BDOS ;;WRITE THE TRACE INFO JMP PASTMSG SETMSG: DB CR,LF DB '&DIR CHANGIE HERE WITH APPROXIMATELY "SECONDS" ;; TIMEOUT, CONTINUE PROCESSING. ENDM ; CLOCK? MACRO LOW,HIGH,IFTRUE ;; CHECK FOR REAL-TIME CLOCK GREATER THAN OR ;; EQUAL TO "LOW." AND LESS THAN "HIGH." ;; CONTINUE AT "IFTRUE" WHEN BETWEEN THESE ;; TIMES. LOCAL IFFALSE ;;ALTERNATE TO TRUE CASE IN CLOCK ;;READ REAL-TIME CLOCK IF NOT NUL HIGH ;;CHECK HIGH CLOCK CPI HIGH ;;EQUAL OR GREATER? JNC IFFALSE ;;SKIP TO END IF SO ENDIF CPI LOW ;;LESS THAN LOW VALUE? JNC IFTRUE ;;SKIP TO LABEL IF NOT IFFA   LSE: ENDM ; RETRY MACRO GOLABEL ;; CONTINUE EXECUTION AT "GOLABEL" JMP GOLABEL ENDM -TIME CLOCK GREATER THAN OR ;; EQUAL TO "LOW." AND LESS THAN "HIGH." ;; CONTINUE AT "IFTRUE" WHEN BETWEEN THESE ;; TIMES. LOCAL IFFALSE ;;ALTERNATE TO TRUE CASE IN CLOCK ;;READ REAL-TIME CLOCK IF NOT NUL HIGH ;;CHECK HIGH CLOCK CPI HIGH ;;EQUAL OR GREATER? JNC IFFALSE ;;SKIP TO END IF SO ENDIF CPI LOW ;;LESS THAN LOW VALUE? JNC IFTRUE ;;SKIP TO LABEL IF NOT IFFA; MACRO LIBRARY FOR 8-BIT COMPARISON OPERATION ; TEST? MACRO X,Y ;; UTILTITY MACRO TO GENERATE CONDITION CODES IF NOT NUL X ;;THEN LOAD X LDA X ;;X ASSUMED TO BE IN MEMORY ENDIF IRPC ?Y,Y ;;Y MAY BE CONSTANT OPERAND TDIG? SET '&?Y'-'0' ;;FIRST CHAR DIGIT? EXITM ;;STOP IRPC AFTER FIRST CHAR ENDM IF TDIG? <= 9 ;;Y NUMERIC? SUI Y ;;YES, SO SUB IMMEDIATE ELSE LXI H,Y ;;Y NOT NUMERIC SUB M ;;SO SUB FROM MEMORY ENDM ; LSS MACRO X,Y,TL,FL ;; X LSS THAN Y TEST, ;; IF TL IS PRESENT,  OR EQUAL TO Y TEST IF NUL TL LSS X,Y,FL ELSE TEST? X,Y JNC TL ENDM ; GTR MACRO X,Y,TL,FL ;; X GREATER THAN Y TEST IF NUL TL LEQ X,Y,FL ELSE LOCAL GFL ;;FALSE LABEL TEST? X,Y JC GFL DCR A JNC TL GFL: ENDM ; EQL MACRO X,Y,TL,FL ;; X EQUAL TO Y TEST IF NUL TL NEQ X,Y,FL ELSE TEST? X,Y JZ TL ENDM ; NEQ MACRO X,Y,TL,FL ;; X NOT EQUAL TO Y TEST IF NUL TL EQL X,Y,FL ELSE TEST? X,Y JNZ TL ENDM ; GEQ MACRO X,Y,TL,FL ;; X GREATER THAN; MACRO LIBRARY FOR "SELECT" CONSTRUCT ; ; LABEL GENERATORS GENSLXI MACRO NUM ;; LOAD HL WITH ADDRESS OF CASE LIST LXI H,SELV&NUM ENDM ; GENCASE MACRO NUM,ELT ;; GENERATE JMP TO END OF CASES IF ELT GT 0 JMP ENDS&NUM ;;PAST ADDR LIST ENDIF ;; GENERATE LABEL FOR THIS CASE CASE&NUM&@&ELT: ENDM ; GENELT MACRO NUM,ELT ;; GENERATE ONE ELEMENT OF CASE LIST DW CASE&NUM&@&ELT ENDM ; GENSLAB MACRO NUM,ELTS ;; GENERATE CASE LIST SELV&NUM: ECNT SET 0 ;;COUNT ELEMENTS REPT ELTS ;;GENERASSUME TRUE TEST ;; IF TL IS ABSENT, THEN INVERT TEST IF NUL TL GEQ X,Y,FL ELSE TEST? X,Y ;;SET CONDITION CODES JC TL ENDM ; LEQ MACRO X,Y,TL,FL ;; X LESS THAN OR EQUAL TO Y TEST IF NUL TL GEQ X,Y,FL ELSE LSS X,Y,TL JZ TL ENDM ; EQL MACRO X,Y,TL,FL ;; X EQUAL TO Y TEST IF NUL TL NEQ X,Y,FL ELSE TEST? X,Y JZ TL ENDM ; NEQ MACRO X,Y,TL,FL ;; X NOT EQUAL TO Y TEST IF NUL TL EQL X,Y,FL ELSE TEST? X,Y JNZ TL ENDM ; GEQ MACRO X,Y,TL,FL ;; X GREATER THANATE DW'S GENELT NUM,%ECNT ECNT SET ECNT+1 ENDM ;;END OF DW'S ;; GENERATE END OF CASE LIST LABEL ENDS&NUM: ENDM ; SELNEXT MACRO ;; GENERATE THE NEXT CASE GENCASE %CCNT,%ECNT ;; INCREMENT THE CASE ELEMENT COUNT ECNT SET ECNT+1 ENDM ; SELECT MACRO VAR ;; GENERATE CASE SELECTION CODE CCNT SET 0 ;;COUNT "SELECTS" SELECT MACRO V ;;REDEFINITION OF SELECT ;; SELECT ON V OR ACCUMULATOR CONTENTS IF NOT NUL V LDA V ;;LOAD SELECT VARIABLE ENDIF GENSLXI %CCNT ;;GENERATE THE LXI H,SELV#     MOV E,A ;;CREATE DOUBLE PRECISION MVI D,0 ;;V IN D,E PAIR DAD D ;;SINGLE PREC INDEX DAD D ;;DOUBLE PREC INDEX MOV E,M ;;LOW ORDER BRANCH ADDR INX H ;;TO HIGH ORDER BYTE MOV D,M ;;HIGH ORDER BRANCH INDEX XCHG ;;READY BRANCH ADDRESS IN HL PCHL ;;GONE TO THE PROPER CASE ECNT SET 0 ;;ELEMENT COUNTER RESET SELNEXT ;;SELECT CASE 0 ENDM ;; INVOKE REDEFINED SELECT THE FIRST TIME SELECT VAR ENDM ; ENDSEL MACRO ;; END OF SELECT, GENERATE CASE LIST GENCASE %CCNT,%ECNT ;;LAST CASE G; SEQUENTIAL FILE I/O LIBRARY ; FILERR SET 0000H ;REBOOT AFTER ERROR @BDOS EQU 0005H ;BDOS ENTRY POINT @TFCB EQU 005CH ;DEFAULT FILE CONTROL BLOCK @TBUF EQU 0080H ;DEFAULT BUFFER ADDRESS ; ; BDOS FUNCTIONS @MSG EQU 9 ;SEND MESSAGE @OPN EQU 15 ;FILE OPEN @CLS EQU 16 ;FILE CLOSE @DIR EQU 17 ;DIRECTORY SEARCH @DEL EQU 19 ;FILE DELETE @FRD EQU 20 ;FILE READ OPERATION @FWR EQU 21 ;FILE WRITE OPERATION @MAK EQU 22 ;FILE MAKE @REN EQU 23 ;FILE RENAME @DMA EQU 26 ;SET DMA ADDRESS ; @SECT EQU 128  SET C ;;MAX LENGTH IRPC ?FC,FC ;;FILL EACH CHARACTER ;; MAY BE END OF COUNT OR NUL NAME IF @CNT=0 OR NUL ?FC EXITM ENDIF DB '&?FC' ;;FILL ONE MORE @CNT SET @CNT-1 ;;DECREMENT MAX LENGTH ENDM ;;OF IRPC ?FC ;; ;; PAD REMAINDER REPT @CNT ;;@CNT IS REMAINDER DB ' ' ;;PAD ONE MORE BLANK ENDM ;;OF REPT ENDM ; FILLDEF MACRO FCB,?FL,?LN ;; FILL THE FILE NAME FROM THE DEFAULT FCB ;; FOR LENGTH ?LN (9 OR 12) LOCAL PSUB JMP PSUB ;;JUMP PAST THE SUBROUTINE @DEF: ;;THIS SUBROUTINE FIL FILLFCB MACRO FID,DN,FN,FT,BS,BA ;; FILL THE FILE CONTROL BLOCK WITH DISK NAME ;; FID IS AN INTERNAL NAME FOR THE FILE, ;; DN IS THE DRIVE NAME (A,B..), OR BLANK ;; FN IS THE FILE NAME, OR BLANK ;; FT IS THE FILE TYPE ;; BS IS THE BUFFER SIZE ;; BA IS THE BUFFER ADDRESS LOCAL PFCB ;; ;; SET UP THE FILE CONTROL BLOCK FOR THE FILE ;; LOOK FOR FILE NAME = 1 OR 2 @C SET 1 ;;ASSUME TRUE TO BEGIN WITH IRPC ?C,FN ;;LOOK THROUGH CHARACTERS OF NAME IF NOT ('&?C' = '1' OR '&?C' = '2') @C SET 0 ;;ECIFIED DRIVE ENDIF FILLNAM FN,8 ;;FILL FILE NAME ;; NOW GENERATE THE FILE TYPE WITH PADDED BLANKS FILLNAM FT,3 ;;AND THREE CHARACTER TYPE ENDIF FCB&FID EQU $-12 ;;BEGINNING OF THE FCB DB 0 ;;EXTENT FIELD 00 FOR SETFILE ;; NOW DEFINE THE 3 BYTE FIELD, AND DISK MAP DS 20 ;;X,X,RC,DM0...DM15,CR FIELDS ;; IF FID&TYP<=2 ;;IN/OUTFILE ;; GENERATE CONSTANTS FOR INFILE/OUTFILE FILLNXT ;;@NXTB=0 ON FIRST CALL IF BS+0<@SECT ;; BS NOT SUPPLIED, OR TOO SMALL @BS SET @SECT ;;DEFAULT TO ONE SECTENSLAB %CCNT,%ECNT ;;CASE LIST ;; INCREMENT "SELECT" COUNT CCNT SET CCNT+1 ENDM ;LOW ORDER BRANCH ADDR INX H ;;TO HIGH ORDER BYTE MOV D,M ;;HIGH ORDER BRANCH INDEX XCHG ;;READY BRANCH ADDRESS IN HL PCHL ;;GONE TO THE PROPER CASE ECNT SET 0 ;;ELEMENT COUNTER RESET SELNEXT ;;SELECT CASE 0 ENDM ;; INVOKE REDEFINED SELECT THE FIRST TIME SELECT VAR ENDM ; ENDSEL MACRO ;; END OF SELECT, GENERATE CASE LIST GENCASE %CCNT,%ECNT ;;LAST CASE G;SECTOR SIZE EOF EQU 1AH ;END OF FILE CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED TAB EQU 09H ;HORIZONTAL TAB ; @KEY EQU 1 ;KEYBOARD @CON EQU 2 ;CONSOLE DISPLAY @RDR EQU 3 ;READER @PUN EQU 4 ;PUNCH @LST EQU 5 ;LIST DEVICE ; ; KEYWORDS FOR "FILE" MACRO INFILE EQU 1 ;INPUT FILE OUTFILE EQU 2 ;OUTPUTFILE SETFILE EQU 3 ;SETUP NAME ONLY ; ; THE FOLLOWING MACROS DEFINE SIMPLE SEQUENTIAL ; FILE OPERATIONS: ; FILLNAM MACRO FC,C ;; FILL THE FILE NAME/TYPE GIVEN BY FC FOR C CHARACTERS @CNTLS FROM THE TFCB (+16) MOV A,M ;;GET NEXT CHARACTER TO A STAX D ;;STORE TO FCB AREA INX H INX D DCR C ;;COUNT LENGTH DOWN TO 0 JNZ @DEF RET ;; END OF FILL SUBROUTINE PSUB: FILLDEF MACRO ?FCB,?F,?L LXI H,@TFCB+?F ;;EITHER @TFCB OR @TFCB+16 LXI D,?FCB MVI C,?L ;;LENGTH = 9,12 CALL @DEF ENDM FILLDEF FCB,?FL,?LN ENDM ; FILLNXT MACRO ;; INITIALIZE BUFFER AND DEVICE NUMBERS @NXTB SET 0 ;;NEXT BUFFER LOCATION @NXTD SET @LST+1 ;;NEXT DEVICE NUMBER FILLNXT MACRO ENDM ENDM ;CLEAR IF NOT 1 OR 2 ENDM ;; @C IS TRUE IF FN = 1 OR 2 AT THIS POINT IF @C ;;THEN FN = 1 OR 2 ;; FILL FROM DEFAULT AREA IF NUL FT ;;TYPE SPECIFIED? @C SET 12 ;;BOTH NAME AND TYPE ELSE @C SET 9 ;;NAME ONLY ENDIF FILLDEF FCB&FID,(FN-1)*16,@C ;;TO SELECT THE FCB JMP PFCB ;;PAST FCB DEFINITION DS @C ;;SPACE FOR DRIVE/FILENAME/TYPE FILLNAM FT,12-@C ;;SERIES OF DB'S ELSE JMP PFCB ;;PAST INITIALIZED FCB IF NUL DN DB 0 ;;USE DEFAULT DRIVE IF NAME IS ZERO ELSE DB '&DN'-'A'+1 ;;USE SPOR ELSE ;; COMPUTE EVEN BUFFER ADDRESS @BS SET (BS/@SECT)*@SECT ENDIF ;; ;; NOW DEFINE BUFFER BASE ADDRESS IF NUL BA ;; USE NEXT ADDRESS AFTER @NXTB FID&BUF SET BUFFERS+@NXTB ;; COUNT PAST THIS BUFFER @NXTB SET @NXTB+@BS ELSE FID&BUF SET BA ENDIF ;; FID&BUF IS BUFFER ADDRESS FID&ADR: DW FID&BUF ;; FID&SIZ EQU @BS ;;LITERAL SIZE FID&LEN: DW @BS ;;BUFFER SIZE FID&PTR: DS 2 ;;SET IN INFILE/OUTFILE ;; SET DEVICE NUMBER @&FID SET @NXTD ;;NEXT DEVICE @NXTD SET @NXTD+1 ENDIF ;;O   F FID&TYP<=2 TEST PFCB: ENDM ; FILE MACRO MD,FID,DN,FN,FT,BS,BA ;; CREATE FILE USING MODE MD: ;; INFILE = 1 INPUT FILE ;; OUTFILE = 2 OUTPUT FILE ;; SETFILE = 3 SETUP FCB ;; (SEE FILLFCB FOR REMAINING PARAMETERS) LOCAL PSUB,MSG,PMSG LOCAL PND,EOD,EOB,PNC ;; CONSTRUCT THE FILE CONTROL BLOCK ;; FID&TYP EQU MD ;;SET MODE FOR LATER REF'S FILLFCB FID,DN,FN,FT,BS,BA IF MD=3 ;;SETUP FCB ONLY, SO EXIT EXITM ENDIF ;; FILE CONTROL BLOCK AND RELATED PARAMETERS ;; ARE CREATED INLINE, NOW CRE DE LHLD FID&LEN ;;DO NOT EXCEED LENGTH ;; DE IS NEXT TO FILL/EMPTY, HL IS MAX LEN MOV A,E ;;COMPUTE NEXT-LEN SUB L ;;TO GET CARRY IF MORE MOV A,D SBB H ;;TO FILL JNC EOB ;; CARRY GEN'ED, HENCE MORE TO FILL/EMPTY LHLD FID&ADR ;;BASE OF BUFFERS DAD D ;;HL IS NEXT BUFFER ADDR XCHG MVI C,@DMA ;;SET DMA ADDRESS CALL @BDOS ;;DMA ADDRESS IS SET LXI D,FCB&FID ;;FCB ADDRESS TO DE IF MD=1 ;;READ BUFFER FUNCTION MVI C,@FRD ;;FILE READ FUNCTION ELSE MVI C,@FWR ;;FILE WRITE FUNCTION BDOS ;;ERROR TO CONSOLE POP PSW ;;REMOVE STACKED CHARACTER JMP FILERR ;;USUALLY REBOOTS EMSG: DB CR,LF DB 'DISK FULL: &FID' DB '$' ENDIF ;; EOB: ;; END OF BUFFER, RESET DMA AND POINTER LXI D,@TBUF MVI C,@DMA CALL @BDOS LXI H,0 SHLD FID&PTR ;;NEXT TO GET ;; PNC: ;; PROCESS THE NEXT CHARACTER XCHG ;;INDEX TO GET/PUT IN DE LHLD FID&ADR ;;BASE OF BUFFER DAD D ;;ADDRESS OF CHAR IN HL XCHG ;;ADDRESS OF CHAR IN DE IF MD=1 ;;INPUT PROCESSING DIFFERS LHLD FID&LEN ;;FOR EOF CHLEN ;;SET BUFF LEN IF MD=1 ;;INPUT FILE SHLD FID&PTR ;;CAUSE IMMEDIATE READ MVI C,@OPN ;;OPEN FILE FUNCTION ELSE ;;OUTPUT FILE LXI H,0 ;;SET NEXT TO FILL SHLD FID&PTR ;;POINTER INITIALIZED MVI C,@DEL LXI D,FCB&FID ;;DELETE FILE CALL @BDOS ;;TO CLEAR EXISTING FILE MVI C,@MAK ;;CREATE A NEW FILE ENDIF ;; NOW OPEN (IF INPUT), OR MAKE (IF OUTPUT) LXI D,FCB&FID CALL @BDOS ;;OPEN/MAKE OK? INR A ;;255 BECOMES 00 JNZ PMSG MVI C,@MSG ;;PRINT MESSAGE FUNCTION LXI D,MSG ;;ERROR MES GIVEN BY FID IRP ?F, ;; SKIP ALL BUT OUTPUT FILES IF ?F&TYP=2 LOCAL EOB?,PEOF,MSG,PMSG ;; WRITE ALL PARTIALLY FILLED BUFFERS EOB?: ;;ARE WE AT THE END OF A BUFFER? LHLD ?F&PTR ;;NEXT TO FILL MOV A,L ;;ON BUFFER BOUNDARY? ANI (@SECT-1) AND 0FFH JNZ PEOF ;;PUT EOF IF NOT 00 IF @SECT>255 ;; CHECK HIGH ORDER BYTE ALSO MOV A,H ANI (@SECT-1) SHR 8 JNZ PEOF ;;PUT EOF IF NOT 00 ENDIF ;; ARRIVE HERE IF END OF BUFFER, SET LENGTH ;; AND WRITE ONE MORE BYTE TO CLEAR BUFFS SHLD ?F&LATE IO FUNCTION JMP PSUB ;;PAST INLINE SUBROUTINE IF MD=1 ;;INPUT FILE GET&FID: ELSE PUT&FID: PUSH PSW ;;SAVE OUTPUT CHARACTER ENDIF LHLD FID&LEN ;;LOAD CURRENT BUFFER LENGTH XCHG ;;DE IS LENGTH LHLD FID&PTR ;;LOAD NEXT TO GET/PUT TO HL MOV A,L ;;COMPUTE CUR-LEN SUB E MOV A,H SBB D ;;CARRY IF NEXT MVI C,@DEL LXI D,FCB&?F CALL @BDOS ENDM ;;OF THE IRP ENDM ; DIRECT MACRO FID ;; PERFORM DIRECTORY SEARCH FOR FILE ;; SETS ZERO FLAG IF NOT PRESENT LXI D,FCB&FID MVI C,@DIR CALL @BDOS INR A ;00 IF NOT PRESENT ENDM ; RENAME MACRO NEW,OLD ;; RENAME FILE GIVEN BY "OLD" TO "NEW" LOCAL PSUB,REN0 ;; INCLUDE THE RENAME SUBROUTINE ONCE JMP PSUB @RENS: ;;RENAME SUBROUTINE, HL IS ADDRESS OF ;;OLD FCB, DE IS ADDRESS OF NEW FCB M RENAME NEW,OLD ENDM ; GET MACRO DEV ;; READ CHARACTER FROM DEVICE IF @&DEV <= @LST ;; SIMPLE INPUT MVI C,@&DEV CALL @BDOS ELSE CALL GET&DEV ENDM ; ND HALF POP D ;;RECALL BASE OF OLD NAME MVI C,@REN ;;RENAME FUNCTION CALL @BDOS RET ;;RENAME COMPLETE PSUB: RENAME MACRO N,O ;;REDEFINE RENAME LXI H,FCB&O ;;OLD FCB ADDRESS LXI D,FCB&N ;;NEW FCB ADDRESS CALL @RENS ;;RENAME SUBROUTINE END; MACRO LIBRARY FOR SIMPLE I/O BDOS EQU 0005H ;BDOS ENTRY CONIN EQU 1 ;CONSOLE INPUT FUNCTION MSGOUT EQU 9 ;PRINT MESSAGE TIL $ CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; READ MACRO VAR ;; READ A SINGLE CHARACTER INTO VAR MVI C,CONIN ;CONSOLE INPUT FUNCTION CALL BDOS ;CHARACTER IS IN A STA VAR ENDM ; WRITE MACRO MSG ;; WRITE MESSAGE TO CONSOLE LOCAL MSGL,PMSG JMP PMSG MSGL: DB CR,LF ;;LEADING CRLF DB '&MSG' ;;INLINE MESSAGE DB '$' ;;MESSAGE TERMINATOR PMSG: MVI C,MSGOUTPUSH H ;;SAVE FOR RENAME LXI B,16 ;;B=00,C=16 DAD B ;;HL = OLD FCB+16 REN0: LDAX D ;;NEW FCB NAME MOV M,A ;;TO OLD FCB+16 INX D ;;NEXT NEW CHAR INX H ;;NEXT FCB CHAR DCR C ;;COUNT DOWN FROM 16 JNZ REN0 ;; OLD NAME IN FIRST HALF, NEW IN SECOND HALF POP D ;;RECALL BASE OF OLD NAME MVI C,@REN ;;RENAME FUNCTION CALL @BDOS RET ;;RENAME COMPLETE PSUB: RENAME MACRO N,O ;;REDEFINE RENAME LXI H,FCB&O ;;OLD FCB ADDRESS LXI D,FCB&N ;;NEW FCB ADDRESS CALL @RENS ;;RENAME SUBROUTINE END ;;PRINT MESSAGE TIL $ LXI D,MSGL CALL BDOS ENDM  $ CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; READ MACRO VAR ;; READ A SINGLE CHARACTER INTO VAR MVI C,CONIN ;CONSOLE INPUT FUNCTION CALL BDOS ;CHARACTER IS IN A STA VAR ENDM ; WRITE MACRO MSG ;; WRITE MESSAGE TO CONSOLE LOCAL MSGL,PMSG JMP PMSG MSGL: DB CR,LF ;;LEADING CRLF DB '&MSG' ;;INLINE MESSAGE DB '$' ;;MESSAGE TERMINATOR PMSG: MVI C,MSGOUT   SIZ MACRO SIZE ;; SET "ORG" AND CREATE STACK LOCAL STACK ;;LABEL ON THE STACK ORG 100H ;;AT BASE OF TPA LXI SP,STACK JMP STACK ;;PAST STACK DS SIZE*2 ;;DOUBLE PRECISION STACK: ENDM ; DUP MACRO ;; DUPLICATE TOP OF STACK PUSH H ENDM ; SUM MACRO ;; ADD THE TOP TWO STACK ELEMENTS POP D ;;TOP-1 TO DE DAD D ;;BACK TO HL ENDM ; LSR MACRO LEN ;; LOGICAL SHIFT RIGHT BY LEN REPT LEN ;;GENERATE INLINE XRA A ;;CLEAR CARRY MOV A,H RAR ;;ROTATE WITH HIGH 0 MOV H,A MOV A,L RAR SHLD DAC&?C ;;VALUE WRITTEN POP H ;;RESTORE STACK ENDM 4H ;A-D CONVERTER 2 ADC3 EQU 1086H ;A-D CONVERTER 3 ; DAC0 EQU 1090H ;D-A CONVERTER 0 DAC1 EQU 1092H ;D-A CONVERTER 1 DAC2 EQU 1094H ;D-A CONVERTER 2 DAC3 EQU 1096H ;D-A CONVERTER 3 ; RDM MACRO ?C ;; READ A-D CONVERTER NUMBER "?C" PUSH H ;;CLEAR THE STACK ;; READ FROM MEMORY MAPPED INPUT ADDRESS LHLD ADC&?C ENDM ; WRM MACRO ?C ;; WRITE D-A CONVERTER NUMBER "?C" ; MACRO LIBRARY FOR STREET TREADLES ; TRINP EQU 01H ;TREADLE INPUT PORT TROUT EQU 01H ;TREADLE OUTPUT PORT ; TREAD? MACRO TR,IFTRUE ;; "TREAD?" IS INVOKED TO CHECK IF ;; TREADLE GIVEN BY TR HAS BEEN SENSED. ;; IF SO, THE LATCH IS CLEARED AND CONTROL ;; TRANSFERS TO THE LABEL "IFTRUE" LOCAL IFFALSE ;;IN CASE NOT SET ;; IN TRINP ;;READ TREADLE SWITCHES ANI 1 SHL TR ;;MASK PROPER BIT JZ IFFALSE ;;SKIP RESET IF 0 MVI A,1 SHL TR ;;TO RESET THE BIT OUT TROUT ;;CLEAR IT JMP IFTRUE ;;GO ; MACRO LIBRARY FOR "WHEN" CONSTRUCT ; ; "WHEN" COUNTERS ; LABEL GENERATORS GENWTST MACRO TST,X,Y,NUM ;; GENERATE A "WHEN" TEST (NEGATED FORM), ;; INVOKE MACRO "TST" WITH PARAMETERS ;; X,Y WITH JUMP TO ENDW & NUM TST X,Y,,ENDW&NUM ENDM ; GENLAB MACRO LAB,NUM ;; PRODUCE THE LABEL "LAB" & "NUM" LAB&NUM: ENDM ; ; "WHEN" MACROS FOR START AND END ; WHEN MACRO XV,REL,YV ;; INITIALIZE COUNTERS FIRST TIME WCNT SET 0 ;;NUMBER OF WHENS WHEN MACRO X,R,Y GENWTST R,X,Y,%WCNT WLEV SET WCNT ;;NE MOV L,A ;;BACK WITH HIGH BIT ENDM ENDM ; ADC0 EQU 1080H ;A-D CONVERTER 0 ADC1 EQU 1082H ;A-D CONVERTER 1 ADC2 EQU 1084H ;A-D CONVERTER 2 ADC3 EQU 1086H ;A-D CONVERTER 3 ; DAC0 EQU 1090H ;D-A CONVERTER 0 DAC1 EQU 1092H ;D-A CONVERTER 1 DAC2 EQU 1094H ;D-A CONVERTER 2 DAC3 EQU 1096H ;D-A CONVERTER 3 ; RDM MACRO ?C ;; READ A-D CONVERTER NUMBER "?C" PUSH H ;;CLEAR THE STACK ;; READ FROM MEMORY MAPPED INPUT ADDRESS LHLD ADC&?C ENDM ; WRM MACRO ?C ;; WRITE D-A CONVERTER NUMBER "?C" TO TRUE LABEL IFFALSE: ENDM R,IFTRUE ;; "TREAD?" IS INVOKED TO CHECK IF ;; TREADLE GIVEN BY TR HAS BEEN SENSED. ;; IF SO, THE LATCH IS CLEARED AND CONTROL ;; TRANSFERS TO THE LABEL "IFTRUE" LOCAL IFFALSE ;;IN CASE NOT SET ;; IN TRINP ;;READ TREADLE SWITCHES ANI 1 SHL TR ;;MASK PROPER BIT JZ IFFALSE ;;SKIP RESET IF 0 MVI A,1 SHL TR ;;TO RESET THE BIT OUT TROUT ;;CLEAR IT JMP IFTRUE ;;GO XT ENDW TO GENERATE WCNT SET WCNT+1 ;;NUMBER OF "WHEN"S ENDM WHEN XV,REL,YV ENDM ; ENDW MACRO ;; GENERATE THE ENDING CODE FOR A "WHEN" GENLAB ENDW,%WLEV WLEV SET WLEV-1 ;;COUNT CURRENT LEVEL DOWN ;; WLEV MUST NOT GO BELOW 0 (NOT CHECKED) ENDM ,YV ;; INITIALIZE COUNTERS FIRST TIME WCNT SET 0 ;;NUMBER OF WHENS WHEN MACRO X,R,Y GENWTST R,X,Y,%WCNT WLEV SET WCNT ;;NE   ; @CHK MACRO USED FOR CHECKING 8 BIT DISPLACMENTS ; @CHK MACRO ?DD ;; USED FOR CHECKING RANGE OF 8-BIT DISP.S IF (?DD GT 7FH) AND (?DD LT 0FF80H) 'DISPLACEMENT RANGE ERROR - Z80 LIB' ENDIF ENDM LDX MACRO ?R,?D @CHK ?D DB 0DDH,?R*8+46H,?D ENDM LDY MACRO ?R,?D @CHK ?D DB 0FDH,?R*8+46H,?D ENDM STX MACRO ?R,?D @CHK ?D DB 0DDH,70H+?R,?D ENDM STY MACRO ?R,?D @CHK ?D DB 0FDH,70H+?R,?D ENDM MVIX MACRO ?N,?D @CHK ?D DB 0DDH,36H,?D,?N ENDM MVIY MACRO ?N,?D @CHK ?DDW ?NNNN ENDM SBCD MACRO ?NNNN DB 0EDH,43H DW ?NNNN ENDM SDED MACRO ?NNNN DB 0EDH,53H DW ?NNNN ENDM SSPD MACRO ?NNNN DB 0EDH,73H DW ?NNNN ENDM SIXD MACRO ?NNNN DB 0DDH,22H DW ?NNNN ENDM SIYD MACRO ?NNNN DB 0FDH,22H DW ?NNNN ENDM SPIX MACRO DB 0DDH,0F9H ENDM SPIY MACRO DB 0FDH,0F9H ENDM PUSHIX MACRO DB 0DDH,0E5H ENDM PUSHIY MACRO DB 0FDH,0E5H ENDM POPIX MACRO DB 0DDH,0E1H ENDM POPIY MACRO DB 0FDH,0E1H ENDM EXAF MACRO DB  ?D @CHK ?D DB 0DDH,8EH,?D ENDM ADCY MACRO ?D @CHK ?D DB 0FDH,8EH,?D ENDM SUBX MACRO ?D @CHK ?D DB 0DDH,96H,?D ENDM SUBY MACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBCX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBCY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANDX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANDY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XORX MACRO ?D @CHK ?D DB 0DDH,0AEH,?D ENDM XORY MACRO ?D @CHK ?D DB 0FDH,0AEH,?D ENDM ORX MACRO ?D @CEH ENDM BC EQU 0 DE EQU 2 HL EQU 4 IX EQU 4 IY EQU 4 DADC MACRO ?R DB 0EDH,?R*8+4AH ENDM DSBC MACRO ?R DB 0EDH,?R*8+42H ENDM DADX MACRO ?R DB 0DDH,?R*8+09H ENDM DADY MACRO ?R DB 0FDH,?R*8+09H ENDM INXIX MACRO DB 0DDH,23H ENDM INXIY MACRO DB 0FDH,23H ENDM DCXIX MACRO DB 0DDH,2BH ENDM DCXIY MACRO DB 0FDH,2BH ENDM BIT MACRO ?N,?R DB 0CBH,?N*8+?R+40H ENDM SETB MACRO ?N,?R DB 0CBH,?N*8+?R+0C0H ENDM RES MACRO ?N,?R DB 0CBH,?N*8+?R+80 DB 0FDH,36H,?D,?N ENDM LDAI MACRO DB 0EDH,57H ENDM LDAR MACRO DB 0EDH,5FH ENDM STAI MACRO DB 0EDH,47H ENDM STAR MACRO DB 0EDH,4FH ENDM LXIX MACRO ?NNNN DB 0DDH,21H DW ?NNNN ENDM LXIY MACRO ?NNNN DB 0FDH,21H DW ?NNNN ENDM LDED MACRO ?NNNN DB 0EDH,5BH DW ?NNNN ENDM LBCD MACRO ?NNNN DB 0EDH,4BH DW ?NNNN ENDM LSPD MACRO ?NNNN DB 0EDH,07BH DW ?NNNN ENDM LIXD MACRO ?NNNN DB 0DDH,2AH DW ?NNNN ENDM LIYD MACRO ?NNNN DB 0FDH,2AH 08H ENDM EXX MACRO DB 0D9H ENDM XTIX MACRO DB 0DDH,0E3H ENDM XTIY MACRO DB 0FDH,0E3H ENDM LDI MACRO DB 0EDH,0A0H ENDM LDIR MACRO DB 0EDH,0B0H ENDM LDD MACRO DB 0EDH,0A8H ENDM LDDR MACRO DB 0EDH,0B8H ENDM CCI MACRO DB 0EDH,0A1H ENDM CCIR MACRO DB 0EDH,0B1H ENDM CCD MACRO DB 0EDH,0A9H ENDM CCDR MACRO DB 0EDH,0B9H ENDM ADDX MACRO ?D @CHK ?D DB 0DDH,86H,?D ENDM ADDY MACRO ?D @CHK ?D DB 0FDH,86H,?D ENDM ADCX MACROHK ?D DB 0DDH,0B6H,?D ENDM ORY MACRO ?D @CHK ?D DB 0FDH,0B6H,?D ENDM CMPX MACRO ?D @CHK ?D DB 0DDH,0BEH,?D ENDM CMPY MACRO ?D @CHK ?D DB 0FDH,0BEH,?D ENDM INRX MACRO ?D @CHK ?D DB 0DDH,34H,?D ENDM INRY MACRO ?D @CHK ?D DB 0FDH,34H,?D ENDM DCRX MACRO ?D @CHK ?D DB 0DDH,035H,?D ENDM DCRY MACRO ?D @CHK ?D DB 0FDH,35H,?D ENDM NEG MACRO DB 0EDH,44H ENDM IM0 MACRO DB 0EDH,46H ENDM IM1 MACRO DB 0EDH,56H ENDM IM2 MACRO DB 0EDH,5H ENDM BITX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+46H ENDM BITY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+46H ENDM SETX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+0C6H ENDM SETY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+0C6H ENDM RESX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+86H ENDM RESY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+86H ENDM JR MACRO ?N DB 18H,?N-$-1 ENDM JRC MACRO ?N DB 38H,?N-$-1 ENDM JRNC MACRO ?N DB 30H,?N-$-1 ENDM JRZ MAC   RO ?N DB 28H,?N-$-1 ENDM JRNZ MACRO ?N DB 20H,?N-$-1 ENDM DJNZ MACRO ?N DB 10H,?N-$-1 ENDM PCIX MACRO DB 0DDH,0E9H ENDM PCIY MACRO DB 0FDH,0E9H ENDM RETI MACRO DB 0EDH,4DH ENDM RETN MACRO DB 0EDH,45H ENDM INP MACRO ?R DB 0EDH,?R*8+40H ENDM OUTP MACRO ?R DB 0EDH,?R*8+41H ENDM INI MACRO DB 0EDH,0A2H ENDM INIR MACRO DB 0EDH,0B2H ENDM IND MACRO DB 0EDH,0AAH ENDM INDR MACRO DB 0EDH,0BAH ENDM OUTI MACRO DB 0EDH,0A3H END0CBH, ?D, 0EH ENDM RRCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 0EH ENDM RARR MACRO ?R DB 0CBH, 18H + ?R ENDM RARX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 1EH ENDM RARY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 1EH ENDM SLAR MACRO ?R DB 0CBH, 20H + ?R ENDM SLAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 26H ENDM SLAY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 26H ENDM SRAR MACRO ?R DB 0CBH, 28H+?R ENDM SRAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 2EH ENDM SRAY MACRO ?D ; SEQUENTIAL FILE I/O LIBRARY ; VRS 2.2 Jack Riley, Boulder Colorado(RCPM phone: (303)499-9169) ; ; This is a highly modified version of the original by unknown author ; believed to be Ward Christensen. ; It has been expanded to include the following new features: ; 1) An APPEND mode to the FILE macro to allow the opening of files ; with automatic positioning to the EOF. Both GET and PUT macros ; are expanded to allow full random access to the file. Random ; access reads and writes ar. A return is made to the ; 'home' user area to allow for 'local' file accesses or switches ; to other areas to access other files. This is not completely ; satisfactory and one could wish for a more elegant method which ; should have been available under CPM. Also an additional byte ; has been added to the FCB generated by FILLFCB to contain the ; user area. The NONLOC option prevents an otherwise automatic ; sequence to look first in the current user area and on the current ; efault values to be modified ; at run time(one of the failings of MACRO-economics) so that ; determinations of the availability of hard disks, for example, ; could be included. Also it is sometimes nice to have these ; values at the very beginning of a program so that DDT-style ; customizations can be made. ; 3) A SECTBUF parameter has been added to FILE to turn off the ; standard character buffering previously provided. It seemed ; reasonable to provide this new open machinery M OUTIR MACRO DB 0EDH,0B3H ENDM OUTD MACRO DB 0EDH,0ABH ENDM OUTDR MACRO DB 0EDH,0BBH ENDM RLCR MACRO ?R DB 0CBH, 00H + ?R ENDM RLCX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 06H ENDM RLCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 06H ENDM RALR MACRO ?R DB 0CBH, 10H+?R ENDM RALX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 16H ENDM RALY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 16H ENDM RRCR MACRO ?R DB 0CBH, 08H + ?R ENDM RRCX MACRO ?D @CHK ?D DB 0DDH,  @CHK ?D DB 0FDH, 0CBH, ?D, 2EH ENDM SRLR MACRO ?R DB 0CBH, 38H + ?R ENDM SRLX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 3EH ENDM SRLY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 3EH ENDM RLD MACRO DB 0EDH, 6FH ENDM RRD MACRO DB 0EDH, 67H ENDM , 26H ENDM SRAR MACRO ?R DB 0CBH, 28H+?R ENDM SRAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 2EH ENDM SRAY MACRO ?D e used instead of sequential(and also ; in other modes of use of the FILE macro so 1.4 is now incompatible). ; 2) PUBLIC and NONLOC options have been added to the FILE macro ; to allow access to files not in the current user area or on the ; current disk drive. The GET and PUT macros also handle the switching ; needed to provide for multiple opens in multiple areas. The way ; they work is to momentarily switch the user area to the one needed ; for the file undergoing an IO operation disk for the file, then switch the user area, then the disk to ; the default locations. When PUBLIC is included in an invocation ; of FILE, then code accessing default and current values is made. ; The allocations for these variables is shown below. ; DEFAULT$USER: ; DB 0 ; or other user area ; DEFAULT$DISK: ; DB 'x'-'A' ; where x is the default ; CUR$USER: ; DB 0FFH ; necessary initial value ; CUR$DISK: ; DB 0FFH ; " " ; ; The intention was to allow the deven when ; simple sector buffering was intended. Also when SECTBUF=NONE ; all buffering is turned off and only the new open code is ; produced. This can also be done through use of the POPEN macro ; directly(without FCB's being generated). FILERR SET 0000H ;REBOOT AFTER ERROR @FALSE SET 0000H @TRUE SET NOT @FALSE @BDOS EQU 0005H ;BDOS ENTRY POINT @TFCB EQU 005CH ;DEFAULT FILE CONTROL BLOCK @TBUF EQU 0080H ;DEFAULT BUFFER ADDRESS ; ; BDOS FUNCTIONS @MSG EQU 9 ;SEND MESSAGE @OPN E   QU 15 ;FILE OPEN @CLS EQU 16 ;FILE CLOSE @DIR EQU 17 ;DIRECTORY SEARCH @DEL EQU 19 ;FILE DELETE @MAK EQU 22 ;FILE MAKE @REN EQU 23 ;FILE RENAME @DMA EQU 26 ;SET DMA ADDRESS @FRD EQU 33 ;FILE RANDOM READ OPERATION @FWR EQU 34 ;FILE RANDOM WRITE OPERATION @CFS EQU 35 ;COMPUTE FILE SIZE @SETRR EQU 36 ;SET RANDOM RECORD ; @SECT EQU 128 ;SECTOR SIZE EOF EQU 1AH ;END OF FILE @CR EQU 0DH ;CARRIAGE RETURN @LF EQU 0AH ;LINE FEED TAB EQU 09H ;HORIZONTAL TAB ; @KEY EQU 1 ;KEYBOARD @CON EQU 2 ;CONSOLUL NAME IF @CNT=0 OR NUL ?FC EXITM ENDIF DB '&?FC' ;;FILL ONE MORE @CNT SET @CNT-1 ;;DECREMENT MAX LENGTH ENDM ;;OF IRPC ?FC ;; ;; PAD REMAINDER REPT @CNT ;;@CNT IS REMAINDER DB ' ' ;;PAD ONE MORE BLANK ENDM ;;OF REPT ENDM ; FILLDEF MACRO FCB,?FL,?LN ;; FILL THE FILE NAME FROM THE DEFAULT FCB ;; FOR LENGTH ?LN (9 OR 12) LOCAL PSUB JMP PSUB ;;JUMP PAST THE SUBROUTINE @DEF: ;;THIS SUBROUTINE FILLS FROM THE TFCB (+16) MOV A,M ;;GET NEXT CHARACTER TO A STAX D ;;STORE TO FCB A NAME ;; DEFINE FILE USING MODE MD: ;; INFILE = 1 INPUT FILE ;; OUTFILE = 2 OUTPUT FILE ;; SETFILE = 3 SETUP FCB ;; FID IS AN INTERNAL NAME FOR THE FILE, ;; DN IS THE DRIVE NAME (A,B..), OR BLANK ;; FN IS THE FILE NAME, OR BLANK ;; FT IS THE FILE TYPE ;; BS IS THE BUFFER SIZE ;; BA IS THE BUFFER ADDRESS LOCAL PFCB ;; FID&TYP SET MD ;;SET MODE FOR LATER REF'S ;; SET UP THE FILE CONTROL BLOCK FOR THE FILE ;; LOOK FOR FILE NAME = 1 OR 2 @C SET 1 ;;ASSUME TRUE TO BEGIN WITH IRPC ?C,FN ;;LB IF NUL DN DB 0 ;;USE DEFAULT DRIVE IF NAME IS ZERO ELSE DB '&DN'-'A'+1 ;;USE SPECIFIED DRIVE ENDIF FILLNAM FN,8 ;;FILL FILE NAME ;; NOW GENERATE THE FILE TYPE WITH PADDED BLANKS FILLNAM FT,3 ;;AND THREE CHARACTER TYPE ENDIF FCB&FID EQU $-12 ;;BEGINNING OF THE FCB DB 0 ;;EXTENT FIELD 00 FOR SETFILE ;; NOW DEFINE THE 3 BYTE FIELD, AND DISK MAP DS 23 ;;X,X,RC,DM0...DM15,CR,R0,R1,R2 FIELDS DB 0FFH ;; DEFAULT CURRENT USER AREA ;; IF FID&TYP<=2 ;;IN/OUTFILE ;; GENERATE CONSTANTS FOR DW @BS ;;BUFFER SIZE FID&PTR EQU $ DS 2 ;;SET IN INFILE/OUTFILE ;; SET DEVICE NUMBER @&FID SET @NXTD ;;NEXT DEVICE @NXTD SET @NXTD+1 ENDIF ;;OF FID&TYP<=2 TEST PFCB EQU $ ENDM ; FILE MACRO FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF ;; (SEE FILLFCB FOR PARAMETERS) FID&FLG SET 1 IF NUL PU FID&PUB SET 0 ELSE FID&PUB SET 1 ENDIF @SETRC SET @SETRR IF FMODE=APPEND @SETRC SET @CFS GFILE FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,0 FID&TYP SET OUTFILE ;;SET MODE FOR LATER REF'S ENE DISPLAY @RDR EQU 3 ;READER @PUN EQU 4 ;PUNCH @LST EQU 5 ;LIST DEVICE ; ; KEYWORDS FOR "FILE" MACRO NONE EQU 1 SECTBUFF EQU @TRUE NONLOC EQU @TRUE INFILE EQU 1 ;INPUT FILE OUTFILE EQU 2 ;OUTPUTFILE SETFILE EQU 3 ;SETUP NAME ONLY APPEND EQU 4 ;APPEND TO FILE ; ; THE FOLLOWING MACROS DEFINE SIMPLE SEQUENTIAL ; FILE OPERATIONS: ; FILLNAM MACRO FC,C ;; FILL THE FILE NAME/TYPE GIVEN BY FC FOR C CHARACTERS @CNT SET C ;;MAX LENGTH IRPC ?FC,FC ;;FILL EACH CHARACTER ;; MAY BE END OF COUNT OR NREA INX H INX D DCR C ;;COUNT LENGTH DOWN TO 0 JNZ @DEF RET ;; END OF FILL SUBROUTINE PSUB EQU $ FILLDEF MACRO ?FCB,?F,?L LXI H,@TFCB+?F ;;EITHER @TFCB OR @TFCB+16 LXI D,?FCB MVI C,?L ;;LENGTH = 9,12 CALL @DEF ENDM FILLDEF FCB,?FL,?LN ENDM ; FILLNXT MACRO ;; INITIALIZE BUFFER AND DEVICE NUMBERS @NXTB SET 0 ;;NEXT BUFFER LOCATION @NXTD SET @LST+1 ;;NEXT DEVICE NUMBER FILLNXT MACRO ENDM ENDM ; FILLFCB MACRO MD,FID,DN,FN,FT,BS,BA ;; FILL THE FILE CONTROL BLOCK WITH DISKOOK THROUGH CHARACTERS OF NAME IF NOT ('&?C' = '1' OR '&?C' = '2') @C SET 0 ;;CLEAR IF NOT 1 OR 2 ENDIF ENDM ;; @C IS TRUE IF FN = 1 OR 2 AT THIS POINT IF @C ;;THEN FN = 1 OR 2 ;; FILL FROM DEFAULT AREA IF NUL FT ;;TYPE SPECIFIED? @C SET 12 ;;BOTH NAME AND TYPE ELSE @C SET 9 ;;NAME ONLY ENDIF FILLDEF FCB&FID,(FN-1)*16,@C ;;TO SELECT THE FCB JMP PFCB ;;PAST FCB DEFINITION DS @C ;;SPACE FOR DRIVE/FILENAME/TYPE FILLNAM FT,12-@C ;;SERIES OF DB'S ELSE JMP PFCB ;;PAST INITIALIZED FC INFILE/OUTFILE FILLNXT ;;@NXTB=0 ON FIRST CALL IF BS+0<@SECT ;; BS NOT SUPPLIED, OR TOO SMALL @BS SET @SECT ;;DEFAULT TO ONE SECTOR ELSE ;; COMPUTE EVEN BUFFER ADDRESS @BS SET (BS/@SECT)*@SECT ENDIF ;; ;; NOW DEFINE BUFFER BASE ADDRESS IF NUL BA ;; USE NEXT ADDRESS AFTER @NXTB FID&BUF SET BUFFERS+@NXTB ;; COUNT PAST THIS BUFFER @NXTB SET @NXTB+@BS ELSE FID&BUF SET BA ENDIF ;; FID&BUF IS BUFFER ADDRESS FID&ADR EQU $ DW FID&BUF ;; FID&SIZ EQU @BS ;;LITERAL SIZE FID&LEN EQU $ DIF GFILE FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,@SETRC ENDM ; GFILE MACRO FMODE,FID,DN,FN,FT,BS,BA,PU,NOLOC,SECTBUF,@SETRC LOCAL PSUB,MSG,PMSG LOCAL PND,EOD,EOB,PNC,GLOOP,SAMEUSR ;; CONSTRUCT THE FILE CONTROL BLOCK ;; MD SET FMODE IF FMODE=APPEND IF @SETRC=0 MD SET INFILE ELSE MD SET OUTFILE ENDIF ENDIF IF FID&FLG FILLFCB MD,FID,DN,FN,FT,BS,BA ENDIF IF MD=SETFILE ;;SETUP FCB ONLY, SO EXIT EXITM ENDIF ;; FILE CONTROL BLOCK AND RELATED PARAMETERS ;; ARE CREATED INLIN   E, NOW CREATE IO FUNCTION BLOCKING SET @TRUE IF NUL SECTBUF ;;INPUT FILE JMP PSUB ;;PAST INLINE SUBROUTINE IF MD=OUTFILE PUT&FID EQU $ PUSH PSW ;;SAVE OUTPUT CHARACTER ELSE GET&FID EQU $ ENDIF LHLD FID&LEN ;;LOAD CURRENT BUFFER LENGTH XCHG ;;DE IS LENGTH LHLD FID&PTR ;;LOAD NEXT TO GET/PUT TO HL MOV A,L ;;COMPUTE CUR-LEN SUB E MOV A,H SBB D ;;CARRY IF NEXT ;; SKIP ALL BUT OUTPUT FILES IF ?F&TYP=OUTFILE LOCAL EOB?,PEOF,MSG,PMSG,SAMEUSR ;; WRITE ALL PARTIALLY FILLED BUFFERS EOB? EQU $ ;;ARE WE AT THE END OF A BUFFER? LHLD ?F&PTR ;;NEXT TO FILL MOV A,L ;;ON BUFFER BOUNDARY? ANI (@SECT-1) AND 0FFH JNZ PEOF ;;P JZ SAMEUSR MVI C,32 MOV E,A CALL @BDOS ;; GO TO FILE USER AREA SAMEUSR EQU $ ENDIF LXI D,FCB&?F ;;FCB ADDRESS TO DE MVI C,@CLS CALL @BDOS ;; CLOSE THE FILE IF ?F&PUB CALL RESET$SYSTEM ENDIF INR A ;;255 IF ERR BECOMES 00 JNZ PMSG ;; FILE CANNOT BE CLOSED MVI C,@MSG LXI D,MSG CALL @BDOS JMP PMSG ;;ERROR MESSAGE PRINTED MSG EQU $ DB @CR,@LF DB 'CANNOT CLOSE &?F' DB '$' PMSG EQU $ ENDIF ENDM ;;OF THE IRP ENDM ; ERASE MACRO FID ;; DELETE THE FILE(S) GIVEN BY  B,16 ;;B=00,C=16 DAD B ;;HL = OLD FCB+16 REN0 EQU $ LDAX D ;;NEW FCB NAME MOV M,A ;;TO OLD FCB+16 INX D ;;NEXT NEW CHAR INX H ;;NEXT FCB CHAR DCR C ;;COUNT DOWN FROM 16 JNZ REN0 ;; OLD NAME IN FIRST HALF, NEW IN SECOND HALF POP D ;;RECALL BASE OF OLD NAME MVI C,@REN ;;RENAME FUNCTION CALL @BDOS RET ;;RENAME COMPLETE PSUB EQU $ RENAME MACRO N,O ;;REDEFINE RENAME LXI H,FCB&O ;;OLD FCB ADDRESS LXI D,FCB&N ;;NEW FCB ADDRESS CALL @RENS ;;RENAME SUBROUTINE ENDM RENAME NEW,OLDM 1.X? ORA L JZ START2$DISK ; CHECK FOR DEFAULT DISK IF SO * OPTION 2: TRY TO OPEN FILE IN USER 0 ON CURRENT DISK MVI E,0FFH ; GET CURRENT USER NUMBER MVI C,32 ; GET USER CODE CALL @BDOS MOV C,A LDA DEFAULT$USER ; CHECK IF AT DEFAULT USER CMP C JZ START2$DISK ; DON'T TRY IF AT DEFAULT USER AREA STA FILEUA ; WHERE THE FILE IS IF ANYWHERE MOV E,A MOV A,C STA CUR$USER ; WHERE WE ARE(SAVE FOR LATER) MVI C,32 ; SET USER CODE TO DEFAULT$USER CALL @BDOS IF NUL NOLOC POP D ;  NUL NOLOC ELSE JZ START3$DISK ENDIF INR A ; ADD ONE TO DISK NUMBER MOV M,A ; PUT INTO FCB START3$DISK EQU $ XCHG ; FCB INTO DE MVI C,15 ; OPEN FILE CALL @BDOS CPI 255 ; NOT PRESENT? LEAVE EQU $ POP D ; GET THE FCB AGAIN(AND CLEAN UP STACK) PUSH PSW ; SAVE OPEN STATUS ON FILE LXI H,36 DAD D LDA FILEUA ; GET THE USER AREA FOR THE FILE MOV M,A ; PUT USER AREA INTO FCB POP PSW RET ; RESET$SYSTEM EQU $ PUSH PSW LDA CUR$USER ; CHECK USER CPI 0FFH ; 0FFH=NO CHANGEUT EOF IF NOT 00 IF @SECT>255 ;; CHECK HIGH ORDER BYTE ALSO MOV A,H ANI (@SECT-1) SHR 8 JNZ PEOF ;;PUT EOF IF NOT 00 ENDIF ;; ARRIVE HERE IF END OF BUFFER, SET LENGTH ;; AND WRITE ONE MORE BYTE TO CLEAR BUFFS SHLD ?F&LEN ;;SET TO SHORTER LENGTH PEOF EQU $ MVI A,EOF ;;WRITE ANOTHER EOF PUSH PSW ;;SAVE ZERO FLAG CALL PUT&?F POP PSW ;;RECALL ZERO FLAG JNZ EOB? ;;NON ZERO IF MORE ;; BUFFERS HAVE BEEN WRITTEN, CLOSE FILE IF ?F&PUB LDA FCB&?F+36 ;; GET USER AREA OF FILE CPI 0FFH FID IRP ?F, MVI C,@DEL LXI D,FCB&?F CALL @BDOS ENDM ;;OF THE IRP ENDM ; DIRECT MACRO FID ;; PERFORM DIRECTORY SEARCH FOR FILE ;; SETS ZERO FLAG IF NOT PRESENT LXI D,FCB&FID MVI C,@DIR CALL @BDOS INR A ;00 IF NOT PRESENT ENDM ; RENAME MACRO NEW,OLD ;; RENAME FILE GIVEN BY "OLD" TO "NEW" LOCAL PSUB,REN0 ;; INCLUDE THE RENAME SUBROUTINE ONCE JMP PSUB @RENS EQU $ ;;RENAME SUBROUTINE, HL IS ADDRESS OF ;;OLD FCB, DE IS ADDRESS OF NEW FCB PUSH H ;;SAVE FOR RENAME LXI ENDM ; GET MACRO DEV ;; READ CHARACTER FROM DEVICE IF @&DEV <= @LST ;; SIMPLE INPUT MVI C,@&DEV CALL @BDOS ELSE CALL GET&DEV ENDM ; POPEN MACRO NOLOC ; DE is assumed to point to the file FCB on entry OPEN SET 0FH LOCAL PSUB,LEAVE ;OPEN MAST.CAT * OPTION 1: TRY TO OPEN FILE IN CURRENT USER NUMBER ON CURRENT DISK JMP PSUB @OPEN EQU $ PUSH D ; save the FCB MVI A,0FFH ; DECLARE CURRENT USER AREA ON FILE STA FILEUA MVI C,12 ; GET VERSION NUMBER CALL @BDOS MOV A,H ; CP/GET BACK FCB PUSH D ; PRESERVE THE STACK MVI C,OPEN CALL @BDOS ; TRY TO OPEN FILE AGAIN CPI 255 ; NOT PRESENT? JNZ LEAVE ENDIF ; NUL NOLOC * OPTION 3: TRY TO OPEN FILE IN USER 0 ON DEFAULT DISK IF NOT CURRENT DISK START2$DISK EQU $ MVI C,25 ; DETERMINE IF CURRENT DISK IS THE DEFAULT CALL @BDOS MOV C,A LDA DEFAULT$DISK ; CHECK IF AT DEFAULT DISK CMP C IF NUL NOLOC JZ LEAVE ;FAILURE TO OPEN SINCE NOTHING LEFT TO TRY ENDIF POP H ; FCB INTO HL PUSH H ; PRESERVE STACK IF JZ RESET$RET MOV E,A ; USER IN E MVI C,32 ; GET/SET USER CODE CALL @BDOS RESET$RET EQU $ POP PSW RET FILEUA EQU $ DS 1 PSUB EQU $ POPEN MACRO CALL @OPEN ENDM POPEN ENDM  UP STACK) PUSH PSW ; SAVE OPEN STATUS ON FILE LXI H,36 DAD D LDA FILEUA ; GET THE USER AREA FOR THE FILE MOV M,A ; PUT USER AREA INTO FCB POP PSW RET ; RESET$SYSTEM EQU $ PUSH PSW LDA CUR$USER ; CHECK USER CPI 0FFH ; 0FFH=NO CHANGE   RSUBD%9*P59-eS&HB`0 f0 D8D"i$R'b@1GM@!"JrLd$$GM!"JrTPRSRDH%=%9&$TTYSTRSbEEEH1AQ=R$OSEXTUd5$T A5]I&P5"ER@*b11`0T`XF^b,3h-!@*D"! l H#*>jYnò Vv@?vڮWͧ Ea p \ .K@#*@=AQJ2 U#"M]2 c)Q=UR2.ISL#%9%R:2SSc`1AQ=R2QSTc=MaR:RDe4dA196$$OEIP TQ RBD48IMB$$RSP2 ՔRBE5e(Q J$530 "$$STKPUQ bBE$EI$$INWK bBDD4 UI:$$VSTR BD4ň1$$IOVF ՑbBED$x=Y$$OODE QbBE%tX=$$MOVF `bBEDU(MQ$$ERRV STdDU$Q1:$$MADRQST`bBDc$$F0.5  `bBD55E( 9R$$DATP UbBDdAQI%2$$DKCF bDDd%8$IN$CH  bBE%5D%AR$$FRPT TQ bBD4=A$WRTCR Q bBETT=AQJ$$TOUT U bBEu$c]I$$@Di7T 8Ͷ,:66H 6Zzo dxڹ ,a4fXҸ,L|M"f?/6 'Ad9Ng5|fmqXtl| f)GgUM#3 p\0O"uYEmV+CXnQVdZ.Kdˀ%@@ kX\.K% pP0\.K%@@ p`\2. K@% q\L.'K%ŀ q\h.7K%` q\.B"K@%p r@0\Ą( HHIiq HH ĄjIְ,HH`\alĄƱ HHĄ* HHĄ HH#Ąi HHa;ĄH1@Hh\afHj\afHi*HȑHĈJJ Q HP,Hĉ)Ĉ( HHĉ)Ĉɑ` Ha~ĉ))1`,Hĉh HĊ*  H]2ĊJjQր H)QTԠbDU%%E(IIAJP5d@ ?TlzeQN#yQ Ln:O)o9 &T`DRTN'CAt2T< im0 n!d(QH*`HeI HaH)ӀSRD)@քa SQQe=R:T#1 A59R<TPc A5YI:<UԒc2 A5]I6pQV d5$x A5]I6CPMENTG@2j*rp!&#2jlPBD4IU:P5f E2@lC14C$\h@"44)8ͦP!"Qp#Ym%[a0 2C10#W gjڠ6df0݀!@#Ep%^uTO*0E&EP4$RBDh$$RSPBD4@$DKC0BE%T$ZROd5TH̘CPMWRMdDU$dhXDIRTMPdd NAMFILSU RD9$STP VU bBPUDS SbBE$D8YIM:P5ta 0 KA EJ ux63i(I[HB]l ɠͰE$%3i(@eU(#o1FrXU<|`@Lȇ`"!pEaf 0lWl+|]0%PffѰ!VtE0@"\p.E@UVb; jʢ-Vmui(0Nb3EI@{fqb V |2 hó` Q9'J SDF~L4p VeU@LF~M6p#+.QKDb1OVU`? $Bk@ Ͳ`Q$t2`r9Bho &(u6 j)[@ ~WZhi HH"ĄH(@ HHĄ *ְ,HH`\apĄƱ HHĄ) HHĄ HHĄh1 HHĄ)q۰ HH,Ą*( HHĄ H@,HH4Ą))@ HHDĄʩq HHĄ舱 HH<Ą Qp HHĄ ɱ HH4Ą q HH7Ą ɑڐ HHFĄIȈq HH8Jj ,HHe'ĄJj HHĄhqۀ HHĄi HHĄjj0*HHPĄjJqѰ*HHQHHĄH HH?Ąꪑ` HHLĄJicr gCg#ia  m8 HS*Hh7N)oy Ɠ) '#1MC)a6#4!L1e5#MQ8tSslB0cI &̎Ql2&Ñd< +rD4bH "Fi6Daa2DStyH@F:Iu: @E79# @R2# u6"d&(a6HeCy@M0"1eyʦn:LF(r9@$$TCRbDU%%($ERRTRbEEERSV`BD@p1ZCUfq4X,p2.I  IMB: S" QQe%:2 T'Ԗ BE%IhP5UfZ h* :<͠ ) rY(YTpaH!  `COV(Mh" 3n(eV]4hER@`*U`(HVaph,Papmif H\@`E; ,r84 0"3n(4f4uX,hڵ +0PWXf`8g<YT r aR0y,<, 66 ¤`'L_5LVdeS*l 6x"eT0ZYZ_UC U aV0mDmV)ZET|FeYX² #`CzOYVDV~VF6k %n; j@)!"bf!Fn)!"e#$   (FI@1!"J $d$)C@1!"b2jd))F@1!"bЕQT`RDĕ@Ԍ1ZQP|Zf m $T:c"@ M22*I  %1B2@ Tc IMB:ITc# MM2ЕQЕQ4%Th UAQJP.ˀc U<Qѓ RDdD1 P5Xf+U@ $#3XBDX`e p @@vjX7Fv" b3V91 HHĄɨQ HH.ĄH H(ɈQ  ȈHHѓ ȅȈ*0 \8Ք BEeI@Ԅ >@P!O @KEɌbBDd($$RSPbBED$*.QU(?8G`sJǀ 6@â,. dZRe2 =] 6 E§dOaXڷ@/S_x` œĄi HH Ą*q0HHMĄ ѝ HHdJjpHHyiHHĄH10H{(q H` Q H` @ Hb- (Q` Hb? (Ԁ HdQ HQՠ Hdc HHꪑ 8ԒTBEu$@| $$WRF0BEu$RE#)@$3@Ą J HH F1 H`8 RE#I@,5Y`RE#Y@X!@ ,X$$FILPbBDE($$POUTbBETdȐ$$WRIRE#Y`bBE%XAIVP 5=f VF@- %0ma# CV@@-T4e@,2@GRT$da_ [h5GXn­fRV"EXyXTLvUf6Wp DXreXYWʶ60 p@m݅NXXrC|~@¼+ 8Hcͦ`Lv/ٴ~,06U(V>2# U_e_@6U_0`_U`*a^#mT6QI:$TRFML@@SlV>-@hmpZ,$|PLdl#) G)!"btd*)#&FH1!"Att&$ B@!"t*)#GJ!"td**,F@@1"ʚTT BDU$I2P51j@`D %f `D eg[E41P HH+d(Q HIHĈ誈(Ԕ BE%3 @\t)@qYW2 TQ#!M2( RT# I]=: 'ԔӠBE%4@t)@T 14ҥZٕM0ڥ#tP^2 j+eH$$ERADbBDT($$RWOEbDtUD*+?? hX,ò ~R2 1mΆ`4Ӑh`P'Hu+U ?:!Xh aU[nSof@* .K%p$$CLSBD5E80 $$DTSbBDU%%hȸ$$FILPbBDH$$RSPRBE4(͈$$VRSNɀ2D8˸$DACD$IPUADT(x$SASA.EEEBUFd%TeE(ʨFINddD$0FRCDBLde$4HPFRCSNGedE S`RD%92P5#qXFjeYb[4h@:p2* U%9222I %828 #!x$VPTdDDe8xDERBFNddBDIREcAX $PV0CI REcAX $PV1CIQ REc$AX $PV2CI bBD4y@3k`h60 63lh60 63k`i(60 63li60 63k`jH60 63lj60 `#ƀ1ZP0h1ZP0 e & aX vGfpf x3k Nʷ Fö` hY,P~S@ķ 6V`ufVQH3o< .̯,( Fͺ ;͡.3h |"a)t) K6(=eT0F~U *l 7FB@1!"d)))A@1"t()"NRE#8AH P5hfŻ 1ZS4TdaH@ @ - %01Z7FpiV  ϋVWh\,02vI #%1B2 P%=A2B & AU22I #'Q1I2I #,] 12hI ԒcAH:c$]IQ J2T"I 62SLRE#i@$3@Ą J HH F H`8`RE#@X!@ ,X$$FILPbBDE(x$$PUFLbBEDUHȐ$$WRIRE#_\ud^È"p F2H Fʫ/c ʀ1{0 ʶ'Fʱ -Pj |5Fxk (#a`[D+9 +<-WX º#C+O,C< _ ==qsE `K6O6m<-WB ~O,2@ sGxY2 FXe/S|+bP'&\.K%@ HH(ĄjjQHHĄ*q HHĄ J0 HH(Ą ђ HHJjp HHĄjQ*HH J H] ꪑ 8ԒU RBEu$@$BݓĄH HH8S`RDĔH$RSNdDU$T`RE$U4@Dt)@#+:*錇bBDT($$RWOERE$U4Q`RDTt=8P5+qK2"m%!T :Pf70Ș$$AOERbBDU$Hȸ$$OEIPBDdX$GETADRDTtp$ON0TBDU%)@԰~phNePsDZ, 0L x$$CLSBDU%(Ȩ$FOERED$8$TTYOTV BDU= R$HXF ѥXhj@hâ` jj 3hx͠ å 4jj jv2<8YEW@` 28)GQxaV[KvUzWj1 I^ e   Xp(V@u\$dH)!"2 d!)J)!"t8$"G@!"B4d|&#$ F@!"z4t'FR@2222RE41A=$POSBIХQ`P&2E@fk%A8$$POUTbBEDUH0$LPOARD($POSARE4)PRED$Q $SPCAIХV0VͩP{%TPF=z â$a W)UBͪF8ZXF/7 RBE4d(x$EQCARDtT4$GTCARDT4$LTCARDT4РRDD4(Q $LECBIPРRDT4(E P5 #|bB>8ZXF/7 RBDDd(x$EQCBRDtT4($GTCBRDT4($LTCBRDT4)RDD48Q $LECCIPRDT48E P5#|bB>8ZXF 028I ѐ# :ITP  :I1 :I㡀9 piH1 HiHq H8QS RDT@0Ո֯`P0DX~ F 2ufcx>&m*hj ,"^. F& ,p` !4Uc d0 p\.FX1!" *b,t S"iUBDD@0$$SVRSBDD ATANBD49@0$$SVRSBD48 COSV BDU @0$$SVRSBDU EXPђV BDd@0$$SVRBDd AINTS BDI@(3@ ɌRBE5e( $FATBDd($INTBDy@0$$SVRSBDx COSV BDUI@0$$SVRSBDUH DEXPђQ BDdI@L3@C3@2c MYJ2I%2 Qc" 9VpS BDI@(3@ ɌRBE5e(8$DFLRBDH $MFM BDI@0$$SVRSBDH DLOGQ BE4I@0$$SVRSBE4H DSINQ BE5I@0$$SVRSBE5H DSQRTQ BEDI@Ԭ1ZWX3@ @fаf- &\.FF@)!"d))FD!"" d"*@!" $d@"!G""JtVRD$U( a$BEXFI",h\bdmh3mhxFf ;N͵XFun8X ? " 6hjEX * aXn ?o31ɗK@%`Px$$CPX̀RBD5D$$RSPbBEd$AB2DX$BSUARD%5T($BSUCRD%5TH$BSUERD%5Th $BSUGRD%5T$DADA2DD(Ϡ$DURDEdD$DVDBRDEdD8 $DVDDRDEdDX@$DVDFRDEdDx`$DVDHRDdD`$FADBRDdD8$FADDRDdDX$FADFRDdDx$FADHRDdT $FMUBRDdT8@$FMUDRDdTX`$FMUFRDdTx@$FMUH2D(ϐ4td($SGFCRE4tdITӠRDd4M $FASIITҠRDd4M:$FASOIT%T /6xFV٠dT#+nVmh\nK^r@ EWڥXFuihFH@)!"d!!"G@@)"2 t# GE)"2 LtT# GJ@)"2 lt# GL)"2 |t# NQ RDd1! $LFMAIPQPu@ EWڬdD)!"d!!$G@@)"b2B t&#$!GC)"b2j t,&#&NST RDD1Q5 $STMAIPR /ܬ-%qK7+63@RBD5D$$CXBDbBD5$$LTMARDD($STMARE5D) RDD4HQ $LECDIP RDT4HE P5#|bB>8ZXF 028I # :ITP#  :I#1 :I#9 p`RDD4XQ $LECEIP`RDT4XE P5#|bB>8Z@j1 HHd(q H h0 Hh H ȨhѠRDD4hQ $LECFIPѠRDT4hE P5#|bB>8Z@j1 HH(q H h0 Hh H ȨhӀRDD4xQ $LECGIPRDT4x   E P5#|bB>8ZXFĄ HH(hА Hh` Hh H8 RDD4Q "$LECHIP RDT4E "P5#|bB>8ZXFĄ HH(iА Hi` Hi H8`RDD4Q &$LECIIP`RDT4E &$LTCJIҠRDT4 *$NECJITPҥRB>Ga!D#u$*@LZT|R@@d(q H(iQА H iQ0 HiQ` HiQ HiQDHQ)$LEJDIR RDTHE)P5(tl|aѰF6Xtl|qK2!`d"#%FH!"" td""GC)":*R$t#%"GB)"b*R$t&*%"GE)"r*R$`RDDXQ)$LEJEIR`RDTXE)P5)tl|aѰF6Xtl|qK7+4 02BI c$M*2HP E):IRcQ):IRc1Q):(IRgRDDhQ)$LEJFIRRDThE)P5)tl|aѰF6Xtl|qK7+4 02BI c$*2H P E):IRQ):IR1Q):(IRRQ)*$LEJJIRRDTE)*P5'tl|aѰF6Xtl|q\B0$$D0.0RBDDd$DACRDUx$GEJJRDuDP$LEJJRDD$NEJJѐRBE4d( P5b@` b@KGf DeQۅdA)!""2d@#!G@)!"2ђRBE4d*P5$b@` b@KGf  G31H@b6Q HHhSQ`RD4D@0$$SVR2D48$CIDAT`RD44@0$$SVR2D4$CISAQ RD4E A $CSPAIQ>[4a`@@DEd%Y $IDVFIQRDEdX%YP53uڥXFf Bplm bYEf@E,[^nRBE%5$D9RDEd$IDVBRDEd8@$IDVDRDEdX$IDVFSUP`RDT%5U$IMUBISUPRDTX%5UP5fuڥXFbYu\n jYh0juұ|S*~UY!Kj:.MOw\x*USzq*gdH1!"Jz4t$E)"Jjt\$@)"Jj$t\$E)"Jj4SUQRDTx%5U*$IMUHISUR`RDT%5U2P5uڥXFf[dXd@)"Jjà@&0y>g>:$iq HH\ĄƱ HH`\kĄi HHCJjP HHhĄJiё HHHj\ard(QH_d*А Hpg (Qp Hp@g (Р Hi)QӀ HAi)ȑH1 (3T bBDd4 @BF=d*.~Sg~S !Xi\ /uج Lt#!NԑP`RE$TI $REACIPQ RE%5DIMQ P5,f V H ȨiS`RDDQ)$LEJAIR`RDTE)P5*tl|aѰF6Xtl|qK2^n6(hQѐ HH1P H H1 HȩH3RDD(Q) $LEJBIRRDT(E) P5*tl|aѰF6Xtl|qK2^n6(Qѐ HHQP H HQ HȩHSRDD8Q)$LEJCIRRDT8E)P5(tl|aѰF6Xtl|qK2!`d)%FH" td"!C)":*Rt#%!B)"b*Rt&*%!E)"r*R RDDDxQ)$LEJGIRRDTxE)P5)tl|aѰF6Xtl|qK2!l02F  #$M*:2ITR): I@1):I㢀9)p RDDQ)"$LEJHIR RDTE)"P5)tl|aѰF6Xtl|qK2!l02F  #$*:2ITR#)": I#@1)":I#9)"p`RDDQ)&$LEJIIR`RDTE)&P5'tl|aѰF6Xtl|q\B0$$F0.0RBE4d$ACRDUx$GEJIRDuDP$LEJIRDD$NEJIRDDBtT22 #"@MYJ:Ic A 2 MA: I# fpS`RD4@<~ЦH/R<`d4$#G@)"Jr P`RDDT4@<KfJ/Z>`d4$#G@)""* PQ`RDD@(U>Jǃ bBDdh$IADATА`RD4$@D>ѝxĄ) H8S RDD5= $MODFISRDDX5=P5HuڥXFf @plm jٴf@+TeSՕNwU/hY.T#+8l:Jj Hs10 Hq H舱0 H7蓀QR)"Jj\t@$FD"i`RE4@P~ޯ> U* a HHi 3P`BD$@x0$ABIRETԔP`RE4t@,d Sqὀ-d@)":J SR`RETԔ@8@-Y@*oN%L($$IOVFRETԔ S BCBԸ$C8IAIPRD4 %9 $V8IAIPRD3H %9$CINDMG^/e{6=Xtdf^bYfE,Ő|[`^͢VG{+ٴWXڠå wgP0*΀@huuU@@!H-ޮcH]@R@0 H46`n²x9^odkHbyDt@@W+63@mf|amb\44|pYdixfX0 "r;*.UF aUh&yh( 2gd+<@4uX, 2a[ "b FVʹ6+T##ܢf~"|L46`qY0()ٖUs@zfͿ@DDb+S0ۀ+/:T`͠,02NI 2 QN2F U#`8QB2I Sգ `8==2I #>IMQ>2T Q 4M= 2 '` 2N P03FUQ#I:(IPPI:IPQ#IMQ;   I3@MM3ђS#%9 22H#'I %9R2ӑT`RE44MM$SASBMQ5)#[±[jlVVnݕLg!Y, ͠ W[64Y-Sx,($$CFTbBD5E4HȘ$$FSSRBDeD$$MOVRBE%5$SASAbE44$SASBSRQ RDBD@ E.1` ɄV JG%=K@2`423X8Z,L\.bBDDE8$$FARGRBDh$MD$A`RD4TIMP5R %Trdͩ #3]l`+UK*`#3ou31ͣ@mIpX,:@e *&)#C@!"$t)GH!"$BD4)@P !# 4xc" QN2I # Q1I: BE5E(MQ&$STDMTjL:N͠ PtC@|z٠d1Gf >p4p@!FaT0Å0Z,p 2I &  a 2z #$5=Z22I #" 2: PMQ: cMQJ2hU#%Y1QeBpRBDԴ5-N$MKDMF!tH|f 0\.RBD5E8Ș$$RSPBDԴH$MKIBDԵ9`RDE4QM$LESAIT`RDU4EMP5$tl|aѰF6X`@[6 ɗK@#-@%QN2 %: Ṭ %MRpє`RDe$THP5W`%3@P#+``B@ ( HHjQ H(fqP HHH1H8S`RDT@(fxɌbBDDE8$LENASRDT)@\e QxFVM4xLd@"$)@1!"b{JBX &|M4Y.V(9~+"y`Y,Vͦ.3í8Z,KjٴqDd&Xv]Z ڈñLVUGbBf ͸LͨNVmpb6pX,mf!i7qq \ E0mf߰j)CH $SlNG#y@-·#I ) &3(o9$F'QVP)0&xM4%DXV6 )3;Z,XV6b6HX@DU@g䘌iQh eXFm[՜ 3i(D"5Xv |Z@a0L&2F~E7(e`-KU]X M?2ڣ@/+aܐYbnU@g|F~LV PX`Vs#db6%!޴e]&mka\'[$xd:X7FwX؀#9B0"BQ1>gq#;lۨ bX+8$K0 p(` p`a p a p a p!b@ q 'b qP-c q3` $$ATSBD4eH͐$$CLSƀBD54 $$CTSրBD5E4H $$DITSBDEE8 $$FSSRBDeD$$GSTRRBDx8 $$MOVځbBDdh$$RSSbBE4eH($$SFTCbBE4et($$SLWAbBE4dh$$STKPbBE5E5XȐ$CDEHLRDDDȸ$OSEXTbEEE RE5uM]A $SWP`BDt@@a=@2@ɌbBEUHH$$TLRGBDtӕS BDT@(aѐɌbBDT8$$TLRGBDTS RD@8aєfp{&2 S `Q1I:ISgU`RDUD@4aє=8d,'+@1!"b 6*Tl$dX`dL$+G1!"b 1>; 6 ݅t^.xWx/3E ( +ͦ.ˀC,N{Sˀ%  p\N- @fc0}K%@ qph J@< W2X0~ @ZeT'R@lLUYUl EaXP'+6?&2ʮ`O⋅aXeY!g+*?lʳO# ځ-ٷ X6с6Qm@2/(h򎁰fP 6f߰K6V u$ j@.Q rl öKvmf@&rXVe.x*(dۮrSڷpA'gAٶ fZ`΃Yʹ!`1(Jt_¦U^ fpGp], `¢6miQpaXVwxh3u^,.  Y.Pj20F3lXX  6VHl@`36)P;R$zYvmfuփؗp÷`݉Fo b_t ^'<>2I&Vmaڀfm"H0m$fC$`A+RO&!@L;X! ;~AgQ\F~D,nC f +dXpM`60UO@nQT8ܮK6T,iI? !`%XFNl a L@ >L$a`#X;`V`dj nFB4QfנSWpՐ| K6@ kYCua@lYu$+w20պ$@hHͧv{V L^,0ëlژ͹` fmLfP]fАm`Xw4<aڀ%\'fӰ7I?<I@-^/ԓw :]1x]{w^ͯ@`C*nmu` ZrhTW 8jς+Ұ`b8P} eTPC*aTPCۘ¨62(#ʬ#*? 2(#\­2 tn`#VpdP m u U$W[^2@6e\Gkկvw8³ E"HHql%[*t:# *, #?-WPTHi0)l [ SxM\Xfِ[jˀR*v $4ͷ a6xX"?h?0(R-Kajo  a$1Yh:Is "`t ^2BDtUHIRQx5f VsAY@"p$eSSʧ`3݅LK60XtD|KH 5)9d !1 bږ:DeP=aV$٠ 2B%K2L+9YeWV+U!Z>nh+*1AEM0؀9\H4â`"8~[*0ERmj`kX3dl}fVU "` UIVn3X,mbOۚ ʺn,Kz6PjHרDN +28F0FzӃ*A`NHlVscdlpȄ([Dg!ô"h{ e*π^V(GLۂjmyh^'vLjl Dx³ 6ƀU@ۘwp h   !'Hr. 64\/ep(~`V`XQU??l(OvUcT<~[X,YnʡL(¼#w |d( T] DI8FF"3F c`5K,t3h*|aT@!wKX84Ͳ.ͼ@-hn?`1\*#`lX,)n2k/M(N* Â8eW#Xڳ@OJtï~ W u@#wb0 ׁ+Zpz@$(ڻ L P*ʹ Ca^&fް+Ufp X#m 218\:a hͦnbnʡ2p+n) U _ĖU &QC ʻo2^,p] .2D8G@<UW(kP UW &]b.ZKZYEV+6Z.KT # ^A\,p`Z.[KeAYaVmWa-paڀVm{XvlU-njX@\:w]n.]KsAT "iZn´,`D $E $2"()ї#h誑`ɨ+ Iq"j BhjQ *HjsSU bDDD@>@P !` a # RBD48Ȱ$$FILPbBDd(p$FOEbDD4$IN$CMbDDDȈDERBFMdDU$$d INDSKCSUBDH%8 6P5Bfœ2t-@T8"D1Zh3 |riUG.H&å $*q HHĄHHIĉ)Ĉ(@ HH ĉ)Ĉi HHĊ))ё 8SPdD4(%9AIRPOPAHTT`dDU$JuL +f SfӠh!eG,:͢@EU4nʭ6+Ut5@UV@ ʢ FYD@6 D>00·?L+jFmC`hhXuL mU0|e^Ffp)Tmf@*?ê.ɌbBDdH$TYPTXd$Ĕ0BUF5$D̘CTRLPTT4(HLISPRTTUDDPRUBSWUUS D5$D=UQ>CTRLPTT T4(IU M^P52a 0>/3h 3h63n( 5p@WI@."|AmfF6Ղ?+dhY'6* jجhD"dh¥ 1 ƇO^+vR3. #15 3lI Sգ7@IMB2 I <`Q=UR=f T#-;Iˣ- :v -6: ӣ P-J: Sѣ%2:  # R2 SQ#)@%8.2 S#`1=; ѣAUR;r #IAR:> ̣iI>2* QS#&Y A5I2U*  A5]I&0Uԓc>@ I>8RUѐ Q=N9Rː.@yI 62 TI I:2T#'`yI3,TS6I92TSc;YI952j TQ%IQ5B2^QT !9d U#1=9` `A!f9R V=`9%1%Z=SL%196>ѝf֐1Xnʤ`!uWͨ.)*Vfp(X,~>ѝj#`pZ,KP\,R!4Ubͮ.(X,:W+U* rfcxMz'1ɅYGUnʮ`"bD2@- %~ `Ņ^X,U"Y3nIn!!%a eZ3,fUfP C'Edjj$#+2Bb 9L!5s@Zێhj &\.K% HHJj@ HHiHq Ȉi Q IȈHJIћphJQ \ȅȈ* \ȅ q\ȅi+Q $dI I:DERDFLTQ`dDU$dI9DERFOVTS`dDU$hIQ5FCERRPV SI}I\D8Y/ $|6>Gàn @#|3 >@x%ɰ$$CLSBDdXDCOMPRdDU$$dDERBFNdDU$%$DERDFLdDU$dXDERFAOdDU$dh8DERFOVdDU$XhDERNMFdDU%DhFCERRdd%HMAXTRKeHXPTRFILԓRBE$9@H@!@ bBDd$$RLCRBE5e(ȀBINLIN4%ThhBUFPTRRSSd$Ĕ@ t9L*"83@E qpeFT ʢ ꪈ 8 RBEt4] $$WCLFMq eQp+2,̯ܵC2? P4cUW eX` 4V(#biQ/HSeVE6EY/%a*#` $j2Gm?\vp\+,͠pGmttYW | fp)oX.F[@1!""Zde&()#FP1!"rbe' Fi1!"zf('Ff1!"zt+Ge1!"Atv+#Fp@1"bze8**,N RBD5 A$$CPADMC#r@ &:I c A:I #! a "pRBD3D( $$CX    B  bBD5$@Դn!TpB0#@Tp#Bw b0&# b0&#dG)!"t\!!GF)!"t4!!"G@1!"Dd< E@!"" RBEda=$$XFOXMJ*>1@ P($~b7E,dˀ% HHĄ HHd(qH8РRBE4)@4F~T ePLt)NQ`RDDD@ oh 1 H8SՠRBDi@8NbGp   Lt&NPR bD4DT@`$CDEHLԑU 2D $A3Q 2D$h 2$POS2ET $AC P̠BD38 $POS2 PK@% w].zK%  w].ˁe2pp@ x Nj@!!""{$"G!!"*{D$Ǵ!!"Ix ǀ@" x  Ǿ" { G!" { ǿ!" x Ga" <{ #Gi" 9x #ǂ" x(!"ǂ"4x4!&G"$xD!G!"" {" G@""x"!G""$x""NJ@""4x"&G""x"*!#G1""1x"*!#nj1""1x"*!#Ǎ1""1x"*!# ǯ""{"+ǰ"*4{ "&#DZ"2{#&G@"2{<#+Ǵ":4{T$ǵ"Q{\%G"Q{d%G"Q{l%G"Q{t%G"j4{|'*G"{Q8c>Ӑ?*iFc1L? RT?@3@:gٰ+4 ڔ 4eW0@+4 k4hC@`f!u2 P5 V2T #2`%X3Iӑc/A!38Ṣ4A%<32I#2AA3TQ92 L,@563Uc)93Dc3 MV2TP0 aQ:QUSDD49`t"!@`d"($FA" d(")@@!"j2lSbDE4QM%:ki)0 Hb 4f 3@h!4zpfѐhzR >aC2DȠ$CC2D4ȸ$XARACBDh$ARGV bDDUQaBk:  HbU/N z{m醢tBiNg z@ҮР^iD LFBHT8@@ 2fi[!l4 uUUz@h!T@43@h! BY4f4f3k̀3@"`04} 03l Qc- 5V3( P.@A!2I+ 2Ic, 9V2 /A1b2 0A1f3c153"I6`=93<Uc4 ME3NUT5I3r Q7i30IU65U12IQ7=Yp,0@,@hʰ@n@xGh4fA4Ijj3@{h$} 85<*~!`V?a \(fQHg4( H0*HQ HgUĈ*(q` HdhqHf(qҐ Ha*ѓ HHdQ HqĈiq HnĈH1 Hqd0Hd1Hĉ*HpHċ*H(sRDDd)@BdfhW3 Nf"H~llɌBD3(ɠ$DACRDD3`2D8 $CD 2DD8 $DE 2DEJ$DV2E$8 $REC  2DTh $FL TBBDT B$FWѠBBD$$IM`2D( ($J4Q2E( A2$PRRDTdx M$SG2ED8 QN$DTBFAIbDED$cQ $DTBF5bDED$cI1>FACQP4$x 1>DFAC PRDD3I$ARGIT̠RD$s8 ($J62D =P.K%` p@(\. K@%Ġ`\R.*K@% q\j.6K%  v].dK%٠ vD].kK% vl].oK% w].u(&G!"z{('G"{()Ǻ"{,)"ǻ@"4{)ǻ"\{)Ǽ"{*)ǽ"tx#ǀj :b|{"# ǽ2"2 b|{ Ǿ*2 b|֔BE$@$l-*ɎBE$QT!TE5%I0t)*3@C@}> |z@h4 Dz¢3B!0" 562 P%520I#`A!2<IU$ AA2HIQ$2TUc&AA2 T(52vITPDD%98t" )@Ɍ2DX$MFMQUSTDDQ9P5#5> Bm>p> `V>Ei1~JaIZX]eXNWN rS (BB `&s3S(syMZ;qDhtZ1sTfBm(8$MFMbDDc%8$MURDEhh$DFLRRDEɰ$NURDDDhx$DF42E5X$SAFBDDc($DPLX2DYU`2DU( FDBLEXPGG"*t"GC"*8Y4a`+68Y4 B2hʬ@W!U8Y` ! N0Z~&r~&ZH~$$} vc0QTRTBDd$MMFBD38x$DSQR2RDDX$MAFBDD( $DIVF2DXɀ$DPLXbDD3(ɰ$SUbDED$cP$MUbDDs(ʘ$ERR2D49T bDD4U =5BjtĈi H` inʦ@ 6'r@q `V"`CK6,:*(fQ0H*Hq H8h(3U2DEX%X$DIVF2DE@$DFLRbDD$$DRNDARDE4(X$SAFBEUI RDEŘY 1A1fjx P H"4Pmf 0D4(8\/!Ѡhr@$2D $DPHFBE5hȀ$DPPARDTh$MMFBDdɐ$MU2DYU 2DXI9$SUS bDTDH$DSHFLbDTE8UMN$DRNDAIP2E5( MF$ART`bE$855$MAF Q`RDDu(9H$DPHAIRDEAA$SQF 2DXQ@$DSQR3 bDE(A%<$DONEIUSRDDdh$DF4`bDDs(19L$DM2TBDE !   5J$MQMh  $XT hh @4 :t!FVNG*zti h`DgUn Oa`fԀm7f0Ugti(S*@p&kv*ـ Py@Y aYdtxB3@YE*XD&̺a*&<&l( rh3@rhjH3@̀{b +8XTTE Bq@ OL.rl.r $GO.-.Ve?fhh@>?IQ,aЀ$AC3BDC$EBBDT#8X$EB4BDT#X$EXPBBDd5ȸ$FLR0RDs(P$MARRD#$MB0BD$ɐ$PHABE4iӑQ2D($NUMC n BD38$EB4zO hfVhaȰ$PHABD$Ȑ$MB0BDX$MB01BD$ɘ$AB0P`2D($AB0`2E4(M$SB0Q&Ht$: Pt$ 2`$AB0 vPiQx?-*fwð Q (fՠ%ʟz!(cJ08~ `\dYtͽ@ ï`NVmpop G@,ͭL;.f 63h0 d  FT" g G^" ""4f( "\" u Ff" c% 2c 2t# *: b:Rc j2 P R2N Qc&I92, Q%@UA.: c%%9R:Lӑ'Q`bDd$x5YI$MFM QA1A@qX<à`H(qpHgɱ HĉHP Hc8T!E5%It)*3@C꜀Q.G#՚5X4`Yf z 3iՀmx*0+Cɔ9`h#CKT3lIAC@!"2 d($FR" d\")FH@)"jd($ I!"2bd(( K)"d)FS!"*eH(&,NUSbDDA%<$FONEUS"Ĉ*)1 HeȬC@9@  DTCTA'p͢` !Vh!` fCXͤ50P0 .@b!0yTP) P1HZFH3 1H>*Q`HKFHWdhSRS bDCQ%9Rj$))ʑ0 HbW/2D($NUBE4iIVDU)t"(!!MƆ/f `YT3@D%0Q,h`, q1݈4:! c  2 c" 1J28 T#M2J c%52j PT'M2v P'=YpI̠bDs#1=LOG2G@)"bz94bDs# fP$LOG21 @!  t0Z,0w%JQ}LǷ(8Q( NPqHJQHg 1H ɊPHa8  BEŘQA=1fjr hf ͢ GE!"b˭@g稍T$SaåpH *FH(pHI@!   H8 Qa4DYt "@TT`evhwV#  2IP#"`UA.26 Ց#ip RDd#M1JjtɊL:I@<zY46>L$.| 1H*FHi f H'IȆ1Hg3Iѐ BDd5 @Ըe͠`{ B+mY"3+?.X+?$ &2  P̣ B2 Q Mp`BDdHI"FLTG@" t#&* ``R!H @pa Hfm`Y&2 P!9J2  ##aJ2( g`BDCVPJ),ҡ@݆aSXp¥vKG >(4-TvtZɅYl*2e0!]a a@"ŻĀ\} ρs8]@@D1Hq5Ċi F1 HcdF1HgIp HaQPH(fqH8TQ bE4CM!)H$SHJR4MF<[quA,@*&Ɍ2D$SHJ41bE4#$SHJR4ՑBDdh=Y$RND0  RE$C@#F@&B<hhH3'(0A#"` 2  T$ 5J: Ց=Y:" # I9:FI gà@ `I^-dC|{;G@!"Bt))GE)"BBD$$MRMRD$$SAF12ECQBE4hM$SAF1MD@ݐ:݀c  2 PM: IQ#MpQBDEi@/#E^vzA-*4'|+B\n3CLt$+NBE4(M!H$SHR1MI!Ce8Å  chdir) )ĝ@ >2/=Y+2/=Y NAMES DIR ZCPR2@w,U 7 P>2.=!9"a 1a I͉x2 y2 o !9" PAGE, Version 1.1:] / PAGE Command -- PAGE is invoked by the following command line: PAGE file1,file2,...,filen o... where each "filen" is an ambiguous file name and type and "o" is zero or more of the following options: 0-9 Select Delay Constant I Inspect and Select Files First L Toggle Numbering of Each Line # O8 !GWXy!v2z0c1c2c3c4c5c6c7c8c9cIiLqPyS02:/2:/2:/2>2z"{z2z* n 1a [ , ʿ" x:x Invalid Disk Specificationä: Gy?:y Invalid User Numberä: Ox2 y2 vZ͉> ͭxE ;$." *| 2 ͧ[x| 1a ͇1] b* ~,¤#Þ ** PAGE Abort ** [x6 x¯: PAGE File Inspect Mode Select ̈́  -- (Y/N/Q=Select IDIVG@"!ˬeR00$D99=-O#@ Vh[(#& 葑H$JSQU`BDtH9J$NGR1IԌ%Qy=&_<~/SEsdɌBD3H$NGDBDu($NGR0RDu# T5)Ht, 3@hhc A!2IPT'N`BDӓQ%5U2j6d'ū!|Z#4M)u$z¡ TREUYU9A .j* bFwREUn'̘$AC2 `BEYAMA1j* "7Lt((( \b* q&2$P! pԓ`BD$9=H$NORMd &aQ֐PRE3iP5 p"1PH(fQHH(f2EC5I$MRM1 PS`2D5I6$MAR0 U BD)@ͤ#8 :pͦVmpY"fHdUHIxFVdan<8$ACBD3(x$FAT2Dx$MAMBD($MAR0BD$$MRMRD$$SAF12ECQBE4hM$SAF1MD@ݐ:݀c  2 PM: IQ#MpQBDEi@/#E^vzA-*4'|+B\n3CLt$+NBE4(M!H$SHR1MI!Ce8 P Toggle Paging Snnnn Skip to Specified Page before Printing Examples: PAGE MYFILE.TXT,*.MAC LI -- Number Lines, Inspect Files PRINT MYFILE.* S25 -- Skip to Page 25 While the displays are being printed, the user may strike ^C to abort PAGE, ^X to skip to next file, ^S to suspend output (any key will resume, and ^C, ^X, P, and 0-9 are effective as commands at this point), P to toggle the paging, or a digit (0-9) to change the speed of the display*a (!" * n w /#~ʘRest/S=Skip Rest/other=Y)? $ͨ5Q>S\N66 x Rest of Files Selected6 x\ Rest of Files NOT Selected~ͣ* " M–x   !""}:t=2  PAGE File: ! ̈́  ͭ File ̈́  NOT Found: O* " -!-! * 6 * 6 * !~#>" *}#"}* ~ ~ʝʺ# ʨ ʼ  _ _6 _* _> 6 y¨_6 _x _6 " >y_>6 _6 _:sG:xGx~"    > 6 ><6 ><6 > 6 > 6 :z: : G@ ͣ :zx : =2 :t2 *#":ú ~ :z@ : ́ S G:z:> 5> 5Ž $ë $ʝ ͨʉpP 0:02:/25: G!+|  :z:*}w: :z:S e ! ̈́  -- Strike Any Key ͣ *#*{|}2zScreen *w -- ~# n +~# ʂ w +#͙ >.5͙ ~5#™ Ʉ4H=;: y4ɯ;:͞:!*#@*?!!44͍ 4:@¾4x4*?͔9͊02@* G!jͷP :lL *uj ~#~#~3 # ; > 3 *|= "u 6*w>"u* }ʬ #~ʬ G#*uʢ • #  è  y ì  •  ͭyc2 : G!jͷ y  6c6~2h#~2i*uU# ~ͨAAh 2h#~:U?.2i#~:UcG~#:L0h h OxG0x h 2i:iO:hG>ɯw+ 786"@,8"w## *uʫO~ͨŸʟ#…*w >Ÿ*w*Aw# *w#~ͨ!=_.:;,<>ɾ">*z |]##~2#~2#~2#^#V#"#^#V#"Â*.;^#"#~2#~2#^#"2*ڟW+}ʰzšÖi`:)=» ^###~))))!o&:/o>?2o"!"o#2.>*DMɯ&`o&~n*#"*u"*| n>~#u>?2o""!"o#ͱ.ž#`o&~nn*#"*u"*| ni*|1DM*x: #3 3?3~w  ~:X@]tt: r:G~t>xʤ ~/W~wʝ?ʝ~w|!""x ~~w*#"*u"÷ ÷*DM~0 !  T]_z#{BBjBóB BWBt͵QAQBQCQDQEQHQLQMbSPcPSWQIQR bBCbDEbHLbAFjIXDjIYdrNZqZrNCqPrPOrPE EPAGE RELPAGE PRN:s>2s*a~>*mͽ:sw#*ms#r*q5O*i*ms#r*q6>:s*_62s> *q~ʏ *a6*e¥>:sw ͳ͠>͠͠͠͠~#h R  ? DDH y yG>GO> 5^2À>2'ͤͤdͤ ͤ}05F}o|gڳ æ}o|gy:> 5ɯ2y05> 5> 5 5555 5 5?r:5H=͈:3 4*@*@*?"?"@"@ bkë4:?2@+5ů2@@ :@ʊ5U :U :_ʔ !Nd  :MO*K> :^ʧ :HX*IT:Yʾ *:» !P:Z :*EG " x   x@ y2 ! @NAMES DIR5# <2@ 5 "f>2h2i$? ~:V b #F >` c *f~:o #˜ .ʘ  >? :hʎ Ͳ ~.¬ #Ͳ Å Å  * >? #² # >  "u"w ͭyc2 :͠2 ͠2 :_͠:_ ͠Y ͠X͠->2`"a"c"f2e!`hh$+9*a~#fo:`կ2i2k 2j2l*cxʨ<~:e~¹:i<=2k_#~G:ex:j2l_ #<ʨ>:i_:k͠:j_:l ͠:kG:lO͠͠2:ͨ>6???????????_ͯ9zʺ9*@}‚:}o~r:{ʗ:a:{_2~:ͨ>6"$** & "u x>2x"`i"*s#r#! xM*"*|g}o""*#"*}|d*"**}o|g"x|x*"tx**YÐ*DM*"*"** y DIRALPHA -- Pointer Error*~#~*u*^#V*u"*^#V!u*##" y*DM+) +) Nq#Nq*DM+) +) N#F^#V`i: # # ~O#~?O#2"PAGE MACPP AGE MACRELCRFPRNL&Z-c D48 CCINT4ĔX(.CODEND̈́QRSw!_^#Vbk$w#*c*g*i!*e>*_~/>*cͭF>Q>*g*ks#r*o6*_6*a~ʄ>*eͭʚ>*i*ms#r*q6*a6*_~>*kͽ|~2s#*ks#r*o5*g*ks#r*o6*k6#6>^5@5*./*. 1O*. D͉x2Yy2Zcb:Y_͠:Z_ ͠Y ͠X͠q͠ ͠OGa{_HͼWHWr# xH  H|&}&~# x ~+ x,!ZF#xP~# By!Z P=PAGE PF?Command error?File not found?Can't enter file~"   J#F!FF!FF!FFXGCOMSCNF",AF