home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol125 / sdir.mqc / SDIR.MAC
Encoding:
Text File  |  1985-02-10  |  31.8 KB  |  1,312 lines

  1. ;
  2. ; SYSLIB Module Name:  SDIR
  3. ; Author:  Richard Conn
  4. ; SYSLIB Version Number:  2.7
  5. ; Module Version Number:  1.2
  6. ; Module Entry Points:
  7. ;    DBUFFER        DFREE        DIRALPHA    DIRF
  8. ;    DIRFS        DIRLOAD        DIRNPACK    DIRPACK
  9. ;    DIRSEL        DIRSLOAD    DPARAMS        FSIZE
  10. ; Module External References:
  11. ;    PRINT
  12. ;
  13. ;*
  14. ;*  EXTERNALS
  15. ;*
  16.     EXT    PRINT    ; PRINT STRING PTED TO BY RETURN ADDRESS
  17.  
  18. ;*
  19. ;*  BASIC EQUATES
  20. ;*
  21. CPM    EQU    0    ; CP/M WARM BOOT
  22. BIOS    EQU    CPM+1    ; BIOS BASE ADDRESS
  23. BDOS    EQU    CPM+5    ; BDOS ENTRY POINT
  24. ESIZE    EQU    16    ; NUMBER OF BYTES/ENTRY IN MEMORY BUFFER
  25. BUFF    EQU    CPM+80H    ; DEFAULT DMA BUFFER
  26.  
  27. ;**************************************************************************
  28.  
  29. ;*
  30. ;*  GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITHOUT SIZING INFORMATION
  31. ;*    THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES
  32. ;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL.  ON EXIT, 
  33. ;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER.
  34. ;*    THE DIRECTORY BUFFER GENERATED BY DIRF CONTAINS ENTRIES WHICH MAY NOT
  35. ;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE.  THE
  36. ;* DIRFS ROUTINE IS DESIGNED FOR THIS PURPOSE.  THE BASIC TRADEOFF BETWEEN
  37. ;* THE TWO ROUTINES IS THE DIRF RUNS FASTER THAN DIRFS, AND THIS IS NOTICABLE
  38. ;* IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED.
  39. ;*
  40. ;*    INPUT PARAMETERS:
  41. ;*    HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG:
  42. ;*            Bit 7 - Select Non-Sys, Bit 6 - Select Sys
  43. ;*            Bit 5 - Select All Users, Bits 4-0 - User Number
  44. ;*    OUTPUT PARAMETERS:
  45. ;*    HL PTS TO FIRST FILE IN BUFFER
  46. ;*    BC = NUMBER OF FILES
  47. ;*    PSW, DE UNCHANGED
  48. ;*
  49. DIRF::
  50.     PUSH    PSW    ; SAVE PSW
  51.     PUSH    D    ; SAVE PTR TO FCB
  52.  
  53.     STA    SELFLG    ; SAVE SELECT FLAG FOR DIRSEL
  54.  
  55.     CALL    DBUFFER    ; GET PTRS
  56.  
  57.     CALL    DIRLOAD    ; LOAD DIRECTORY WITHOUT SIZING INFORMATION (FAST LOAD)
  58.  
  59.     POP    D    ; GET PTR TO FCB
  60.     LDA    SELFLG    ; GET SELECT FLAG
  61.     CALL    DIRSEL    ; SELECT FILES
  62.  
  63.     CALL    DIRPACK    ; PACK DIRECTORY
  64.  
  65.     MVI    A,0    ; SORT FLAG
  66.     CALL    DIRALPHA    ; ALPHABETIZE
  67.  
  68.     POP    PSW    ; GET PSW
  69.     RET
  70.  
  71. ;**************************************************************************
  72.  
  73. ;*
  74. ;*  BUFFERS
  75. ;*
  76. TFCB:
  77.     DB    0,'???????????',0,0,0,0    ; TEMPORARY FCB (FN,FT WILD)
  78.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  79.     DB    0,0,0
  80. BLKSHF:
  81.     DS    1    ; BLOCK SHIFT FACTOR
  82. BLKMSK:
  83.     DS    1    ; BLOCK MASK
  84. BLKMAX:
  85.     DS    2    ; MAX NUMBER OF BLOCKS
  86. DIRMAX:
  87.     DS    2    ; MAX NUMBER OF DIRECTORY ENTRIES
  88. SELFLG:
  89.     DS    1    ; FILE ATTRIBUTE FLAG
  90. DFLAG:            ; 0=SELECT FILES OF LARGER EX, ELSE OF SMALLER EX
  91. CMP$FLAG:        ; 0=SORT BY FILE NAME/TYPE, ELSE BY TYPE/NAME
  92.     DS    1
  93. ORDER:
  94.     DS    2    ; POINTER TO ORDER TABLE
  95. DIRBUF:
  96.     DS    2    ; POINTER TO DIRECTORY
  97. DSTART:
  98.     DS    2    ; POINTER TO FIRST DIRECTORY ENTRY
  99. EXTENT:
  100.     DB    0    ; NUMBER OF EXTENT "0" (INITIALIZED TO 0)
  101. FCOUNT:
  102.     DS    2    ; TOTAL NUMBER OF FILES/NUMBER OF SELECTED FILES
  103. HOLD:
  104.     DS    35    ; EXCHANGE HOLD BUFFER FOR FCB'S
  105. PTPTR:
  106.     DS    2    ; POINTER POINTER
  107. PTDIR:
  108.     DS    2    ; DIRECTORY POINTER
  109. I:
  110.     DS    2    ; INDEXES FOR SORT
  111. J:
  112.     DS    2
  113. JG:
  114.     DS    2
  115. N:
  116.     DS    2    ; NUMBER OF ELEMENTS TO SORT
  117. GAP:
  118.     DS    2    ; BINARY GAP SIZE
  119.  
  120. ;**************************************************************************
  121.  
  122. ;*
  123. ;*  GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITH SIZING INFORMATION
  124. ;*    THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES
  125. ;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL.  ON EXIT, 
  126. ;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER.
  127. ;*    THE DIRECTORY BUFFER GENERATED BY DIRFS CONTAINS ENTRIES WHICH MAY
  128. ;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE.  THE
  129. ;* DIRFS ROUTINE IS DESIGNED FOR THIS PURPOSE.  THE BASIC TRADEOFF BETWEEN
  130. ;* THE DIRF AND DIRFS ROUTINES IS THE DIRF RUNS FASTER THAN DIRFS, AND THIS
  131. ;* IS NOTICABLE IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED.
  132. ;*
  133. ;*    INPUT PARAMETERS:
  134. ;*    HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG:
  135. ;*            Bit 7 - Select Non-Sys, Bit 6 - Select Sys
  136. ;*            Bit 5 - Select All Users, Bits 4-0 - User Number
  137. ;*    OUTPUT PARAMETERS:
  138. ;*    HL PTS TO FIRST FILE IN BUFFER
  139. ;*    BC = NUMBER OF FILES
  140. ;*    PSW, DE UNCHANGED
  141. ;*
  142. DIRFS::
  143.     PUSH    PSW    ; SAVE PSW
  144.     PUSH    D    ; SAVE PTR TO FCB
  145.  
  146.     STA    SELFLG    ; SAVE SELECT FLAG FOR DIRSEL
  147.  
  148.     CALL    DBUFFER    ; GET PTRS
  149.  
  150.     CALL    DIRSLOAD    ; LOAD DIRECTORY WITH SIZING INFORMATION
  151.  
  152.     POP    D    ; GET PTR TO FCB
  153.     LDA    SELFLG    ; GET SELECT FLAG
  154.     CALL    DIRSEL    ; SELECT FILES
  155.  
  156.     CALL    DIRPACK    ; PACK DIRECTORY
  157.  
  158.     MVI    A,0    ; SORT FLAG
  159.     CALL    DIRALPHA    ; ALPHABETIZE
  160.  
  161.     POP    PSW    ; GET PSW
  162.     RET
  163.  
  164. ;**************************************************************************
  165.  
  166. ;*
  167. ;*  THIS ROUTINE ACCEPTS A BASE ADDRESS FOR THE DYNAMIC BUFFERS
  168. ;*    REQUIRED, DETERMINES HOW MUCH SPACE IS REQUIRED FOR THE BUFFERS,
  169. ;*    AND SETS THE ORDER PTR TO PT TO THE FIRST AND DIRBUF TO PT TO
  170. ;*    THE SECOND (ORDER SPACE = DIRMAX*2 AND DIRBUF = DIRMAX * ESIZE)
  171. ;*  ON INPUT, HL PTS TO AVAILABLE BASE
  172. ;*  ON OUTPUT, HL PTS TO DIRBUF
  173. ;*    A=0 AND ZERO FLAG SET IF BDOS OVERRUN
  174. ;*
  175. DBUFFER::
  176.     PUSH    D    ; SAVE DE
  177.     PUSH    B    ; SAVE BC
  178.     SHLD    ORDER    ; PT TO ORDER TABLE
  179.     CALL    DPARAMS    ; GET PARAMETERS
  180.     LHLD    DIRMAX    ; NUMBER OF ENTRIES IN DIR
  181.     XCHG        ; ... IN DE
  182.     LHLD    ORDER    ; ADD TO ORDER BASE
  183.     DAD    D    ; *1
  184.     CALL    MEMCHK    ; CHECK FOR WITHIN RANGE
  185.     DAD    D    ; HL PTS TO DIRBUF
  186.     CALL    MEMCHK    ; CHECK FOR WITHIN RANGE
  187.     SHLD    DIRBUF    ; SET PTR AND HL PTS TO DIRECTORY BUFFER
  188.     POP    B    ; RESTORE BC
  189.     POP    D    ; RESTORE DE
  190.     MVI    A,0FFH    ; OK
  191.     ORA    A    ; SET FLAGS
  192.     RET
  193.  
  194. MEMCHK:
  195.     PUSH    H    ; SAVE REGS
  196.     PUSH    D
  197.     XCHG        ; NEXT ADDRESS IN DE
  198.     LHLD    BDOS+1    ; GET ADDRESS OF BDOS
  199.     MOV    A,D    ; CHECK FOR PAGE OVERRUN
  200.     CMP    H
  201.     JNC    MEMORUN    ; OVERRUN IF D>=H
  202.     POP    D
  203.     POP    H
  204.     RET
  205. MEMORUN:
  206.     POP    D    ; RESTORE
  207.     POP    H
  208.     XRA    A    ; RETURN 0
  209.     POP    B    ; CLEAR STACK
  210.     POP    B    ; RESTORE BC
  211.     RET
  212.  
  213. ;**************************************************************************
  214.  
  215. ;*
  216. ;*  THIS ROUTINE EXTRACTS DISK PARAMETER INFORMATON FROM THE DPB AND
  217. ;*    STORES THIS INFORMATION IN:
  218. ;*    BLKSHF    <-- BLOCK SHIFT FACTOR (1 BYTE)
  219. ;*    BLKMSK    <-- BLOCK MASK (1 BYTE)
  220. ;*    EXTENT  <-- EXTENT MASK (1 BYTE)
  221. ;*    BLKMAX    <-- MAX NUMBER OF BLOCKS ON DISK (2 BYTES)
  222. ;*    DIRMAX    <-- MAX NUMBER OF DIRECTORY ENTRIES (2 BYTES)
  223. ;*
  224. DPARAMS::
  225.     PUSH    B    ; SAVE REGS
  226.     PUSH    D
  227.     PUSH    H
  228.     PUSH    PSW
  229.     MVI    C,12    ; GET VERSION NUMBER
  230.     CALL    BDOS
  231.     MOV    A,H    ; CHECK FOR 1.4
  232.     ORA    L
  233.     JZ    DPARM1    ; PRE-2.x...GET PARAMS THE 1.4 WAY
  234.  
  235. ;*
  236. ;*  VERSION 2.x OR MP/M
  237. ;*
  238.     MVI    C,31    ; 2.x OR MP/M...REQUEST DPB
  239.     CALL    BDOS
  240.     INX    H
  241.     INX    H
  242.     MOV    A,M    ; GET BLOCK SHIFT
  243.     STA    BLKSHF    ; BLOCK SHIFT FACTOR
  244.     INX    H    ; GET BLOCK MASK
  245.     MOV    A,M
  246.     STA    BLKMSK    ; BLOCK MASK
  247.     INX    H
  248.     MOV    A,M    ; GET MAX EXTENT NUMBER
  249.     STA    EXTENT    ; THIS IS CALLED THE EXTENT MASK
  250.     INX    H
  251.     MOV    E,M    ; GET MAX BLOCK NUMBER
  252.     INX    H
  253.     MOV    D,M
  254.     XCHG
  255.     INX    H    ; ADD 1 FOR MAX NUMBER OF BLOCKS
  256.     SHLD    BLKMAX    ; MAXIMUM NUMBER OF BLOCKS
  257.     XCHG
  258.     INX    H
  259.     MOV    E,M    ; GET DIRECTORY SIZE
  260.     INX    H
  261.     MOV    D,M
  262.     XCHG
  263.     INX    H    ; ADD 1 FOR NUMBER OF ENTRIES
  264.     SHLD    DIRMAX    ; MAXIMUM NUMBER OF DIRECTORY ENTRIES
  265.     JMP    DPARM2
  266.  
  267. ;*
  268. ;*  CP/M 1.4
  269. ;*
  270. DPARM1:
  271.     LHLD    BDOS+1    ; GET PARAMS 1.4 STYLE
  272.     MVI    L,3BH    ; POINT TO DIRECTORY SIZE ENTRY IN 1.4 BDOS
  273.     MOV    E,M    ; GET IT
  274.     MVI    D,0    ; FORCE HI ORDER BYTE TO 0
  275.     XCHG        ; SAVE SIZE OF DIRECTORY ENTRY
  276.     INX    H    ; ADD 1
  277.     SHLD    DIRMAX    ; MAXIMUM NUMBER OF ENTRIES
  278.     XCHG
  279.     INX    H    ; POINT TO BLOCK SHIFT
  280.     MOV    A,M
  281.     STA    BLKSHF    ; BLOCK SHIFT FACTOR
  282.     INX    H    ; POINT TO BLOCK MASK
  283.     MOV    A,M
  284.     STA    BLKMSK    ; BLOCK MASK
  285.     INX    H
  286.     MOV    E,M    ; GET MAXIMUM BLOCK NUMBER
  287.     MVI    D,0
  288.     XCHG
  289.     INX    H    ; ADD 1
  290.     SHLD    BLKMAX    ; MAXIMUM NUMBER OF BLOCKS
  291.     XRA    A    ; A=0
  292.     STA    EXTENT    ; SET EXTENT MASK TO 0 FOR CP/M 1.4 EXTENT SIZE
  293.  
  294. ;*
  295. ;*  ALL PARAMETERS EXTRACTED
  296. ;*
  297. DPARM2:
  298.     POP    PSW    ; RESTORE REGS
  299.     POP    H
  300.     POP    D
  301.     POP    B
  302.     RET
  303.  
  304. ;**************************************************************************
  305.  
  306. ;*
  307. ;*  COMPUTE AMOUNT OF FREE SPACE LEFT ON DISK
  308. ;*    ON EXIT, DE=AMOUNT OF FREE SPACE ON DISK IN K
  309. ;*    THE DPARAMS ROUTINE MUST BE CALLED BEFORE THIS ROUTINE IS USED
  310. ;*
  311. DFREE::
  312.     PUSH    B    ; SAVE REGS
  313.     PUSH    H
  314.     PUSH    PSW
  315.     MVI    C,27    ; GET ADDRESS OF ALLOCATION VECTOR
  316.     CALL    BDOS
  317.     XCHG
  318.     LHLD    BLKMAX    ; GET LENGTH OF ALLOCATION VECTOR
  319.     LXI    B,0    ; INIT BLOCK COUNT TO 0
  320.  
  321. ;*
  322. ;*  BC IS ACCUMULATOR FOR SPACE
  323. ;*
  324. FREE1:
  325.     PUSH    D    ; SAVE ALLOC ADDRESS
  326.     LDAX    D    ; GET BIT PATTERN OF ALLOCATION BYTE
  327.     MVI    E,8    ; SET TO PROCESS 8 BLOCKS
  328. FREE2:
  329.     RAL        ; ROTATE ALLOCATED BLOCK BIT INTO CARRY FLAG
  330.     JC    FREE3    ; IF SET (BIT=1), BLOCK IS ALLOCATED
  331.     INX    B    ; IF NOT SET, BLOCK IS NOT ALLOCATED, SO INCREMENT
  332.             ;   FREE BLOCK COUNT
  333. FREE3:
  334.     MOV    D,A    ; SAVE REMAINING ALLOCATION BITS IN D
  335.     DCX    H    ; COUNT DOWN NUMBER OF BLOCKS ON DISK
  336.     MOV    A,L
  337.     ORA    H
  338.     JZ    FREE4    ; DONE IF NO MORE BLOCKS LEFT
  339.     MOV    A,D    ; A=CURRENT ALLOCATION BIT PATTERN
  340.     DCR    E    ; HAVE ALL 8 BITS BEEN EXAMINED?
  341.     JNZ    FREE2    ; CONTINUE IF NOT
  342.     POP    D    ; GET POINTER TO ALLOCATION VECTOR
  343.     INX    D    ; POINT TO NEXT ALLOCATION BYTE
  344.     JMP    FREE1    ; CONTINUE BY PROCESSING NEXT ALLOCATION BYTE
  345.  
  346. ;*
  347. ;*  BC = TOTAL AMOUNT OF FREE SPACE IN TERMS OF BLOCKS
  348. ;*
  349. FREE4:
  350.     POP    D    ; CLEAR DE FROM STACK
  351.     MOV    L,C    ; HL=BC=NUMBER OF FREE BLOCKS
  352.     MOV    H,B
  353.     LDA    BLKSHF    ; GET BLOCK SHIFT FACTOR
  354.     SUI    3    ; CONVERT NUMBER OF BLOCKS TO K
  355.     JZ    FREE6    ; DONE IF SINGLE DENSITY (1K PER BLOCK)
  356.  
  357. ;*
  358. ;*  WE ARE AT A MORE ADVANCED DENSITY LEVEL; MULTIPLY THE NUMBER OF BLOCKS
  359. ;*    BY THE SIZE OF A BLOCK IN K
  360. ;*
  361. FREE5:
  362.     DAD    H    ; 2, 4, 8, 16, ETC K/BLK, SO BLOCK SHIFT FACTOR
  363.     DCR    A    ;   IS A POWER-OF-TWO MULTIPLE
  364.     JNZ    FREE5
  365.  
  366. ;*
  367. ;*  AT THIS POINT, HL=AMOUNT OF FREE SPACE ON DISK IN K
  368. ;*
  369. FREE6:
  370.     XCHG        ; DE=ANSWER
  371.     POP    PSW    ; RESTORE REGS
  372.     POP    H
  373.     POP    B
  374.     RET
  375.  
  376. ;**************************************************************************
  377.  
  378. ;*
  379. ;*  COMPUTE SIZE OF FILE WHOSE LAST EXTENT IS POINTED TO BY HL
  380. ;*    FILE SIZE IS RETURNED IN DE IN K
  381. ;*  NOTE THAT THE ROUTINE DPARAMS MUST HAVE BEEN CALLED BEFORE THIS ROUTINE
  382. ;*    IS USED
  383. ;*
  384. FSIZE::
  385.     PUSH    B    ; SAVE REGS
  386.     PUSH    H
  387.     PUSH    PSW
  388.     LXI    D,12    ; POINT TO EXTENT
  389.     DAD    D
  390.     MOV    E,M    ; GET EXTENT #
  391.     MVI    D,0
  392.     INX    H    ; SKIP S1
  393.     INX    H    ; SKIP S2
  394.     INX    H    ; HL PTS TO RECORD COUNT FIELD
  395.     MOV    A,M    ; GET RECORD COUNT OF LAST EXTENT
  396.     XCHG
  397.     DAD    H    ; NUMBER OF EXTENTS TIMES 16K
  398.     DAD    H
  399.     DAD    H
  400.     DAD    H
  401.     XCHG        ; TOTAL SIZE OF PREVIOUS EXTENTS IN DE
  402.     LXI    H,BLKMSK
  403.     ADD    M    ; ROUND LAST EXTENT TO BLOCK SIZE
  404.     RRC
  405.     RRC        ; CONVERT FROM RECORDS TO K
  406.     RRC
  407.     ANI    1FH
  408.     MOV    L,A    ; ADD SIZE OF LAST EXTENT TO TOTAL OF PREVIOUS EXTENTS
  409.     MVI    H,0    ; HL=SIZE OF LAST EXTENT, DE=TOTAL OF PREVIOUS EXTENTS
  410.     DAD    D    ; HL=TOTAL FILE SIZE IN BLOCKS
  411.     LDA    BLKMSK    ; GET RECORDS/BLK-1
  412.     RRC
  413.     RRC        ; CONVERT TO K/BLK
  414.     RRC
  415.     ANI    1FH
  416.     CMA        ; USE TO FINISH ROUNDING
  417.     ANA    L
  418.     MOV    L,A    ; HL NOW EQUALS THE SIZE OF THE FILE IN K INCREMENTS
  419.     XCHG        ; DE=FILE SIZE IN K
  420.     POP    PSW    ; RESTORE REGS
  421.     POP    H
  422.     POP    B
  423.     RET
  424.  
  425. ;**************************************************************************
  426.  
  427. ;*
  428. ;*  BUILD DIRECTORY TABLE AT DIRBUF
  429. ;*    THIS IS THE OPTIMAL DIRECTORY LOAD ROUTINE; IT ONLY LOADS UNIQUE
  430. ;*        FILE NAMES FROM DISK, BUT THE INFORMATION IS NOT SUFFICIENT
  431. ;*        TO COMPUTE THE FILE SIZES
  432. ;*    ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX)
  433. ;*    ON OUTPUT, BC IS NUM OF FILES
  434. ;*        DE, HL, PSW UNAFFECTED
  435. ;*
  436. DIRLOAD::
  437.     PUSH    H    ; SAVE REGISTERS
  438.     PUSH    D
  439.     MVI    A,0FFH    ; SELECT FILES OF SMALLER EX
  440.     STA    DFLAG    ; SET FLAG
  441. DLCOMMON:
  442.     MVI    A,'?'    ; SELECT FILES FROM ALL USER AREAS
  443.     STA    TFCB    ; SET DR FIELD TO ZERO TO DO THIS
  444.     SHLD    DIRBUF    ; SAVE PTR TO DIRECTORY BUFFER
  445.     SHLD    DSTART    ; SET START OF BUFFER AREA
  446. ;*
  447. ;*  THIS SECTION OF CODE INITIALIZES THE COUNTERS USED
  448. ;*
  449.     LXI    H,0    ; HL=0
  450.     SHLD    FCOUNT    ; TOTAL FILES ON DISK = 0
  451. ;*
  452. ;*  NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER
  453. ;*
  454.     MVI    C,17    ; SEARCH FOR FILE
  455.     LXI    D,TFCB    ; PT TO WILD NAME
  456.     CALL    BDOS
  457.     CPI    255    ; NO MATCH?
  458.     JZ    DIRDN
  459. DIRLP:
  460.     CALL    PENTRY    ; PLACE ENTRY IN DIR
  461.     JZ    DIROVFL    ; MEMORY OVERFLOW ERROR
  462.     MVI    C,18    ; SEARCH FOR NEXT MATCH
  463.     CALL    BDOS
  464.     CPI    255    ; DONE?
  465.     JNZ    DIRLP
  466. ;*
  467. ;*  NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES
  468. ;*
  469. DIRDN:
  470.     MVI    A,0FFH    ; LOAD OK
  471.     ORA    A    ; SET FLAGS
  472. DIRDNX:
  473.     LHLD    FCOUNT    ; GET TOTAL NUMBER OF FILES
  474.     MOV    B,H    ; ... IN BC
  475.     MOV    C,L
  476. ;*
  477. ;*  RESTORE REGISTERS AND RETURN
  478. ;*
  479.     POP    D
  480.     POP    H
  481.     RET
  482. ;*
  483. ;*  MEMORY OVERFLOW ERROR
  484. ;*
  485. DIROVFL:
  486.     XRA    A    ; LOAD ERROR
  487.     JMP    DIRDNX
  488.  
  489. ;*
  490. ;*  PENTRY --
  491. ;*  PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY
  492. ;*
  493. ;*  ON INPUT,  A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB
  494. ;*          FCOUNT=NUMBER OF FILES IN DIR SO FAR
  495. ;*  ON OUTPUT, FCOUNT=NUMBER OF FILES IN DIR SO FAR
  496. ;*          A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR
  497. ;*
  498. PENTRY:
  499.     PUSH    B    ; SAVE REGS
  500.     PUSH    D
  501.     PUSH    H
  502.     RRC        ; MULTIPLY BY 32 FOR OFFSET COMPUTATION
  503.     RRC
  504.     RRC
  505.     ANI    60H    ; A=BYTE OFFSET
  506.     LXI    D,BUFF    ; PT TO BUFFER ENTRY
  507.     MOV    L,A    ; LET HL=OFFSET
  508.     MVI    H,0
  509.     DAD    D    ; HL=PTR TO FCB
  510.     MOV    A,M    ; GET USER NUMBER
  511.     CPI    0E5H    ; DELETED?
  512.     JZ    PEDONE    ; SKIP IT IF DELETED
  513. ;*
  514. ;*  HL=ADR OF FCB IN BUFF
  515. ;*
  516.  
  517. ;*
  518. ;*  SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME
  519. ;*    NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX
  520. ;*    AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT
  521. ;*    FOUND, RETURN WITH ZERO FLAG RESET (NZ)
  522. ;*
  523.     CALL    DUPENTRY    ; CHECK FOR DUPLICATE AND SELECT EX
  524.     JZ    PEDONE    ; SKIP IF DUPLICATE
  525.  
  526. ;*  INCREMENT TOTAL NUMBER OF FILES
  527.     PUSH    H    ; SAVE PTR TO FCB
  528.     LHLD    FCOUNT    ; TOTAL FILES = TOTAL FILES + 1
  529.     INX    H
  530.     SHLD    FCOUNT
  531.     POP    H    ; GET PTR TO FCB
  532.  
  533. ;*
  534. ;*  COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER
  535. ;*
  536.     XCHG        ; SAVE PTR IN DE
  537.     LHLD    DIRBUF    ; PT TO NEXT ENTRY LOCATION
  538.     XCHG        ; HL PTS TO FCB, DE PTS TO NEXT ENTRY LOCATION
  539.     MVI    B,ESIZE    ; NUMBER OF BYTES/ENTRY
  540.     CALL    MOVE    ; COPY FCB INTO MEMORY BUFFER
  541.     XCHG        ; HL PTS TO NEXT ENTRY
  542.     SHLD    DIRBUF    ; SET PTR
  543.     XCHG        ; PTR TO NEXT ENTRY IN DE
  544.     LHLD    BDOS+1    ; BASE ADDRESS OF BDOS IN HL
  545.     MOV    A,H    ; GET BASE PAGE OF BDOS
  546.     SUI    9    ; COMPUTE 1 PAGE IN FRONT OF BASE PAGE OF CCP
  547.     CMP    D    ; IS PTR TO NEXT ENTRY BEYOND THIS?
  548.     JNZ    PEDONE    ; OK IF NOT AT BUFFER OVERFLOW LEVEL
  549.  
  550. ;*  DONE WITH PENTRY WITH MEMORY OVERFLOW ERROR
  551. PEOVFL:
  552.     XRA    A    ; ERROR
  553.     POP    H    ; RESTORE REGS
  554.     POP    D
  555.     POP    B
  556.     RET
  557.  
  558. ;*  DONE WITH PENTRY AND NO ERROR
  559. PEDONE:
  560.     MVI    A,0FFH    ; NO ERROR
  561.     ORA    A    ; SET FLAGS
  562.     POP    H    ; RESTORE REGS
  563.     POP    D
  564.     POP    B
  565.     RET
  566.  
  567. ;*
  568. ;*  COPY FROM HL TO DE FOR B BYTES
  569. ;*
  570. MOVE:
  571.     MOV    A,M    ; GET BYTE
  572.     STAX    D    ; PUT BYTE
  573.     INX    H    ; PT TO NEXT
  574.     INX    D
  575.     DCR    B    ; COUNT DOWN
  576.     JNZ    MOVE
  577.     RET
  578.  
  579. ;**************************************************************************
  580.  
  581. ;*
  582. ;*  BUILD DIRECTORY TABLE AT DIRBUF
  583. ;*    THIS DIRECTORY LOAD ROUTINE IS MUST LESS EFFICIENT THAN DIRLOAD,
  584. ;*        BUT IT DOES LOAD ENOUGH INFORMATION TO COMPUTE THE FILE
  585. ;*        SIZES USING THE FSIZE ROUTINE
  586. ;*    ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX)
  587. ;*    ON OUTPUT, BC IS NUM OF FILES
  588. ;*        DE, HL, PSW UNAFFECTED
  589. ;*
  590. DIRSLOAD::
  591.     PUSH    H    ; SAVE REGISTERS
  592.     PUSH    D
  593.     XRA    A    ; SELECT LARGER EX
  594.     STA    DFLAG    ; SET FLAG
  595.     JMP    DLCOMMON
  596.  
  597. ;*
  598. ;*  SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME
  599. ;*    NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX
  600. ;*    AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT
  601. ;*    FOUND, RETURN WITH ZERO FLAG RESET (NZ)
  602. ;*  ON INPUT, HL PTS TO ENTRY TO SCAN FOR, FCOUNT = NUMBER OF ENTRIES SO FAR,
  603. ;*        AND (DSTART) = STARTING ADDRESS OF DIRECTORY LOADED
  604. ;*  ON OUTPUT, A=0 AND ZERO FLAG SET IF DUPLICATE ENTRY FOUND; A=0FFH AND NZ
  605. ;*        IF NO DUP ENTRY FOUND
  606. ;*        ONLY HL NOT AFFECTED
  607. ;*
  608. DUPENTRY:
  609.     PUSH    H    ; SAVE PTR TO ENTRY TO SCAN FOR
  610.     XCHG        ; PTR IN DE
  611.     LHLD    FCOUNT    ; CHECK COUNT
  612.     MOV    A,H    ; NO ENTRIES?
  613.     ORA    L
  614.     JZ    NODUP    ; NO DUPLICATE ENTRY RETURN
  615.     MOV    B,H    ; BC=NUMBER OF ENTRIES
  616.     MOV    C,L
  617.     LHLD    DSTART    ; HL PTS TO FIRST ENTRY
  618. DUPELOOP:
  619.     PUSH    B    ; SAVE COUNT
  620.     PUSH    H    ; SAVE PTRS
  621.     PUSH    D
  622.     MVI    B,12    ; COMPARE USER NUMBER, FN, AND FT
  623.     CALL    COMP
  624.     POP    D    ; RESTORE PTRS
  625.     POP    H
  626.     JNZ    NODUPL    ; CONTINUE LOOKING FOR ANOTHER ENTRY
  627. ;  DUPLICATE ENTRIES HAVE BEEN IDENTIFIED AT THIS POINT
  628.     PUSH    H    ; SAVE PTRS AGAIN
  629.     PUSH    D
  630.     LXI    B,12    ; PT TO EX FIELD
  631.     DAD    B
  632.     XCHG
  633.     DAD    B    ; DE PTS TO DIRECTORY ENTRY, HL PTS TO TARGET
  634.     LDAX    D    ; GET EXTENT FIELD FROM DIRECTORY ENTRY
  635.     CMP    M    ; COMPARE WITH THAT IN TARGET
  636.     POP    D    ; GET PTRS
  637.     POP    H
  638.     JNC    DUPSMALL
  639. ;  NEW TARGET IS LARGER THAN STORED ENTRY
  640.     LDA    DFLAG    ; CHECK FLAG FOR LARGE OR SMALL EX
  641.     ORA    A    ; 0=SELECT LARGER
  642.     JNZ    DUPFND
  643. DUPSEL:
  644.     XCHG        ; MAKE HL PT TO NEW TARGET, DE PT TO DEST
  645.     MVI    B,ESIZE    ; NUMBER OF BYTES TO MOVE
  646.     CALL    MOVE    ; MOVE IT
  647.     JMP    DUPFND
  648. ;  NEW TARGET IS SMALLER THAN STORED ENTRY
  649. DUPSMALL:
  650.     LDA    DFLAG    ; CHECK FLAG FOR LARGE OR SMALL EX
  651.     ORA    A    ; 0FFH=SELECT SMALLER
  652.     JNZ    DUPSEL
  653. ;  RETURN INDICATOR THAT DUPLICATE WAS FOUND
  654. DUPFND:
  655.     POP    B    ; CLEAR COUNT FROM STACK
  656.     XRA    A    ; INDICATE DUP FOUND
  657.     POP    H    ; RESTORE PTR TO ENTRY TO SCAN FOR
  658.     RET
  659. ;  NO DUPLICATE FOUND; ADVANCE TO NEXT ENTRY
  660. NODUPL:
  661.     LXI    B,ESIZE    ; HL PTS TO CURRENT ENTRY IN BUFFER, SO ADD ESIZE TO IT
  662.     DAD    B
  663.     POP    B    ; GET COUNT
  664.     DCX    B    ; COUNT DOWN
  665.     MOV    A,B    ; CHECK FOR DONE
  666.     ORA    C
  667.     JNZ    DUPELOOP
  668. ;  NO DUPLICATE FOUND, PERIOD
  669. NODUP:
  670.     MVI    A,0FFH    ; INDICATE DUP NOT FOUND
  671.     ORA    A    ; SET FLAGS
  672.     POP    H    ; RESTORE PTR TO ENTRY TO SCAN FOR
  673.     RET
  674.  
  675. ;**************************************************************************
  676.  
  677. ;*
  678. ;*  DIRALPHA -- ALPHABETIZES DIRECTORY PTED TO BY HL; BC CONTAINS
  679. ;*    THE NUMBER OF FILES IN THE DIRECTORY AND A = SORT FLAG
  680. ;*    (0=SORT BY FILE NAME/TYPE, <>0 = SORT BY FILE TYPE/NAME)
  681. ;*
  682. DIRALPHA::
  683.     STA    CMP$FLAG    ; SET FLAG
  684.     MOV    A,B    ; ANY FILES?
  685.     ORA    C
  686.     RZ
  687.     PUSH    H    ; SAVE REGS
  688.     PUSH    D
  689.     PUSH    B
  690.     SHLD    DIRBUF    ; SAVE PTR TO DIRECTORY
  691.     PUSH    H    ; SAVE HL
  692.     MOV    H,B    ; HL=BC=FILE COUNT
  693.     MOV    L,C
  694.     SHLD    N    ; SET "N"
  695.     POP    H
  696. ;*
  697. ;*  SHELL SORT --
  698. ;*    THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS"
  699. ;*    BY KERNIGAN AND PLAUGHER, PAGE 106.  COPYRIGHT, 1976, ADDISON-WESLEY.
  700. ;*  ON ENTRY, BC=NUMBER OF ENTRIES
  701. ;*
  702. SORT:
  703.     XCHG        ; POINTER TO DIRECTORY IN DE
  704.     LHLD    ORDER    ; PT TO ORDER TABLE
  705. ;*
  706. ;*  SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT
  707. ;*    ENTRY IN DIRECTORY, BC = NUMBER OF ELEMENTS REMAINING
  708. ;*
  709. SORT1:
  710.     MOV    M,E    ; STORE LOW-ORDER ADDRESS
  711.     INX    H    ; PT TO NEXT ORDER BYTE
  712.     MOV    M,D    ; STORE HIGH-ORDER ADDRESS
  713.     INX    H    ; PT TO NEXT ORDER ENTRY
  714.     PUSH    H    ; SAVE PTR
  715.     LXI    H,ESIZE    ; HL=NUMBER OF BYTES/ENTRY
  716.     DAD    D    ; PT TO NEXT DIR1 ENTRY
  717.     XCHG        ; DE PTS TO NEXT ENTRY
  718.     POP    H    ; GET PTR TO ORDER TABLE
  719.     DCX    B    ; COUNT DOWN
  720.     MOV    A,B    ; DONE?
  721.     ORA    C
  722.     JNZ    SORT1
  723. ;*
  724. ;*  THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P
  725. ;*
  726.  
  727. ;*
  728. ;*  SHELL SORT FROM "SOFTWARE TOOLS" BY KERNINGHAN AND PLAUGER
  729. ;*
  730.     LHLD    N    ; NUMBER OF ITEMS TO SORT
  731.     SHLD    GAP    ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2
  732.  
  733. ;*  FOR (GAP = N/2; GAP > 0; GAP = GAP/2)
  734. SRTL0:
  735.     ORA    A    ; CLEAR CARRY
  736.     LHLD    GAP    ; GET PREVIOUS GAP
  737.     MOV    A,H    ; ROTATE RIGHT TO DIVIDE BY 2
  738.     RAR
  739.     MOV    H,A
  740.     MOV    A,L
  741.     RAR
  742.     MOV    L,A
  743.  
  744. ;*  TEST FOR ZERO
  745.     ORA    H
  746.     JZ    SDONE    ; DONE WITH SORT IF GAP = 0
  747.  
  748.     SHLD    GAP    ; SET VALUE OF GAP
  749.     SHLD    I    ; SET I=GAP FOR FOLLOWING LOOP
  750.  
  751. ;*  FOR (I = GAP + 1; I <= N; I = I + 1)
  752. SRTL1:
  753.     LHLD    I    ; ADD 1 TO I
  754.     INX    H
  755.     SHLD    I
  756.  
  757. ;*  TEST FOR I <= N
  758.     XCHG        ; I IS IN DE
  759.     LHLD    N    ; GET N
  760.     MOV    A,L    ; COMPARE BY SUBTRACTION
  761.     SUB    E
  762.     MOV    A,H
  763.     SBB    D    ; CARRY SET MEANS I > N
  764.     JC    SRTL0    ; DON'T DO FOR LOOP IF I > N
  765.  
  766.     LHLD    I    ; SET J = I INITIALLY FOR FIRST SUBTRACTION OF GAP
  767.     SHLD    J
  768.  
  769. ;*  FOR (J = I - GAP; J > 0; J = J - GAP)
  770. SRTL2:
  771.     LHLD    GAP    ; GET GAP
  772.     XCHG        ; ... IN DE
  773.     LHLD    J    ; GET J
  774.     MOV    A,L    ; COMPUTE J - GAP
  775.     SUB    E
  776.     MOV    L,A
  777.     MOV    A,H
  778.     SBB    D
  779.     MOV    H,A
  780.     SHLD    J    ; J = J - GAP
  781.     JC    SRTL1    ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT
  782.     MOV    A,H    ; J=0?
  783.     ORA    L
  784.     JZ    SRTL1    ; IF ZERO, J=0 AND ABORT
  785.  
  786. ;*  SET JG = J + GAP
  787.     XCHG        ; J IN DE
  788.     LHLD    GAP    ; GET GAP
  789.     DAD    D    ; J + GAP
  790.     SHLD    JG    ; JG = J + GAP
  791.  
  792. ;*  IF (V(J) <= V(JG))
  793.     CALL    ICOMPARE    ; J IN DE, JG IN HL
  794.  
  795. ;*  ... THEN BREAK
  796.     JC    SRTL1
  797.  
  798. ;*  ... ELSE EXCHANGE
  799.     LHLD    J    ; SWAP J, JG
  800.     XCHG
  801.     LHLD    JG
  802.     CALL    ISWAP    ; J IN DE, JG IN HL
  803.  
  804. ;*  END OF INNER-MOST FOR LOOP
  805.     JMP    SRTL2
  806.  
  807. ;*
  808. ;*  SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE
  809. ;*
  810. SDONE:
  811.     LHLD    N    ; NUMBER OF ENTRIES
  812.     MOV    B,H    ; ... IN BC
  813.     MOV    C,L
  814.     LHLD    ORDER    ; PTR TO ORDERED POINTER TABLE
  815.     SHLD    PTPTR    ; SET PTR PTR
  816.     LHLD    DIRBUF    ; PTR TO UNORDERED DIRECTORY
  817.     SHLD    PTDIR    ; SET PTR DIR BUFFER
  818.  
  819. ;*  FIND PTR TO NEXT DIR1 ENTRY
  820. SRTDN:
  821.     LHLD    PTPTR    ; PT TO REMAINING POINTERS
  822.     XCHG        ; ... IN DE
  823.     LHLD    PTDIR    ; HL PTS TO NEXT DIR ENTRY
  824.     PUSH    B    ; SAVE COUNT OF REMAINING ENTRIES
  825.  
  826. ;*  FIND PTR TABLE ENTRY
  827. SRTDN1:
  828.     LDAX    D    ; GET CURRENT POINTER TABLE ENTRY VALUE
  829.     INX    D    ; PT TO HIGH-ORDER POINTER BYTE
  830.     CMP    L    ; COMPARE AGAINST DIR1 ADDRESS LOW
  831.     JNZ    SRTDN2    ; NOT FOUND YET
  832.     LDAX    D    ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE
  833.     CMP    H    ; COMPARE AGAINST DIR1 ADDRESS HIGH
  834.     JZ    SRTDN3    ; MATCH FOUND
  835. SRTDN2:
  836.     INX    D    ; PT TO NEXT PTR TABLE ENTRY
  837.     DCX    B    ; COUNT DOWN
  838.     MOV    A,C    ; END OF TABLE?
  839.     ORA    B
  840.     JNZ    SRTDN1    ; CONTINUE IF NOT
  841.  
  842. ;*  FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT
  843. FERR$PTR:
  844.     CALL    PRINT
  845.     DB    0DH,0AH,'DIRALPHA -- Pointer Error',0
  846.     JMP    CPM
  847.  
  848. ;*  FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED DIR1 ENTRY
  849. ;*    MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED DIR1 ENTRY)
  850. ;*    POINT TO SAME LOCATION (PTR TO NEXT DIR1 ENTRY TO BE ORDERED)
  851. SRTDN3:
  852.     LHLD    PTPTR    ; GET PTR TO NEXT ORDERED ENTRY
  853.     DCX    D    ; DE PTS TO LOW-ORDER POINTER ADDRESS
  854.     MOV    A,M    ; MAKE PTR TO NEXT UNORDERED DIR1 PT TO BUFFER FOR
  855.     STAX    D    ;   DIR1 ENTRY TO BE MOVED TO NEXT UNORDERED DIR1 POS
  856.     INX    H    ; PT TO NEXT PTR ADDRESS
  857.     INX    D
  858.     MOV    A,M    ; MAKE HIGH POINT SIMILARLY
  859.     STAX    D
  860.  
  861. ;*  COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER
  862.     MVI    B,ESIZE    ; B=NUMBER OF BYTES/ENTRY
  863.     LHLD    PTDIR    ; PT TO ENTRY
  864.     LXI    D,HOLD    ; PT TO HOLD BUFFER
  865.     PUSH    B    ; SAVE B=NUMBER OF BYTES/ENTRY
  866.     CALL    MOVE
  867.     POP    B
  868.  
  869. ;*  COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION
  870.     LHLD    PTPTR    ; POINT TO ITS POINTER
  871.     MOV    E,M    ; GET LOW-ADDRESS POINTER
  872.     INX    H
  873.     MOV    D,M    ; GET HIGH-ADDRESS POINTER
  874.     LHLD    PTDIR    ; DESTINATION ADDRESS FOR NEXT ORDERED DIR1 ENTRY
  875.     XCHG        ; HL PTS TO ENTRY TO BE MOVED, DE PTS TO DEST
  876.     PUSH    B    ; SAVE B=NUMBER OF BYTES/ENTRY
  877.     CALL    MOVE
  878.     POP    B
  879.     XCHG        ; HL PTS TO NEXT UNORDERED DIR1 ENTRY
  880.     SHLD    PTDIR    ; SET POINTER FOR NEXT LOOP
  881.  
  882. ;*  COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY
  883.     LHLD    PTPTR    ; GET PTR TO PTR TO THE DESTINATION
  884.     MOV    E,M    ; GET LOW-ADDRESS POINTER
  885.     INX    H
  886.     MOV    D,M    ; HIGH-ADDRESS POINTER
  887.     LXI    H,HOLD    ; HL PTS TO HOLD BUFFER, DE PTS TO ENTRY DEST
  888.     CALL    MOVE    ; B=NUMBER OF BYTES/ENTRY
  889.  
  890. ;*  POINT TO NEXT ENTRY IN POINTER TABLE
  891.     LHLD    PTPTR    ; POINTER TO CURRENT ENTRY
  892.     INX    H    ; SKIP OVER IT
  893.     INX    H
  894.     SHLD    PTPTR
  895.  
  896. ;*  COUNT DOWN
  897.     POP    B    ; GET COUNTER
  898.     DCX    B    ; COUNT DOWN
  899.     MOV    A,C    ; DONE?
  900.     ORA    B
  901.     JNZ    SRTDN
  902.     POP    B    ; RESTORE REGS
  903.     POP    D
  904.     POP    H
  905.     RET        ; DONE
  906.  
  907. ;*
  908. ;*  SWAP (Exchange) the pointers in the ORDER table whose indexes are in
  909. ;*    HL and DE
  910. ;*
  911. ISWAP:
  912.     PUSH    H        ; SAVE HL
  913.     LHLD    ORDER        ; ADDRESS OF ORDER TABLE - 2
  914.     MOV    B,H        ; ... IN BC
  915.     MOV    C,L
  916.     POP    H
  917.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  918.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  919.                 ;   OF ORIGINAL HL (1, 2, ...)
  920.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  921.     XCHG            ; DE NOW PTS TO POINTER INDEXED BY HL
  922.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  923.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  924.                 ;   OF ORIGINAL DE (1, 2, ...)
  925.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  926.     MOV    C,M        ; EXCHANGE POINTERS -- GET OLD (DE)
  927.     LDAX    D        ; -- GET OLD (HL)
  928.     XCHG            ; SWITCH
  929.     MOV    M,C        ; PUT NEW (HL)
  930.     STAX    D        ; PUT NEW (DE)
  931.     INX    H        ; PT TO NEXT BYTE OF POINTER
  932.     INX    D
  933.     MOV    C,M        ; GET OLD (HL)
  934.     LDAX    D        ; GET OLD (DE)
  935.     XCHG            ; SWITCH
  936.     MOV    M,C        ; PUT NEW (DE)
  937.     STAX    D        ; PUT NEW (HL)
  938.     RET
  939. ;*
  940. ;*  ICOMPARE compares the entry pointed to by the pointer pointed to by HL
  941. ;*    with that pointed to by DE (1st level indirect addressing); on entry,
  942. ;*    HL and DE contain the numbers of the elements to compare (1, 2, ...);
  943. ;*    on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)),
  944. ;*    and Non-Zero and No-Carry means ((DE)) > ((HL))
  945. ;*
  946. ICOMPARE:
  947.     PUSH    H        ; SAVE HL
  948.     LHLD    ORDER        ; ADDRESS OF ORDER - 2
  949.     MOV    B,H        ; ... IN BC
  950.     MOV    C,L
  951.     POP    H
  952.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  953.     DAD    H        ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR
  954.     DAD    B        ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE
  955.     XCHG            ; RESULT IN DE
  956.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  957.     DAD    H        ; DO THE SAME WITH THE ORIGINAL DE
  958.     DAD    B
  959.     XCHG
  960.  
  961. ;*
  962. ;*  HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH
  963. ;*  DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH
  964. ;*    FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL
  965. ;* TO THE 4TH POINTER
  966. ;*
  967.     MOV    C,M        ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO
  968.     INX    H        ; ... BY THE ORIGINAL HL
  969.     MOV    B,M
  970.     XCHG
  971.     MOV    E,M        ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO
  972.     INX    H        ; ... BY THE ORIGINAL DE
  973.     MOV    D,M
  974.     MOV    H,B        ; SET HL = OBJECT PTED TO INDIRECTLY BY BC
  975.     MOV    L,C
  976.  
  977. ;*
  978. ;*  COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE;
  979. ;*    NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE<HL
  980. ;*    RET W/ZERO SET MEANS DE=HL
  981. ;*
  982. CMP$ENTRY:
  983.     LDA    CMP$FLAG    ; GROUP BY FILE TYPE?
  984.     ORA    A
  985.     JZ    CMP$FN$FT
  986. ;*
  987. ;*  COMPARE BY FILE TYPE, FILE NAME, EXTENSION, AND USER (IN THAT ORDER)
  988. ;*
  989. CMP$FCB1:    
  990.     PUSH    H
  991.     PUSH    D
  992.     LXI    B,9    ; PT TO FT (8 BYTES + 1 BYTE FOR USER NUMBER)
  993.     DAD    B
  994.     XCHG
  995.     DAD    B
  996.     XCHG        ; DE, HL NOW PT TO THEIR FT'S
  997.     MVI    B,3    ; 3 BYTES
  998.     CALL    COMP    ; COMPARE FT'S
  999.     POP    D
  1000.     POP    H
  1001.     RNZ        ; CONTINUE IF COMPLETE MATCH
  1002.     PUSH    H
  1003.     PUSH    D
  1004.     INX    H    ; PT TO FILE NAME
  1005.     INX    D
  1006.     MVI    B,8    ; 8 BYTES
  1007.     CALL    COMP    ; COMPARE FN'S
  1008.     POP    D
  1009.     POP    H
  1010.     RNZ        ; CONTINUE IF COMPLETE MATCH
  1011.     PUSH    H
  1012.     PUSH    D
  1013.     LXI    B,12    ; PT TO EXT (11 BYTES FOR FN/FT AND 1 BYTE FOR USER)
  1014.     DAD    B
  1015.     XCHG
  1016.     DAD    B
  1017.     XCHG        ; DE, HL NOW PT TO THEIR EXT'S
  1018.     LDAX    D    ; COMPARE
  1019.     CMP    M
  1020.     POP    D
  1021.     POP    H
  1022.     RNZ
  1023.     LDAX    D    ; COMPARE USER NUMBERS
  1024.     CMP    M
  1025.     RET
  1026. ;*
  1027. ;*  COMPARE BY FILE NAME, FILE TYPE, EXTENSION, AND USER NUM (IN THAT ORDER)
  1028. ;*
  1029. CMP$FN$FT:
  1030.     PUSH    H
  1031.     PUSH    D
  1032.     INX    H    ; PT TO FN
  1033.     INX    D
  1034.     MVI    B,12    ; COMPARE FN, FT, EX
  1035.     CALL    COMP
  1036.     POP    D
  1037.     POP    H
  1038.     RNZ
  1039.     LDAX    D    ; COMPARE USER NUMBER
  1040.     CMP    M
  1041.     RET
  1042. ;*
  1043. ;*  COMP COMPARES DE W/HL FOR B BYTES; RET W/CARRY IF DE<HL
  1044. ;*    MSB IS DISREGARDED
  1045. ;*
  1046. COMP:
  1047.     MOV    A,M    ; GET (HL)
  1048.     ANI    7FH    ; MASK MSB
  1049.     MOV    C,A    ; ... IN C
  1050.     LDAX    D    ; COMPARE
  1051.     ANI    7FH    ; MASK MSB
  1052.     CMP    C
  1053.     RNZ
  1054.     INX    H    ; PT TO NEXT
  1055.     INX    D
  1056.     DCR    B    ; COUNT DOWN
  1057.     JNZ    COMP
  1058.     RET
  1059. ;*
  1060. ;*  AS COMP, BUT MATCH ON '?' PTED TO BY HL
  1061. ;*
  1062. COMP2:
  1063.     MOV    A,M    ; GET (HL)
  1064.     ANI    7FH    ; MASK MSB
  1065.     CPI    '?'    ; MATCH '?'
  1066.     JZ    COMP2A
  1067.     MOV    C,A    ; ... IN C
  1068.     LDAX    D    ; COMPARE
  1069.     ANI    7FH    ; MASK MSB
  1070.     CMP    C
  1071.     RNZ
  1072. COMP2A:
  1073.     INX    H    ; PT TO NEXT
  1074.     INX    D
  1075.     DCR    B    ; COUNT DOWN
  1076.     JNZ    COMP2
  1077.     RET
  1078.  
  1079. ;*
  1080. ;*  DIRSEL -- SELECT DIRECTORY ENTRIES WHICH MATCH USER NUMBER, FILE
  1081. ;*    NAME, AND FILE TYPE PTED TO BY DE
  1082. ;*
  1083. ;*  ON INPUT, HL PTS TO DIRECTORY, DE PTS TO FCB, BC=NUMBER OF FILES, A=FLAG:
  1084. ;*            Bit 7 - Select Non-Sys, Bit 6 - Select Sys
  1085. ;*            Bit 5 - Select All Users, Bits 4-0 - User Number
  1086. ;*  ON OUTPUT, THE MS BIT OF THE USER OF THE SELECTED FILES IS SET
  1087. ;*
  1088. DIRSEL::
  1089.     PUSH    H    ; SAVE REGS
  1090.     PUSH    D
  1091.     PUSH    B
  1092.     PUSH    PSW
  1093.     STA    SELFLG    ; SAVE SELECT FLAG
  1094.     SHLD    DIRBUF    ; SAVE PTR
  1095.     PUSH    B    ; SAVE COUNT
  1096.  
  1097. ;*  CHECK FOR MATCH
  1098. DSMAT:
  1099.     POP    B    ; GET COUNT
  1100.     MOV    A,B    ; CHECK FOR NO ENTRIES
  1101.     ORA    C
  1102.     JZ    DSDONE    ; DONE IF NONE
  1103.     DCX    B    ; COUNT DOWN
  1104.     PUSH    B    ; SAVE COUNT
  1105.     PUSH    H    ; SAVE PTRS
  1106.     PUSH    D
  1107.     INX    H    ; PT TO FN
  1108.     INX    D
  1109.     MVI    B,8    ; CHECK 8 CHARS
  1110.     XCHG        ; LET HL PT TO FCB
  1111.     CALL    COMP2    ; COMPARE WITH '?' MATCH
  1112.     POP    D    ; GET PTRS
  1113.     POP    H
  1114.     JNZ    DSMATNX    ; ADVANCE TO NEXT ENTRY IF NO MATCH
  1115.     PUSH    H    ; SAVE PTRS
  1116.     PUSH    D
  1117.     LXI    B,9    ; CHECK R/O FLAG, SYS FLAG, LAST BYTE
  1118.     DAD    B
  1119.     XCHG
  1120.     DAD    B    ; DON'T EXCHANGE -- HL PTS TO FCB, DE PTS TO DIR
  1121.     MVI    B,3    ; CHECK 3 BYTES
  1122.     CALL    COMP2    ; COMPARE WITH '?' MATCH
  1123.     POP    D    ; RESTORE PTRS
  1124.     POP    H
  1125.     JNZ    DSMATNX    ; NO MATCH?
  1126.     CALL    FLGCHK    ; CHECK FLAGS
  1127.     JNZ    DSMATNX    ; NO MATCH?
  1128.  
  1129. ;*
  1130. ;*  WE HAVE A MATCH -- MARK ENTRY
  1131. ;*
  1132. DSMARK:
  1133.     MOV    A,M    ; GET BYTE
  1134.     ORI    80H    ; SET MSB
  1135.     MOV    M,A    ; PUT BYTE
  1136.  
  1137. ;*
  1138. ;*  ADVANCE TO NEXT ENTRY
  1139. ;*
  1140. DSMATNX:
  1141.     LXI    B,ESIZE    ; NUMBER OF BYTES/ENTRY
  1142.     DAD    B    ; PT TO NEXT ENTRY
  1143.     JMP    DSMAT    ; CONTINUE
  1144.  
  1145. ;*
  1146. ;*  DONE WITH SCAN
  1147. ;*
  1148. DSDONE:
  1149.     POP    PSW        ; RESTORE REGS
  1150.     POP    B
  1151.     POP    D
  1152.     POP    H
  1153.     RET
  1154.  
  1155. ;*
  1156. ;*  WE HAVE A NAME MATCH -- NOW CHECK FLAGS
  1157. ;*    RETURN Z IF MATCH, NZ IF NO MATCH
  1158. ;*
  1159. FLGCHK:
  1160.     PUSH    D    ; SAVE FCB PTR
  1161.     PUSH    H    ; SAVE ENTRY PTR
  1162.     LXI    D,10    ; CHECK SYSTEM BIT
  1163.     DAD    D    ; HL PTS TO SYSTEM BIT
  1164.     MOV    A,M    ; GET BYTE
  1165.     POP    H    ; RESTORE PTRS
  1166.     POP    D
  1167.     ANI    80H    ; MASK FOR SYSTEM BIT
  1168.     LDA    SELFLG    ; GET FLAG BYTE
  1169.     JZ    DSNSBIT
  1170. ; IT IS A SYSTEM FILE, SO LOOK AT BIT 6 OF FLAG
  1171.     ANI    40H    ; LOOK AT BIT 6
  1172.     JNZ    DSUSER    ; OK, SO LOOK AT USER
  1173.     JMP    DSNOMAT    ; CONTINUE PROCESSING
  1174. ; IT IS A NON-SYSTEM FILE, SO LOOK AT BIT 7 OF FLAG
  1175. DSNSBIT:
  1176.     ANI    80H    ; LOOK AT BIT 7
  1177.     JZ    DSNOMAT    ; NOT SET, SO SKIP ENTRY AS FAILING TEST
  1178. ; NOW CHECK FOR PROPER USER AREA
  1179. DSUSER:
  1180.     LDA    SELFLG    ; GET FLAG
  1181.     ANI    20H    ; CHECK FOR ALL USERS
  1182.     JNZ    DSYESMAT    ; MATCH IF SET
  1183.     LDA    SELFLG    ; GET FLAG
  1184.     ANI    1FH    ; GET USER NUMBER (LOW 5 BITS)
  1185.     MOV    B,A    ; SAVE IN B
  1186.     MOV    A,M    ; COMPARE USER NUMBER TO DIR ENTRY
  1187.     ANI    1FH    ; LOOK AT USER NUMBER
  1188.     CMP    B    ; COMPARE TO PASSED USER NUMBER
  1189.     JNZ    DSNOMAT    ; SKIP IF NOT SAME USER NUMBER
  1190. ;  MATCH, SO RETURN Z
  1191. DSYESMAT:
  1192.     XRA    A    ; SET ZERO
  1193.     RET
  1194. ;  NOT A MATCH, SO RETURN NZ
  1195. DSNOMAT:
  1196.     MVI    A,0FFH    ; SET NO ZERO
  1197.     ORA    A
  1198.     RET
  1199.  
  1200. ;**************************************************************************
  1201.  
  1202. ;*
  1203. ;*  NEGATIVE DIRECTORY PACK UTILITY -- RESTRUCTURE THE DIRECTORY TO INCLUDE
  1204. ;*    ONLY THOSE ENTRIES NOT MARKED BY DIRSEL
  1205. ;*
  1206. ;*  ON INPUT, HL PTS TO DIRECTORY BUFFER AND BC=NUMBER OF FILES
  1207. ;*  ON EXIT, BC=NUMBER OF SELECTED FILES
  1208. ;*  REQUIRED SIDE EFFECT IS THAT FLAG EXTENT (SET BY DIR::) BE CORRECT
  1209. ;*    (IN MOST CASES, DEFAULT OF 0 IS OK, EXCEPT WHEN EXTENT SIZE >16K)
  1210. ;*
  1211. DIRNPACK::
  1212.     PUSH    H    ; SAVE REGS
  1213.     PUSH    D
  1214.     PUSH    B
  1215.     PUSH    PSW
  1216. DNPACK:
  1217.     MOV    A,B    ; DONE?
  1218.     ORA    C
  1219.     JZ    DNPAK1
  1220.     DCX    B    ; COUNT DOWN
  1221.     MOV    A,M    ; GET FIRST BYTE
  1222.     CMA        ; FLIP BITS
  1223.     ANI    80H    ; LOOK AT MOST SIG BIT
  1224.     MOV    D,A    ; SAVE IN D
  1225.     MOV    A,M    ; GET FIRST BYTE AGAIN
  1226.     ANI    7FH    ; MASK OUT MS BIT
  1227.     ORA    D    ; MASK IN NEW MOST SIG BIT
  1228.     MOV    M,A    ; PUT BYTE BACK
  1229.     ANI    80H    ; SELECTED NOW?
  1230.     JZ    DNPAK0    ; SKIP IF NOT SELECTED
  1231.     PUSH    B    ; SAVE COUNTER
  1232.     CALL    FLGCHK    ; CHECK FOR FLAGS
  1233.     POP    B    ; GET COUNTER
  1234.     JZ    DNPAK0
  1235.     MOV    A,M    ; GET BYTE
  1236.     ANI    7FH    ; DESELECT IT
  1237.     MOV    M,A    ; PUT BYTE BACK
  1238. DNPAK0:
  1239.     LXI    D,ESIZE    ; POINT TO NEXT ENTRY
  1240.     DAD    D
  1241.     JMP    DNPACK
  1242. DNPAK1:
  1243.     POP    PSW    ; RESTORE REGS
  1244.     POP    B
  1245.     POP    D
  1246.     POP    H    ; NOW FALL THRU TO DIRPACK
  1247.  
  1248. ;**************************************************************************
  1249.  
  1250. ;*
  1251. ;*  DIRECTORY PACK UTILITY -- RESTRUCTURE THE DIRECTORY TO INCLUDE ONLY
  1252. ;*    THOSE ENTRIES MARKED BY DIRSEL
  1253. ;*
  1254. ;*  ON INPUT, HL PTS TO DIRECTORY BUFFER AND BC=NUMBER OF FILES
  1255. ;*  ON EXIT, BC=NUMBER OF SELECTED FILES
  1256. ;*  REQUIRED SIDE EFFECT IS THAT FLAG EXTENT (SET BY DIR::) BE CORRECT
  1257. ;*    (IN MOST CASES, DEFAULT OF 0 IS OK, EXCEPT WHEN EXTENT SIZE >16K)
  1258. ;*
  1259. DIRPACK::
  1260.     PUSH    H    ; SAVE REGS
  1261.     PUSH    D
  1262.     PUSH    PSW
  1263.     PUSH    H    ; SAVE HL
  1264.     LXI    H,0
  1265.     SHLD    FCOUNT    ; INIT FILE COUNT
  1266.     POP    H    ; GET HL
  1267.     SHLD    DIRBUF    ; SAVE PTR
  1268.     PUSH    B    ; SAVE COUNTER
  1269. DPLOOP:
  1270.     POP    B    ; GET COUNTER
  1271.     MOV    A,B    ; CHECK FOR DONE
  1272.     ORA    C
  1273.     JZ    DPDONE
  1274.     DCX    B    ; COUNT DOWN
  1275.     PUSH    B    ; SAVE COUNTER
  1276.     MOV    A,M    ; GET 1ST BYTE OF ENTRY
  1277.     ANI    80H    ; SELECTED?
  1278.     JZ    DPNEXT
  1279. ;*  FOUND SELECTED ENTRY
  1280.     MOV    A,M    ; CLEAR MSB OF SELECTED ENTRY
  1281.     ANI    7FH
  1282.     MOV    M,A
  1283.     PUSH    H    ; SAVE PTR
  1284.     LHLD    FCOUNT    ; INCREMENT FILE COUNT
  1285.     INX    H
  1286.     SHLD    FCOUNT
  1287.     POP    D    ; PT TO CURRENT ENTRY IN DE
  1288.     LHLD    DIRBUF    ; PT TO NEXT ENTRY POSITION
  1289.     XCHG        ; HL PTS TO CURRENT, DE PTS TO NEXT ENTRY
  1290.     MVI    B,ESIZE    ; COPY ENTRY
  1291.     CALL    MOVE
  1292.     XCHG        ; HL PTS TO NEXT ENTRY
  1293.     SHLD    DIRBUF    ; SAVE IT
  1294.     XCHG        ; HL PTS TO NEXT ENTRY TO CHECK
  1295.     JMP    DPLOOP    ; CONTINUE
  1296. ;*  SKIP TO NEXT ENTRY
  1297. DPNEXT:
  1298.     LXI    B,ESIZE    ; SKIP ENTRY
  1299.     DAD    B
  1300.     JMP    DPLOOP    ; CONTINUE
  1301. ;*  COMPRESSION COMPLETE -- SET UP RETURNED VALUES
  1302. DPDONE:
  1303.     LHLD    FCOUNT    ; PUT FILE COUNT
  1304.     MOV    B,H    ; ... IN BC
  1305.     MOV    C,L
  1306.     POP    PSW    ; RESTORE REGS
  1307.     POP    D
  1308.     POP    H
  1309.     RET
  1310.  
  1311.     END
  1312.