0001 ;============================================================== 0002 ; 0003 ; Program DFILE ( outputref,dirref,/x ) 0004 ; 0005 ; DFILE creates a file of disk directory information suitable 0006 ; for input to a program in a high-level language. See the 0007 ; text for the format of the file records (and see the OutInfo, 0008 ; OutData, and Format routines in this program). 0009 ; 0010 ; outputref is an explicit file reference; that file will 0011 ; receive the output data. The file is opened after the search 0012 ; of the directory, so the output file cannot be described in 0013 ; the output -- although an earlier file of that name may be. 0014 ; 0015 ; The outputref operand is REQUIRED. 0016 ; 0017 ; dirref is a (possibly ambiguous) file reference which is 0018 ; used to filter the directory. Output records will describe 0019 ; directory entries that match dirref. If dirref is omitted, 0020 ; "*.*" will be used in its place. 0021 ; 0022 ; /x (or simply a slash) requests a full directory search, which 0023 ; will return inactive entries and all active entries. The 0024 ; dirref operand has no effect (and may as well be omitted) 0025 ; when /x is given. 0026 ; ***************************************************** 0027 ; * This program was originally published in * 0028 ; * A PROGRAMMER'S NOTEBOOK * 0029 ; * Utilities for CP/M-80 * 0030 ; * by David E. Cortesi * 0031 ; * Copyright (C) Reston Publishing Company Inc. 1983 * 0032 ; ***************************************************** 0033 ;============================================================== 0034 MACLIB CPMEQU 0035 MACLIB PROG 0036 PROLOG 0037 ;============================================================== 0038 ; The Info record data... 0039 InfoRec: 0040 InfoFname db ' ' ; dummy file name 0041 InfoFtype db ' ' ; dummy file type 0042 Info255 db 255 ; info record flag 0043 InfoRpT dw 0 ; DPB.SPT -- records per track 0044 InfoABsize dw 0 ; alloc. blocksize -- 128<<BSH 0045 InfoDSM dw 0 ; DPB.DSM -- blocks per drive 0046 InfoAlloc dw 0 ; count of allocated blocks 0047 InfoOFF dw 0 ; DPB.OFF -- track offset 0048 InfoDRM dw 0 ; DPB.DRM+1 -- # dir. entries 0049 InfoRcount dw 0 ; count of EntRecs following 0050 ;============================================================== 0051 ; The global variables... 0052 Anchor dw 0 ; anchor of the EntRec chain 0053 NextFree dw 0 ; next free byte of storage 0054 StoreLimit dw 0 ; highest byte of free storage 0055 MapSize db 0 ; 08h or 10h -- data map size 0056 OptionX db 0 ; 00h, or '?' if /x found 0057 EntRecCount equ InfoRcount 0058 BASIC equ TRUE ; Output format: BASIC not PASCAL 0059 ;============================================================== 0060 ; defining an EntRec, the augmented directory entry. 0061 EntNext equ 0 ; first word is ->next EntRec 0062 EntMs equ 2 ; map size next 0063 EntAs equ 3 ; allocation count 0064 EntHc equ 4 ; hole/compact "attribute" 0065 EntEntry equ 5 ; the real directory entry 0066 EntUser equ EntEntry+0 0067 EntFname equ EntUser+1 0068 EntFtype equ EntFname+8 0069 EntExtent equ EntFtype+3 0070 EntS1 equ EntExtent+1 0071 EntS2 equ EntS1+1 0072 EntRc equ EntS2+1 0073 EntMap equ EntRc+1 0074 EntEndMap equ EntMap+16 0075 LengthEntRec equ EntEndMap 0076 LengthEntry equ LengthEntRec-EntUser 0077 ; #include utilio.inc,OutVars 0078 ;============================================================== 0079 ; constant strings... 0080 MsgNoRoom db 'Too many entries, storage exhausted.$' 0081 MsgNoOutref db 'An output file must be named.$' 0082 ; #include utilio.inc,FileMessages 0083 ;=============================================================== 0084 ; Definitions of record formats, and format maps. This is 0085 ; pretty lengthy -- but it contains a lot of the program logic. 0086 ; 0087 FormatChar equ 80h ; write data as Ascii 0088 FormatConst equ 40h ; write format byte as Ascii 0089 FormatBit7 equ 20h ; write data bit 7 as 0 or 1 0090 FormatDec8 equ 10h ; write data byte as decimal 0091 FormatDec16 equ 08h ; write data word as decimal 0092 FormatCRLF equ 04h ; write CR, LF 0093 ; macro used to put delimiters between record items in maps 0094 COMMA MACRO 0095 IF BASIC 0096 DB ',',FORMATCONST 0097 ELSE 0098 DB ' ',FORMATCONST 0099 ENDIF 0100 ENDM 0101 QUOTE MACRO 0102 IF BASIC 0103 DB '"',FORMATCONST 0104 ENDIF 0105 ENDM 0106 ; 0107 ; This is the format map for the Info record. 0108 ; 0109 InfoMap: 0110 QUOTE 0111 db InfoFname-InfoRec+0,FormatChar 0112 db InfoFname-InfoRec+1,FormatChar 0113 db InfoFname-InfoRec+2,FormatChar 0114 db InfoFname-InfoRec+3,FormatChar 0115 db InfoFname-InfoRec+4,FormatChar 0116 db InfoFname-InfoRec+5,FormatChar 0117 db InfoFname-InfoRec+6,FormatChar 0118 db InfoFname-InfoRec+7,FormatChar 0119 QUOTE 0120 COMMA 0121 QUOTE 0122 db InfoFtype-InfoRec+0,FormatChar 0123 db InfoFtype-InfoRec+1,FormatChar 0124 db InfoFtype-InfoRec+2,FormatChar 0125 QUOTE 0126 COMMA 0127 db Info255-InfoRec,FormatDec8 0128 COMMA 0129 db InfoRpT-InfoRec,FormatDec16 0130 COMMA 0131 db InfoABsize-InfoRec,FormatDec16 0132 COMMA 0133 db InfoDSM-InfoRec,FormatDec16 0134 COMMA 0135 db InfoAlloc-InfoRec,FormatDec16 0136 COMMA 0137 db InfoOFF-InfoRec,FormatDec16 0138 COMMA 0139 db InfoDRM-InfoRec,FormatDec16 0140 COMMA 0141 db InfoRcount-InfoRec,FormatDec16 0142 db 0,FormatCRLF 0143 db 255 ; end of map 0144 ; 0145 ; this is the format map for the first part of an EntRec 0146 ; 0147 EntFmap1: 0148 QUOTE 0149 db EntFname+0,FormatChar 0150 db EntFname+1,FormatChar 0151 db EntFname+2,FormatChar 0152 db EntFname+3,FormatChar 0153 db EntFname+4,FormatChar 0154 db EntFname+5,FormatChar 0155 db EntFname+6,FormatChar 0156 db EntFname+7,FormatChar 0157 QUOTE 0158 IF BASIC 0159 db ',',FormatConst 0160 ENDIF 0161 QUOTE 0162 db EntFtype+0,FormatChar 0163 db EntFtype+1,FormatChar 0164 db EntFtype+2,FormatChar 0165 QUOTE 0166 COMMA 0167 db EntUser,FormatDec8 0168 COMMA 0169 db EntExtent,FormatDec8 0170 COMMA 0171 db EntS1,FormatDec8 0172 COMMA 0173 db EntS2,FormatDec8 0174 COMMA 0175 db EntRc,FormatDec8 0176 COMMA 0177 db EntFtype+0,FormatBit7 0178 COMMA 0179 db EntFtype+1,FormatBit7 0180 COMMA 0181 db EntFtype+2,FormatBit7 0182 COMMA 0183 db EntFname+0,FormatBit7 0184 COMMA 0185 db EntFname+1,FormatBit7 0186 COMMA 0187 db EntFname+2,FormatBit7 0188 COMMA 0189 db EntFname+3,FormatBit7 0190 COMMA 0191 db EntFname+4,FormatBit7 0192 COMMA 0193 db EntFname+5,FormatBit7 0194 COMMA 0195 db EntFname+6,FormatBit7 0196 COMMA 0197 db EntFname+7,FormatBit7 0198 db 255 ; end of first part of map 0199 ; 0200 ; the map for a 16-slot data map 0201 ; 0202 EntFmap16: 0203 COMMA 0204 db EntMap+00,FormatDec8 0205 COMMA 0206 db EntMap+01,FormatDec8 0207 COMMA 0208 db EntMap+02,FormatDec8 0209 COMMA 0210 db EntMap+03,FormatDec8 0211 COMMA 0212 db EntMap+04,FormatDec8 0213 COMMA 0214 db EntMap+05,FormatDec8 0215 COMMA 0216 db EntMap+06,FormatDec8 0217 COMMA 0218 db EntMap+07,FormatDec8 0219 COMMA 0220 db EntMap+08,FormatDec8 0221 COMMA 0222 db EntMap+09,FormatDec8 0223 COMMA 0224 db EntMap+10,FormatDec8 0225 COMMA 0226 db EntMap+11,FormatDec8 0227 COMMA 0228 db EntMap+12,FormatDec8 0229 COMMA 0230 db EntMap+13,FormatDec8 0231 COMMA 0232 db EntMap+14,FormatDec8 0233 COMMA 0234 db EntMap+15,FormatDec8 0235 db 0,FormatCRLF,255 ; end of record 0236 ; 0237 ; the map for an 8-slot, 16-bit, data map 0238 ; 0239 EntFmap8: 0240 COMMA 0241 db EntMap+0,FormatDec16 0242 COMMA 0243 db EntMap+2,FormatDec16 0244 COMMA 0245 db EntMap+4,FormatDec16 0246 COMMA 0247 db EntMap+6,FormatDec16 0248 COMMA 0249 db EntMap+8,FormatDec16 0250 COMMA 0251 db EntMap+10,FormatDec16 0252 COMMA 0253 db EntMap+12,FormatDec16 0254 COMMA 0255 db EntMap+14,FormatDec16 0256 db 0,FormatCRLF,255 ; end of map and record 0257 ;============================================================== 0258 ; The main program...at last. 0259 ; 0260 Main: 0261 shld StoreLimit ; save top-of-storage 0262 lxi h,FreeStart 0263 shld NextFree ; set up for allocation 0264 lxi h,0 0265 shld EntRecCount ; clear count of entries found 0266 ; 0267 call SetUpFCB ; save outputref, move dirref 0268 call NoteOption ; note option /x 0269 call DefaultRef ; fill in *.* if no fileref 0270 call SetDrivecode ; set default drive and FCB 0271 call GetInfo ; set MapSize, InfoRec 0272 ; 0273 ; first loop -- read, sort, and store the entries 0274 ; 0275 call FirstSearch 0276 Main2: ; while (P<>nil) 0277 mov a,h 0278 ora l 0279 JRZ Main2a 0280 call StowEntry ; record the entry in sequence 0281 call NextSearch ; get the next one 0282 JMPR Main2 ; end while. 0283 Main2a: 0284 ; 0285 ; Initialize the output mechanism. SetUpOutput expects the 0286 ; output fileref in the second-operand location. We saved it 0287 ; in the OutFCB, now we have to put it back. It expects an 0288 ; FCB to take missing parts of the fileref from -- we give it 0289 ; the fileref itself, nullifying that action. Missing parts 0290 ; of the output ref will stay missing. 0291 ; 0292 lxi h,OutFCB 0293 lxi d,CpmFCB2 0294 lxi b,16 0295 call MoveHtoD ; outputref back in CpmFCB 0296 lxi b,CpmFCB2 ; ineffective default parts 0297 lhld NextFree ; start of output buffer 0298 xchg ; ..in DE 0299 lhld StoreLimit ; end of output buffer in HL 0300 call SetUpOutput 0301 call WriteInfo ; write the info record 0302 ; 0303 ; second loop -- read EntRecs in order, format output lines 0304 ; 0305 call FirstEntry 0306 Main3: 0307 mov a,h ; while P<>nil 0308 ora l 0309 JRZ Main4 0310 call WriteFile ; write this record, 0311 call NextEntry ; find the next EntRec 0312 JMPR Main3 ; end while. 0313 ; 0314 Main4: 0315 call FinishOutput 0316 ret 0317 ;--------------------------------------------------------------- 0318 ; SetUpFCB : Make sure there is an outputref, and move it to 0319 ; the OutFCB. If it lacks a drivecode, give it the present 0320 ; default drive. Then move the dirref down in CpmFcb. 0321 ; preserves -- all 0322 ;--------------------------------------------------------------- 0323 SetUpFCB: 0324 push psw 0325 push b 0326 push d 0327 push h 0328 ; 0329 lxi h,CpmFcb+1 0330 call Delimiter 0331 JRNZ SetUpFCB2 0332 ABORT MsgNoOutRef 0333 SetUpFCB2: 0334 dcx h 0335 lxi d,OutFcb 0336 lxi b,16 ; copy outputref to OutFcb, and 0337 call MoveHtoD ; ..increment HL to CpmFcb2 0338 lda OutFcb 0339 ora a ; make sure OutFCB names a 0340 JRNZ SetUpFCB3 ; drive, because dirref may 0341 SERVICE BdosDrive 0342 inr a ; name a different one. 0343 sta OutFCB 0344 ; 0345 SetUpFCB3: 0346 lxi d,CpmFcb ; HL->CpmFcb2, remember? 0347 call MoveHtoD ; copy dirref to front of FCB 0348 ; 0349 pop h 0350 pop d 0351 pop b 0352 pop psw 0353 ret 0354 ;--------------------------------------------------------------- 0355 ; GetInfo : collect information from the Disk Parameter Block 0356 ; and the system's Allocation Vector, and stow it in InfoRec. 0357 ; preserves -- all 0358 ;--------------------------------------------------------------- 0359 GetInfo: 0360 push psw 0361 push b 0362 push d 0363 push h 0364 ; 0365 SERVICE BdosGetDPB 0366 ; 0367 ; SPT (128-byte RECORDS, dammit, per track) in the 1st 2 bytes 0368 ; 0369 mov e,m 0370 inx h 0371 mov d,m 0372 xchg 0373 shld InfoRpT 0374 xchg 0375 ; 0376 ; size of an allocation block -- 128 shifted left DPB.BSH times 0377 ; 0378 inx h 0379 mov b,m ; B := DPB.BSH 0380 xchg ; (save DPB pointer) 0381 lxi h,128 0382 GetInfo1: 0383 dad h ; shift 128 left 0384 DJNZ GetInfo1 ; ..BSH times 0385 shld InfoABsize 0386 xchg ; (recover DPB pointer) 0387 ; 0388 ; number of allocation blocks on the entire drive: DSM+1 0389 ; 0390 inx h ; HL->BLM 0391 inx h ; HL->EXM 0392 inx h ; HL->DSM 0393 mov e,m 0394 inx h 0395 mov d,m ; DE = DPB.DSM 0396 inx d ; = DPB.DSM+1 0397 xchg 0398 shld InfoDSM 0399 xchg 0400 ; 0401 ; incidentally, set MapSize now we have DSM. 0402 ; 0403 dcx d 0404 mov a,d 0405 ora a 0406 mvi a,16 0407 JRZ GetInfo3 0408 mvi a,8 0409 GetInfo3: 0410 sta MapSize 0411 ; 0412 ; number of entry slots in the directory: DRM+1 0413 ; 0414 inx h 0415 mov e,m 0416 inx h 0417 mov d,m 0418 inx d 0419 xchg 0420 shld InfoDRM 0421 xchg 0422 ; 0423 ; track offset -- tracks skipped between 0 and directory 0424 ; 0425 inx h ; HL->AL0 0426 inx h ; HL->AL1 0427 inx h ; HL->CKS 0428 inx h 0429 inx h ; HL->OFF 0430 mov e,m 0431 inx h 0432 mov d,m 0433 xchg 0434 shld InfoOFF 0435 ; 0436 ; find the allocation vector -- a bit map of DSM+1 bits, where 0437 ; 1 means that block is in use, 0 means it's free. 0438 ; 0439 SERVICE BdosGetAlloc 0440 ; 0441 ; ..and count the one-bits in it. There are (DSM/8)+1 bytes. 0442 ; Usually, the majority will be 00h, and the code reflects this. 0443 ; Register use is: 0444 ; HL->allocation vector byte 0445 ; DE = count of bytes to inspect 0446 ; BC = count of 1-bits found so far 0447 ; 0448 xchg 0449 lhld InfoDSM 0450 xchg ; DE = DSM 0451 call SRLDE ; = DSM/2 0452 call SRLDE ; = DSM/4 0453 call SRLDE ; = DSM/8 0454 inx d ; = DSM/8 + 1 0455 lxi b,0 0456 ; 0457 GetInfAV1: 0458 mov a,m ; get next byte to inspect 0459 GetInfAV2: 0460 ora a ; clear carry, test for 00h 0461 jz GetInfAV4 ; ..and stop when byte cleared 0462 GetInfAV3: 0463 ral ; get next 1-bit to carry, 0464 jnc GetInfAV3 ; (next bit was 0) 0465 inx b ; ..count it 0466 jmp GetInfAV2 ; ..and see if there are more 0467 GetInfAV4: 0468 inx h ; point to next byte 0469 dcx d ; ..count that one, 0470 mov a,d 0471 ora e ; ..and test for done 0472 jnz GetInfAV1 0473 ; 0474 mov h,b 0475 mov l,c 0476 shld InfoAlloc ; whew. 0477 ; 0478 pop h 0479 pop d 0480 pop b 0481 pop psw 0482 ret 0483 ;--------------------------------------------------------------- 0484 ; WriteInfo : write the info record at the head of the file. 0485 ; This is done by calling Format with a data map and the Info 0486 ; data block. 0487 ; preserves -- all 0488 ;--------------------------------------------------------------- 0489 WriteInfo: 0490 push d 0491 push h 0492 ; 0493 lxi d,InfoRec ; point DE to the data source, 0494 lxi h,InfoMap ; ..and HL to its format map. 0495 call Format ; isn't that easy? 0496 ; 0497 pop h 0498 pop d 0499 ret 0500 ;--------------------------------------------------------------- 0501 ; WriteFile(P) : write a record describing HL->EntRec. This is 0502 ; done by calling Format with various data maps. 0503 ; preserves -- all 0504 ;--------------------------------------------------------------- 0505 WriteFile: 0506 push psw 0507 push d 0508 push h 0509 ; 0510 xchg ; DE->EntRec 0511 lxi h,EntFmap1 ; HL->map for start of record 0512 call Format 0513 ; 0514 lxi h,EntFmap16 ; assume 16, 8-bit entries 0515 lda MapSize 0516 cpi 16 0517 JRZ WriteFile2 ; (yep) 0518 lxi h,EntFmap8 ; (nope, 8, 16-bit entries) 0519 WriteFile2: 0520 call Format ; and that, friends, is that. 0521 pop h 0522 pop d 0523 pop psw 0524 ret 0525 ;--------------------------------------------------------------- 0526 ; Format(data,fmap) : format DE->data structure according to 0527 ; HL->format map, and write the result to the output file. 0528 ; Each entry of the format map contains 2 bytes. The first 0529 ; contains an offset from the address in DE (or, sometimes, a 0530 ; constant byte). The second has one bit giving the format. 0531 ; preserves -- all 0532 ;--------------------------------------------------------------- 0533 Format: 0534 push psw 0535 push b 0536 push h 0537 ; 0538 FormatLoop: 0539 mov a,m ; offset or constant... 0540 inr a ; ..which, if FFh, means 0541 jz FormatDone ; ..end of map. 0542 dcr a 0543 ; 0544 mov c,a ; save offset/constant 0545 inx h 0546 mov a,m ; pick up format byte 0547 inx h ; ..and set up for next. 0548 ; 0549 Format1: 0550 rlc ; FormatChar to carry 0551 JRNC Format2 0552 call FormatLoad ; load the data byte 0553 jmp FormatAscii ; ..and type it. 0554 ; 0555 Format2: 0556 rlc ; FormatConst to carry 0557 JRNC Format3 0558 mov a,c ; recover constant data 0559 FormatAscii: 0560 ani AsciiDEL ; set off Bit 7 0561 call PutChar ; ..write a byte 0562 jmp FormatLoop 0563 ; 0564 Format3: 0565 rlc ; FormatBit7 to carry 0566 JRNC Format4 0567 call FormatLoad ; load data byte, 0568 ral 0569 ral ; attribute bit to A bit 0 0570 ani 01h ; ..isolated 0571 jmp Format8bit ; ..treat as decimal 0572 ; 0573 Format4: 0574 rlc ; FormatDec8 to carry 0575 JRNC Format5 0576 call FormatLoad ; load data byte, 0577 Format8bit: 0578 call PutZZ9 ; ..write as integer in 0..255 0579 jmp FormatLoop 0580 ; 0581 Format5: 0582 rlc ; FormatDec16 to carry 0583 JRNC Format6 0584 push h 0585 call FormatLoad 0586 mov l,a ; least-significant byte 0587 inx b 0588 ldax b 0589 mov h,a ; ..most-sig. one 0590 call PutSint ; write as signed integer 0591 pop h 0592 jmp FormatLoop 0593 ; 0594 Format6: 0595 rlc ; FormatCRLF to carry 0596 JRNC Format7 ; (???) 0597 call PutCRLF 0598 Format7: 0599 Format8: 0600 jmp FormatLoop 0601 ; 0602 FormatDone: 0603 pop h 0604 pop b 0605 pop psw 0606 ret 0607 ; 0608 ; inner subroutine for BC:=BC+DE, and load A from there. 0609 ; 0610 FormatLoad: 0611 mov a,c 0612 add e 0613 mov c,a 0614 mov a,d 0615 aci 0 0616 mov b,a 0617 ldax b 0618 ret 0619 ;--------------------------------------------------------------- 0620 ; FirstSearch(var P): Perform the BDOS Search-first operation. 0621 ; preserves - AF, BC, DE 0622 ; returns - HL->dir. entry, or HL=0000 0623 ; note -- exits via MakeAddr, common code with NextSearch 0624 ;--------------------------------------------------------------- 0625 FirstSearch: 0626 push psw 0627 ; 0628 SERVICE BdosSrch1,CpmFcb 0629 JMPR MakeAddr 0630 ;--------------------------------------------------------------- 0631 ; NextSearch(var P): Perform the BDOS Search-next operation 0632 ; preserves - AF, BC, DE 0633 ; returns - HL->dir. entry, or HL=0000 0634 ;--------------------------------------------------------------- 0635 NextSearch: 0636 push psw 0637 ; 0638 SERVICE BdosSrchn,CpmFcb 0639 ; 0640 MakeAddr: 0641 lxi h,0 0642 ora a ; A=FFh? 0643 jm MakeAdout 0644 add a ; offset * 2 0645 add a ; * 4 0646 add a ; * 8 0647 add a ; * 16 0648 add a ; * 32 0649 ori CpmBuffer ; address in base page 0650 mvi h,CpmBasePage 0651 mov l,a 0652 MakeAdOut: 0653 pop psw 0654 ret 0655 ;--------------------------------------------------------------- 0656 ; StowEntry(X) : HL points to a directory entry in low storage. 0657 ; Put it away in high storage embedded in an EntRec. Insert the 0658 ; EntRec in high-to-low sequence into the chain based on Anchor. 0659 ; preserves - AF, BC, DE 0660 ; returns - HL->EntRec 0661 ; The pseudo-code variables are: P=BC, Q=DE, N=HL 0662 ;--------------------------------------------------------------- 0663 StowEntry: 0664 push psw 0665 push b 0666 push d 0667 ; 0668 call CopyEntry ; N := CopyEntry(X) 0669 ; call PrepEntRec -- not needed in this application 0670 ; 0671 xra a 0672 mov m,a 0673 inx h 0674 mov m,a 0675 dcx h ; N->word := nil 0676 lxi b,Anchor ; P := address of Anchor 0677 StowRepeat: ; repeat 0678 ldax b 0679 mov e,a 0680 inx b 0681 ldax b 0682 mov d,a 0683 dcx b ; Q := P->word 0684 ora e ; if ( Q <> nil ) then 0685 JRZ StowUntil 0686 ; 0687 call StowComp ; if (N->EntRec < Q->EntRec) then 0688 JRNC StowGT 0689 mov b,d 0690 mov c,e ; P := Q 0691 JMPR StowRepeat ; (optimize--this is the only 0692 ; branch that loops) 0693 StowGT: ; else { new>old, put here } 0694 mov m,e 0695 inx h 0696 mov m,d 0697 dcx h ; N->word := Q 0698 ; no need for "Q:=nil" 0699 StowUntil: ; end of loop, P->predecessor of N->EntRec 0700 mov a,l 0701 stax b 0702 inx b 0703 mov a,h 0704 stax b ; P->word := N 0705 ; 0706 pop d 0707 pop b 0708 pop psw 0709 ret 0710 ; 0711 ; Inner subroutine to compare the "u:filename.typ.ex" of 0712 ; two EntRecs. HL->the new one, DE->the old one. 0713 ; 0714 StowComp: 0715 push b 0716 push d 0717 push h 0718 lxi b,EntEntry ; offset to compare data 0719 dad b 0720 xchg ; DE->new compare data 0721 dad b ; HL->old compare data 0722 mvi b,13 ; amount to compare 0723 StowComp1: 0724 mov a,m ; get 'old' data byte, 0725 ani AsciiDEL ; ..set off attribute bit, 0726 mov c,a ; ..and save it. 0727 ldax d ; get 'new' byte, 0728 ani AsciiDEL ; ..set off attribute bit, 0729 cmp c ; new vs. old 0730 jnz StowComp2 ; ..and quit on first inequality 0731 inx d ; still equal, step pointers 0732 inx h 0733 DJNZ StowComp1 0734 StowComp2: ; flags set for new :: old 0735 pop h 0736 pop d 0737 pop b 0738 ret 0739 ;--------------------------------------------------------------- 0740 ; CopyEntry(X) : HL->a directory entry in low storage. Allocate 0741 ; the next EntRec in high storage (abort if out of room), and 0742 ; copy the directory entry into it. Step the count of entries. 0743 ; preserves - AF, BC, DE 0744 ; returns - HL->EntRec 0745 ;--------------------------------------------------------------- 0746 CopyEntry: 0747 push psw 0748 push b 0749 push d 0750 ; 0751 push h ; save ->dir. entry 0752 lhld NextFree 0753 push h ; save will-be address of EntRec 0754 lxi b,LengthEntRec 0755 dad b 0756 xchg ; DE = NextFree+Length 0757 lhld StoreLimit 0758 call CmpDH ; compare to end of free store 0759 JRC CopyEnt2 ; (ok, DE<HL) 0760 ABORT MsgNoRoom 0761 ; 0762 CopyEnt2: 0763 xchg 0764 shld NextFree ; NextFree := NextFree+Length 0765 pop h ; recover new address.. 0766 push h ; ..and save another copy 0767 lxi d,EntEntry ; offset to start of entry 0768 dad d 0769 xchg ; DE->target address 0770 pop h 0771 xthl ; HL->dir. entry, ->EntRec stacked 0772 lxi b,LengthEntry ; BC = length to move 0773 call MoveHtoD 0774 ; 0775 lhld EntRecCount 0776 inx h 0777 shld EntRecCount 0778 ; 0779 pop h ; HL->new EntRec 0780 pop d 0781 pop b 0782 pop psw 0783 ret 0784 ;--------------------------------------------------------------- 0785 ; FirstEntry : Return the first stored EntRec. But first... 0786 ; The chain of EntRecs was created in reverse order -- high to 0787 ; low -- because that may save a few comparisons. Now we want 0788 ; to read it out from low to high. In order to do so, we have 0789 ; to reverse the direction of all the chain pointers. 0790 ; preserves - AF, BC, DE 0791 ; returns - HL->first (lowest in sequence) EntRec 0792 ; or HL=0000 if the chain is empty 0793 ; Note -- the pseudo-code variables are P=DE, Q=HL, R=BC 0794 ;--------------------------------------------------------------- 0795 FirstEntry: 0796 push psw 0797 push b 0798 push d 0799 ; 0800 lxi d,0 ; P := nil 0801 lhld Anchor ; Q := Anchor 0802 ; 0803 mov a,h 0804 ora l ; if ( Q <> nil ) then 0805 JRZ FirstDone 0806 ; 0807 FirstLoop: ; loop: 0808 ; 0809 mov c,m 0810 inx h 0811 mov b,m ; R := Q->word 0812 mov m,d 0813 dcx h 0814 mov m,e ; Q->word := P 0815 ; 0816 mov a,c 0817 ora b ; while ( R <> nil ) 0818 jz FirstDone 0819 ; 0820 mov d,h 0821 mov e,l ; P := Q 0822 mov h,b 0823 mov l,c ; Q := R 0824 ; 0825 jmp FirstLoop ; end loop. 0826 ; endif. 0827 FirstDone: 0828 shld Anchor ; Anchor := Q 0829 pop d 0830 pop b 0831 pop psw 0832 ret ; return Q (= HL) 0833 ;--------------------------------------------------------------- 0834 ; NextEntry(P) : return the address of the EntRec after the one 0835 ; that HL addresses. This function exists in order to hide the 0836 ; chaining mechanism from the main routine. 0837 ; preserves - AF, BC, DE 0838 ; returns - HL->EntRec, or 0839 ; HL=0000 if there are no more 0840 ;--------------------------------------------------------------- 0841 NextEntry: 0842 push psw 0843 mov a,m 0844 inx h 0845 mov h,m 0846 mov l,a 0847 pop psw 0848 ret 0849 ;--------------------------------------------------------------- 0850 ; NoteOptions : search the command tail for a "/" and assume 0851 ; that it means "/x" -- we have only one option, why be picky? 0852 ; Set OptionX to the appropriate drivecode flag for searches. 0853 ; preserves - all 0854 ;--------------------------------------------------------------- 0855 NoteOption: 0856 push psw 0857 push h 0858 ; 0859 lxi h,CpmTail 0860 call CmdSlash 0861 mvi a,0 ; assume none 0862 JRNZ NoteOpt2 0863 mvi a,'?' ; / seen -- get all types of entries 0864 NoteOpt2: 0865 sta OptionX 0866 ; 0867 pop h 0868 pop psw 0869 ret 0870 ;--------------------------------------------------------------- 0871 ; DefaultRef: if no fileref was given, fill the FCB name and typ 0872 ; fields with ??????????? -- which is what "*.*" means. Put a 0873 ; "?" in the extent field so that all extents will be seen. 0874 ; preserves -- all 0875 ; Note -- by this time, SetUpFCB has moved the search-ref down 0876 ; to the first fileref position in the FCB. 0877 ;--------------------------------------------------------------- 0878 DefaultRef: 0879 push psw 0880 push b 0881 push d 0882 push h 0883 ; 0884 lxi h,CpmFcb+1+8 ; first byte of filetype... 0885 call Delimiter ; ..is blank, /, comma? 0886 JRNZ DefRef2 ; (no, fileref given) 0887 lxi h,CpmFcb+1 ; blank filetype... 0888 call Delimiter ; ..filetype too? 0889 JRNZ DefRef2 ; (no, " .xxx") 0890 ; 0891 xchg ; DE->CpmFcb+1, or fileref. 0892 lxi b,8+3 ; size to fill 0893 mvi a,'?' ; ..with "????????.???" 0894 call FillA 0895 DefRef2: 0896 mvi a,'?' 0897 sta CpmFcb+1+8+3 ; set extent number to ? 0898 ; 0899 pop h 0900 pop d 0901 pop b 0902 pop psw 0903 ret 0904 ;--------------------------------------------------------------- 0905 ; SetDriveCode: if a drivecode was given, make that the default 0906 ; drive -- the search requests work only on the default drive. 0907 ; Then set the FCB drivecode as per OptionX. 0908 ; preserves -- all 0909 ;--------------------------------------------------------------- 0910 SetDriveCode: 0911 push psw 0912 push h 0913 ; 0914 lda CpmFcb 0915 ora a ; drivecode given? 0916 JRZ SetDrive2 ; (no -- present drive is OK) 0917 dcr a ; yes, adjust for service 0918 mov e,a 0919 SERVICE BdosSetDrive 0920 SetDrive2: 0921 lda OptionX 0922 sta CpmFcb 0923 ; 0924 pop h 0925 pop psw 0926 ret 0927 ;=============================================================== 0928 ; included subroutines... 0929 ; #include TypeSubs.Inc,TypeCommon 0930 ; #include arithlib.inc,CmpDH 0931 ; #include arithlib.inc,SRLDE 0932 ; #include Textlib.inc,FillA (and MoveHtoD) 0933 ; #include textlib.inc,Delimiter 0934 ; #include cmdparse.inc,CmdSlash 0935 ; #include utilio.inc,PutChar (and DumpOut) 0936 ; #include utilio.inc,SetUpOutput 0937 ; #include PutSubs.inc,PutDecimal (PutZZ9, PutSint) 0938 ; #include PutSubs.inc,PutCommon (for PutCRLF) 0939 ;=============================================================== 0940 ; Buffer space at the end of the program. As usual, this isn't 0941 ; a good idea for MP/M. 0942 FreeStart equ $ 0943 end * CROSS-REFERENCE * def. val. symbol and uses * 0052 0170 ANCHOR LXI-676 LHLD-801 SHLD-828 * ---- 007F ASCIIDEL ANI-560 -725 -728 * 0058 FFFF BASIC IF-95 -102 -158 * ---- 0019 BDOSDRIVE SERVICE-341 * ---- 001B BDOSGETALLOC SERVICE-439 * ---- 001F BDOSGETDPB SERVICE-365 * ---- 000E BDOSSETDRIVE SERVICE-919 * ---- 0011 BDOSSRCH1 SERVICE-628 * ---- 0012 BDOSSRCHN SERVICE-638 * ---- 0786 CMDSLASH CALL-860 * ---- 0730 CMPDH CALL-758 * 0762 0658 COPYENT2 JRC-759 * 0746 063A COPYENTRY CALL-668 * ---- 0000 CPMBASEPAGE MVI-650 * ---- 0080 CPMBUFFER ORI-649 * ---- 005C CPMFCB LXI-329 -346 SERVICE-628 -638 LXI-884 -887 STA-897 * LDA-914 STA-922 * ---- 006C CPMFCB2 LXI-293 -296 * ---- 0080 CPMTAIL LXI-859 * 0878 06BA DEFAULTREF CALL-269 * 0895 06D9 DEFREF2 JRNZ-886 -889 * ---- 076B DELIMITER CALL-330 -885 -888 * 0063 0003 ENTAS * 0074 0025 ENTENDMAP EQU-75 * 0065 0005 ENTENTRY EQU-66 LXI-718 -767 * 0069 0011 ENTEXTENT EQU-70 DB-169 * 0147 032D ENTFMAP1 LXI-511 * 0202 038E ENTFMAP16 LXI-514 * 0239 03D1 ENTFMAP8 LXI-518 * 0067 0006 ENTFNAME EQU-68 DB-149 -150 -151 -152 -153 -154 -155 -156 * -183 -185 -187 -189 -191 -193 -195 -197 * 0068 000E ENTFTYPE EQU-69 DB-162 -163 -164 -177 -179 -181 * 0064 0004 ENTHC * 0073 0015 ENTMAP EQU-74 DB-204 -206 -208 -210 -212 -214 -216 -218 * -220 -222 -224 -226 -228 -230 -232 -234 -241 -243 * -245 -247 -249 -251 -253 -255 * 0062 0002 ENTMS * 0061 0000 ENTNEXT * 0072 0014 ENTRC EQU-73 DB-175 * 0057 016E ENTRECCOUNT SHLD-265 LHLD-775 SHLD-777 * 0070 0012 ENTS1 EQU-71 DB-171 * 0071 0013 ENTS2 EQU-72 DB-173 * 0066 0005 ENTUSER EQU-67 -76 DB-167 * ---- 0746 FILLA CALL-894 * ---- 08F8 FINISHOUTPUT CALL-315 * 0827 0697 FIRSTDONE JRZ-805 JZ-818 * 0795 0677 FIRSTENTRY CALL-305 * 0807 0685 FIRSTLOOP JMP-825 * 0625 05B6 FIRSTSEARCH CALL-275 * 0533 054D FORMAT CALL-495 -512 -520 * 0549 055A FORMAT1 * 0555 0564 FORMAT2 JRNC-551 * 0564 0571 FORMAT3 JRNC-557 * 0573 057F FORMAT4 JRNC-566 * 0581 058C FORMAT5 JRNC-575 * 0594 059F FORMAT6 JRNC-583 * 0598 05A6 FORMAT7 JRNC-596 * 0599 05A6 FORMAT8 * 0577 0586 FORMAT8BIT JMP-571 * 0559 0569 FORMATASCII JMP-553 * 0089 0020 FORMATBIT7 DB-177 -179 -181 -183 -185 -187 -189 -191 -193 * -195 -197 * 0087 0080 FORMATCHAR DB-111 -112 -113 -114 -115 -116 -117 -118 -122 * -123 -124 -149 -150 -151 -152 -153 -154 -155 -156 * -162 -163 -164 * 0088 0040 FORMATCONST DB-96 -98 -103 -159 * 0092 0004 FORMATCRLF DB-142 -235 -256 * 0091 0008 FORMATDEC16 DB-129 -131 -133 -135 -137 -139 -141 -241 * -243 -245 -247 -249 -251 -253 -255 * 0090 0010 FORMATDEC8 DB-127 -167 -169 -171 -173 -175 -204 -206 -208 * -210 -212 -214 -216 -218 -220 -222 -224 -226 -228 * -230 -232 -234 * 0602 05A9 FORMATDONE JZ-541 * 0610 05AD FORMATLOAD CALL-552 -567 -576 -585 * 0538 0550 FORMATLOOP JMP-562 -579 -592 -600 * 0942 0A18 FREESTART LXI-262 * 0457 0502 GETINFAV1 JNZ-472 * 0459 0503 GETINFAV2 JMP-466 * 0462 0507 GETINFAV3 JNC-464 * 0467 050F GETINFAV4 JZ-461 * 0359 0494 GETINFO CALL-271 * 0382 04AF GETINFO1 DJNZ-384 * 0409 04CE GETINFO3 JRZ-407 * 0042 0161 INFO255 DB-127 * 0044 0164 INFOABSIZE DB-131 SHLD-385 * 0046 0168 INFOALLOC DB-135 SHLD-476 * 0048 016C INFODRM DB-139 SHLD-420 * 0045 0166 INFODSM DB-133 SHLD-398 LHLD-449 * 0040 0156 INFOFNAME DB-111 -112 -113 -114 -115 -116 -117 -118 * 0041 015E INFOFTYPE DB-122 -123 -124 * 0109 02EA INFOMAP LXI-494 * 0047 016A INFOOFF DB-137 SHLD-434 * 0049 016E INFORCOUNT EQU-57 DB-141 * 0039 0156 INFOREC DB-111 -112 -113 -114 -115 -116 -117 -118 -122 * -123 -124 -127 -129 -131 -133 -135 -137 -139 -141 * LXI-493 * 0043 0162 INFORPT DB-129 SHLD-373 * 0075 0025 LENGTHENTREC EQU-76 LXI-754 * 0076 0020 LENGTHENTRY LXI-772 * 0260 03F4 MAIN * 0276 0415 MAIN2 JMPR-282 * 0283 0423 MAIN2A JRZ-279 * 0306 0442 MAIN3 JMPR-312 * 0314 0450 MAIN4 JRZ-309 * 0640 05D7 MAKEADDR JMPR-629 * 0652 05E8 MAKEADOUT JM-643 * 0055 0176 MAPSIZE STA-410 LDA-515 * ---- 075C MOVEHTOD CALL-295 -337 -347 -773 * 0081 01CC MSGNOOUTREF ABORT-332 * 0080 01A7 MSGNOROOM ABORT-760 * 0841 069E NEXTENTRY CALL-311 * 0053 0172 NEXTFREE SHLD-263 LHLD-297 -752 SHLD-764 * 0635 05C8 NEXTSEARCH CALL-281 * 0864 06B4 NOTEOPT2 JRNZ-862 * 0855 06A5 NOTEOPTION CALL-268 * 0056 0177 OPTIONX STA-865 LDA-921 * ---- 0178 OUTFCB LXI-292 -335 LDA-338 STA-343 * ---- 079A PUTCHAR CALL-561 * ---- 09FA PUTCRLF CALL-597 * ---- 097C PUTSINT CALL-590 * ---- 096B PUTZZ9 CALL-578 * 0920 06F9 SETDRIVE2 JRZ-916 * 0910 06E3 SETDRIVECODE CALL-270 * 0323 0454 SETUPFCB CALL-267 * 0333 0469 SETUPFCB2 JRNZ-331 * 0345 0489 SETUPFCB3 JRNZ-340 * ---- 0824 SETUPOUTPUT CALL-300 * ---- 073C SRLDE CALL-451 -452 -453 * 0054 0174 STORELIMIT SHLD-261 LHLD-299 -757 * 0714 061A STOWCOMP CALL-687 * 0723 0625 STOWCOMP1 DJNZ-733 * 0734 0636 STOWCOMP2 JNZ-730 * 0663 05EA STOWENTRY CALL-280 * 0693 060D STOWGT JRNC-688 * 0677 05F8 STOWREPEAT JMPR-691 * 0699 0611 STOWUNTIL JRZ-685 * ---- FFFF TRUE EQU-58 * 0505 052E WRITEFILE CALL-310 * 0519 0546 WRITEFILE2 JRZ-517 * 0489 0520 WRITEINFO CALL-301 * CENSUS OF OPCODE USAGE * * ABORT 2 ACI 1 ADD 6 * ANI 4 CALL 40 CMP 1 * COMMA 50 CPI 1 DAD 5 * DB 86 DCR 2 DCX 7 * DJNZ 2 DW 10 ELSE 1 * END 1 ENDIF 3 ENDM 2 * EQU 25 IF 3 INR 2 * INX 31 JM 1 JMP 8 * JMPR 4 JNC 1 JNZ 2 * JRC 1 JRNC 7 JRNZ 5 * JRZ 7 JZ 3 LDA 4 * LDAX 5 LHLD 7 LXI 28 * MACLIB 2 MOV 53 MVI 8 * ORA 11 ORI 1 POP 42 * PROLOG 1 PUSH 43 QUOTE 9 * RAL 3 RET 16 RLC 6 * SERVICE 6 SHLD 12 STA 5 * STAX 2 XCHG 18 XRA 1 * XTHL 1