home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / squsq / unsq15.lbr / UNSQ15.AQM / UNSQ15.ASM
Assembly Source File  |  1985-02-09  |  20KB  |  1,040 lines

  1. ;UNSQ.ASM ver. 1.5 - A Z80 assembly language version of USQ.
  2. ;Copyright (C) 1983,1984 by Gail Zacharias, 345 Harvard St.,Apt. 2A,
  3. ;Cambridge, MA  02138.  Phone (617) 876-3035.
  4. ;
  5. ;Commands:
  6. ; UNSQ inputfile [ outputdrive: ]
  7. ;   Unsqueezes files created with SQ.  Input filename may be ambiguous.
  8. ;   Any matching non-SQ files will be ignored.
  9. ;
  10. ; UNSQ inputfile T
  11. ;   Unsqueezes files and types them out on the console.
  12. ;   ^S pauses output, ^O toggles output on/off.
  13. ;
  14. ;In either form, ^C aborts, ^X skips to next file.
  15. ;
  16. ;Modifications/updates (in reverse order)
  17. ;
  18. ;06/02/84 - Fixed bug introduced in 1.3 where buffer boundaries used wrong
  19. ; UNSQ15    offsets. (GZ for C.Falconer)
  20. ;
  21. ;04/21/84 - Changed ORG statement to allow assembly for
  22. ; UNSQ14    non-standard CP/M systems. (KBP)
  23. ;
  24. ;03/28/84 - Added option to save alternate registers across
  25. ; UNSQ13    system calls. (GZ)
  26. ;
  27. ;11/07/83 - Renamed from USQ to UNSQ to avoid confusion with
  28. ; UNSQ12    other programs of the same name.  Released for
  29. ;        non-commercial use by permission of Gail Zacharias. (KBP)
  30. ;
  31. ;Originally written in March 1983.  Converted to assemble on
  32. ;CP/M with MAC and Z80.LIB -- April 1983 by Keith Petersen, W8SDZ
  33. ;
  34.     MACLIB    Z80        ;Macro Library for MAC to know Z80
  35. ;
  36. TABEX    EQU    -1        ;Sofware-expand tabs on TTY output
  37.                 ;Set to 0 if your terminal has hardware tabs.
  38. EXXOS    EQU    -1        ;Preserve alternate registers across os calls
  39.                 ;Set to 0 if your system doesn't mung them.
  40. ;
  41. ID1    EQU    076H        ;Low ID byte
  42. ID2    EQU    0FFH        ;High ID byte
  43. DLE    EQU    090H        ;Multiples-collapsing escape
  44. ;
  45. ;CP/M stuff
  46. ;
  47. BASE    EQU    0        ;Base address of standard CP/M
  48. ;
  49. XBDOS    EQU    5        ;System BDOS address
  50. ;
  51.     IF    NOT EXXOS
  52. BDOS    EQU    5
  53.     ENDIF
  54. ;
  55. DFCB    EQU    5CH
  56. DFCB2    EQU    DFCB+10H
  57. DBUF    EQU    80H
  58. ;
  59. FCB@EX    EQU    0CH
  60. FCB@CR    EQU    20H
  61. ;
  62. CONIN    EQU    1        ;Console Input
  63. CONOUT    EQU    2        ;Console Output
  64. PCS    EQU    9        ;Print Console String
  65. RCS    EQU    10        ;Read Console String
  66. OPENF    EQU    15        ;Open File
  67. CLOSF    EQU    16        ;Close File
  68. SFF    EQU    17        ;Search For First
  69. SFN    EQU    18        ;Search For Next
  70. DELF    EQU    19        ;Delete File
  71. RSS    EQU    20        ;Read Sector Sequential
  72. WSS    EQU    21        ;Write Sector Sequential
  73. MAKEF    EQU    22        ;Make File
  74. SDMA    EQU    26        ;Set DMA
  75. ;
  76. CR    EQU    'M'-'@'
  77. LF    EQU    'J'-'@'
  78. ;
  79. ;Flags
  80. TTYFLG    EQU    7        ;TTY output (not DISK)
  81. FLSFLG    EQU    6        ;TTY output temporarily being flushed
  82. EOFFLG    EQU    5        ;Past EOF, only reading for checksum (when TTY)
  83. FILFLG    EQU    4        ;Have a file (always false for TTY)
  84. ;
  85.     ORG    BASE+100H    ;TPA
  86. ;
  87. OBUF    EQU    $        ;Output buffer beginning page
  88. CHKSUM    EQU    $+1        ;Checksum
  89. ;
  90. START:    JMP    INIT
  91. ;
  92. ;I/O Transfer subroutine.
  93. ;  Called with buffer address in DE, FCB address in HL, I/O code in A.
  94. ;  Returns with NZ set if error, DE=DE+80h, all other registers preserved.
  95. ;  IOSB gets error status if error.  Carry always cleared.
  96. ;  Gives user a chance to abort.
  97. IOT:    PUSH    B
  98.     PUSH    D
  99.     PUSH    H
  100.     PUSH    PSW
  101.     CALL    SETDMA
  102.     CALL    CONCHK        ;Wanna quit?
  103.     POP    B
  104.     POP    D
  105.     PUSH    D
  106.     PUSH    B
  107.     MOV    C,B
  108.     CALL    BDOS
  109.     POP    B
  110.     POP    H
  111.     XTHL
  112.     LXI    D,80H
  113.     DAD    D
  114.     XCHG
  115.     POP    H
  116.     ORA    A
  117.     JRZ    IOT1
  118.     STA    IOSB
  119. ;
  120. IOT1:    MOV    A,B
  121.     POP    B
  122.     RET
  123. ;
  124. ;Page I/O Transfer. 
  125. ;  Called with A=beginning page, H=end page, BC=FCB, L=I/O code.
  126. ;  Returns with NZ set if error, C=# pages, HL=beginning address,
  127. ;    B,DE,A clobbered.
  128. ;  If A=H, returns with Z set but HL clobbered.
  129. ;  For input transfer returns with Carry set if had EOF last time.
  130. POT:    LDA    OBUF
  131.     MVI    L,WSS
  132.     LXI    B,OFCB
  133.     JR    PIOT
  134. ;
  135. PIT:    MVI    A,IBUF
  136. ;
  137. PIT1:    MOV    L,A
  138.     LDA    IOSB
  139.     ORA    A
  140.     MOV    A,L
  141.     STC
  142.     RNZ
  143.     MVI    L,RSS
  144.     LXI    B,IFCB
  145. ;
  146. PIOT:    PUSH    B
  147.     MOV    D,A
  148.     MOV    A,H
  149.     SUB    D
  150.     MOV    B,A
  151.     MOV    C,A        ;Save it to return
  152.     JRZ    PIOT2
  153.     XRA    A        ;This sets Z for first time in loop
  154.     MOV    E,A        ;Page number --> address
  155.     MOV    A,L
  156.     POP    H
  157.     PUSH    D        ;Save it to return
  158. ;
  159. PIOT1:    CZ    IOT        ;Do a page (2 sectors)
  160.     CZ    IOT
  161.     DJNZ    PIOT1
  162. ;
  163. PIOT2:    POP    H
  164.     RET
  165. ;
  166. ;Flush output file.
  167. ; Called with message pointer in DE.
  168. ; Closes and deletes the file.  All regs clobbered.
  169. FLUSH:    CALL    PRINT        ;Explain the reason
  170.     LDA    FLAGS        ;Nothing to flush if no file
  171.     BIT    FILFLG,A
  172.     RZ
  173.     MVI    C,CLOSF        ;Close it
  174.     CALL    OFDOS
  175.     INR    A
  176.     JZ    CLSERR
  177.     MVI    C,DELF
  178.     JMP    OFDOS        ;Delete and return, dont care if fails
  179. ;
  180. CLSERR:    LXI    D,CLSERM
  181.     JMP    EXIT
  182. ;
  183. ;Read Huffman encoded character. 
  184. ;  Called with HL'=pointer, B'=bit count, C'=page count.
  185. ;  Returns with A=char, NZ set if eof, HL',B',C' updated, DE' clobbered.
  186. ;     If eof then A=0.
  187. GETERM:    DB    ' ** Bad SQ file: Missing EOF marker **',CR,LF,'$'
  188. ;
  189. HUFC:    EXX            ;Get alternate registers
  190.     XRA    A        ;Init tree offset
  191. ;
  192. HUFC0:    DJNZ    HUFC2
  193.     INR    L        ;New byte
  194.     JRNZ    HUFC1
  195.     INR    H        ;New page
  196.     DCR    C
  197.     JRNZ    HUFC1
  198.     PUSH    PSW        ;New bufferful
  199.     CALL    PIT
  200.     LXI    D,GETERM    ;Past EOF? (This doesnt catch all past-EOF
  201.     JC    FABT        ;errors, just those which try to go around the
  202.                 ;the buffer a 2nd time. Others will be caught
  203.                 ;by the checksum, presumably)
  204.     POP    PSW
  205. ;
  206. HUFC1:    MVI    B,8
  207. ;
  208. HUFC2:    PUSH    H        ;DE=Tree+4*A (The node address)
  209.     MOV    L,A
  210.     MVI    H,0
  211.     DAD    H
  212.     DAD    H
  213.     LXI    D,TREE
  214.     DAD    D
  215.     XCHG
  216.     POP    H
  217.     RRCR    M
  218.     JRNC    HUFC3        ;Want car, ok
  219.     INX    D        ;Else want cdr
  220.     INX    D
  221. ;
  222. HUFC3:  INX    D        ;high
  223.     LDAX    D
  224.     DCX    D
  225.     ORA    A
  226.     JRNZ    HUFC4        ;Leaf
  227.     LDAX    D
  228.     JR    HUFC0
  229. ;
  230. HUFC4:    INR    A        ;Set eof flag
  231.     LDAX    D        ;Get actual data
  232.     CMA
  233.     EXX            ;Back to regular regs
  234.     RET
  235. ;
  236. ;Filename Character Check. 
  237. ; Entered with character in A.
  238. ; Returns with NC if illegal, C if legal.  In latter case, Z if '.'
  239. ;  Character gets upcased.
  240. FCCHK:    ANI    7FH
  241.     CPI    ' '+1
  242.     CMC
  243.     RNC            ;space or less
  244.     CPI    '*'
  245.     RZ            ;*
  246.     CPI    ','
  247.     RZ            ;,
  248.     CPI    '.'
  249.     CMC
  250.     RZ            ;.
  251.     CPI    ':'
  252.     RC            ;Everything else before : is ok
  253.     CPI    '@'
  254.     CMC
  255.     RNC            ;:;<=>?
  256.     CPI    '['
  257.     RZ            ;[
  258.     CPI    ']'        ;]
  259.     RZ
  260.     CPI    'a'
  261.     RC            ;@,uppercase letters,\,^,_,` all ok
  262.     CPI    'z'+1
  263.     JRNC    FCCHK1
  264.     ADI    'A'-'a'        ;upcase setting carry
  265.     RET            ;cause we accept lowercase letters as ok
  266. ;
  267. FCCHK1:    CPI    7FH        ;Clear carry for rubout
  268.     RET            ;else {|} are ok.
  269. ;
  270. ;Fill Output Fcb.  
  271. ;  Called with filename pointer in DE, length in A.
  272. ;  Returns with everything clobbered, NC if error in filename, otherwise
  273. ;   OFCB has the name.
  274. OUTFCB:    LXI    H,OFCB+1    ;Fill with spaces
  275.     MVI    B,11
  276. ;
  277. OUTF0:    MVI    M,' '
  278.     INX    H
  279.     DJNZ    OUTF0
  280.     ORA    A
  281.     RZ            ;Too short
  282.     CPI    12+1
  283.     RNC            ;Too long
  284.     MOV    C,A        ;save
  285.     MOV    B,A
  286.     LXI    H,OFCB
  287. ;
  288. OUTF1:    INX    D
  289.     LDAX    D
  290.     CALL    FCCHK
  291.     RNC            ;Illegal char
  292.     JRNZ    OUTF2        ;Not '.', ok
  293.     ORA    A        ;Clear carry
  294.     DCR    C
  295.     RZ            ;Too short, or we are in file type already
  296.     MVI    C,1        ;Mark as being in file type
  297.     MOV    A,B
  298.     CPI    4+1
  299.     RNC            ;Type too long
  300.     LXI    H,OFCB+8
  301.     JR    OUTF3
  302. ;
  303. OUTF2:    INX    H
  304.     MOV    M,A
  305. ;
  306. OUTF3:    DJNZ    OUTF1
  307.     MOV    A,C
  308.     CPI    8+1
  309.     RET            ;Illegal if no . and more than 8 long
  310. ;
  311. ;Word move.
  312. ;  Called with source in DE, destination in HL, length in B.
  313. ;  Moves non-space characters.  DE & HL advanced, A,B clobbered.
  314. WMOVE:    LDAX    D
  315.     INX    D
  316.     ANI    7FH
  317.     CPI    ' '
  318.     JRZ    WMOVE1
  319.     MOV    M,A
  320.     INX    H
  321. ;
  322. WMOVE1:    DJNZ    WMOVE
  323.     RET
  324. ;
  325. ;Filename Type.
  326. ; Called with FCB in DE. Everything clobbered.
  327. NAMBUF:    DB    15        ;Buffer length
  328.     DS    1+15
  329. ;
  330. FTYPE:    LXI    H,NAMBUF+1
  331.     LDAX    D
  332.     INX    D
  333.     ORA    A
  334.     JRZ    FTYPE1        ;Default drive
  335.     ADI    'A'-1
  336.     MOV    M,A
  337.     INX    H
  338.     MVI    M,':'
  339.     INX    H
  340. ;
  341. FTYPE1:    MVI    B,8
  342.     CALL    WMOVE
  343.     MVI    M,'.'
  344.     INX    H
  345.     MVI    B,3
  346.     CALL    WMOVE
  347.     LXI    D,NAMBUF
  348.     STC
  349.     DSBC    D
  350.     MOV    A,L
  351.     XCHG
  352.     ;JP    ATYPE        ;(falls into ATYPE)
  353. ;
  354. ;Ascii Type.
  355. ;  Called with length in A, (back)pointer in HL.
  356. ;   Returns with everything clobbered.
  357. ATYPE:    ORA    A
  358.     RZ
  359.     MVI    C,CONOUT
  360.     MOV    B,A
  361. ;
  362. ATYPE0:    INX    H
  363.     MOV    E,M
  364.     PUSH    H
  365.     PUSH    B
  366.     CALL    BDOS
  367.     POP    B
  368.     POP    H
  369.     DJNZ    ATYPE0
  370.     RET
  371. ;
  372. ; Random little utilities.
  373. CRLFMSG:DB    CR,LF,'$'
  374. ;
  375. CRLF:    LXI    D,CRLFMSG
  376. PRINT:    MVI    C,PCS
  377. JBDOS:    IF    NOT EXXOS
  378.     JMP    BDOS
  379.     ENDIF
  380.     IF    EXXOS
  381. BDOS:    CALL    SAVEXX
  382.     CALL    XBDOS
  383. RETEXX:    CALL    RESEXX
  384.     RET
  385. ;
  386. SAVEXX:    EXX
  387.     XTHL
  388.     PUSH    D
  389.     PUSH    B
  390.     PUSH    H
  391. XXHL:    LXI    H,0
  392. XXDE:    LXI    D,0
  393. XXBC:    LXI    B,0
  394.     EXX
  395.     RET
  396. ;
  397. RESEXX:    EXX
  398.     SHLD    XXHL+1
  399.     SDED    XXDE+1
  400.     SBCD    XXBC+1
  401.     POP    H
  402.     POP    B
  403.     POP    D
  404.     XTHL
  405.     EXX
  406.     RET
  407. ;
  408.     ENDIF
  409. ;
  410. OFDOS:    LXI    D,OFCB
  411.     JR    JBDOS
  412. IFDOS:    LXI    D,IFCB
  413.     JR    JBDOS
  414. ;
  415. SDDMA:    LXI    D,DBUF
  416. SETDMA:    MVI    C,SDMA
  417.     JR    JBDOS
  418. ;
  419. ;Open Output File.
  420. ; Called with original name pointer in HL, length in A.
  421. ; Returns with everything clobbered, file open on OFCB.
  422. NEWMSG:    DB    '  Name to use instead ==> ','$'
  423. DELMSG:    DB    '  File exists, delete (Y/N)?:','$'
  424. DELERM: DB    ' ++ Cannot delete file. ++','$'
  425. MAKERM:    DB    ' ++ Cannot make file (dir full?) ++','$'
  426. ;
  427. OUTFIL:    PUSH    H
  428.     PUSH    PSW
  429.     CALL    ATYPE        ;Type original name
  430.     CALL    CRLF
  431.     POP    B
  432.     POP    D
  433.     LDA    FLAGS        ;TTY output?
  434.     RAL
  435.     RC            ;Then no file to get
  436.     MOV    A,B
  437. ;
  438. OUTNAM:    CALL    OUTFCB        ;Good name?
  439.     JRC    OUTDEL
  440. ;
  441. OUTNM1:    LXI    D,NEWMSG    ;Lost, ask him for a new one
  442.     CALL    PRINT
  443.     LXI    D,NAMBUF
  444.     MVI    C,RCS
  445.     CALL    BDOS
  446.     CALL    CRLF        ;Bdos only echos CR (sigh)
  447.     LXI    D,NAMBUF+1
  448.     LDAX    D
  449.     JR    OUTNAM        ;Try again
  450. ;
  451. OUTDEL:    CALL    SDDMA
  452.     XRA    A
  453.     STA    OFCB+FCB@CR
  454.     STA    OFCB+FCB@EX
  455.     MVI    C,SFF
  456.     CALL    OFDOS
  457.     INR    A
  458.     JRZ    OUTMAK
  459.     LXI    D,DELMSG
  460.     CALL    PRINT
  461.     MVI    C,CONIN
  462.     CALL    BDOS
  463.     PUSH    PSW
  464.     CALL    CRLF
  465.     POP    PSW
  466.     ORI    20H
  467.     CPI    'y'
  468.     JRNZ    OUTNM1
  469.     MVI    C,DELF
  470.     CALL    OFDOS
  471.     INR    A
  472.     JRZ    DELERR
  473. ;
  474. OUTMAK:    MVI    C,MAKEF
  475.     CALL    OFDOS
  476.     INR    A
  477.     LXI    H,FLAGS
  478.     SETB    FILFLG,M
  479.     RNZ
  480.     LXI    D,MAKERM
  481.     JR    JEXIT
  482. ;
  483. DELERR:    LXI    D,DELERM
  484. ;
  485. JEXIT:    JMP    EXIT
  486. ;
  487. ;Get tree Node.
  488. ;   Called with input pointer in HL, output in DE
  489. ;   Returns with HL,DE advanced, A,C clobbered
  490. ;    NC set if node out of range.
  491. GETNOD:    INX    H        ;Low
  492.     MOV    A,M
  493.     STAX    D
  494.     INX    D
  495.     MOV    C,A
  496.     INX    H        ;High
  497.     MOV    A,M
  498.     STAX    D
  499.     INX    D
  500.     INR    A        ;Make sure in -257 to 255 range
  501.     CPI    2
  502.     RC            ;High= FF or 00, always in range
  503.     INR    A
  504.     RNZ            ;Else high not FE is illegal
  505.     INR    C
  506.     RNZ            ;And anything but FEFF is illegal
  507.     STC
  508.     RET
  509. ;
  510. ;Unsqueeze a huffman encoded file.
  511. ; Called with file open on IFCB, drive field initialized in OFCB, OBuf set up.
  512. ORGMSG:    DB    ' ==> ','$'
  513. IDERM:    DB    'Not a SQ file',CR,LF,'$'
  514. FNMERM:    DB    '** Original filename way too long!',CR,LF,'$'
  515. NCTERM:    DB    '** Node count too large',CR,LF,'$'
  516. TREERM:    DB    '** Tree node not in -257:255 range',CR,LF,'$'
  517. CLSERM:    DB    ' ++ Cannot close file ++','$'
  518. CHKMSG:    DB    ' ** Warning: Checksum did not match **',CR,LF,'$'
  519. NOFMSG:    DB    ' (Empty output file, deleting)',CR,LF,'$'
  520. ;
  521. FABMSG:    DB    CR,LF,' ++++ File aborted ++++',CR,LF,'$'
  522. ;
  523. TREERR:    LXI    D,TREERM
  524.     ;JP    FABT        ;(falls into FABT)
  525. ;
  526. FABT:    CALL    FLUSH        ;Flush output file if any
  527.     ;JP    NXTF        ;(falls into NXTF)
  528. ;
  529. NXTF:    LXI    SP,STACK    ;Reset stack
  530.     MVI    C,CLOSF        ;This is probably not needed but..
  531.     CALL    IFDOS        ; close old input file anyhow
  532.     LXI    H,IFCB+1    ;Reset search context
  533.     LXI    D,DFCB+1
  534.     LXI    B,11
  535.     LDIR
  536.     CALL    SDDMA
  537.     XRA    A
  538.     STA    DFCB+FCB@CR
  539.     STA    DFCB+FCB@EX
  540.     MVI    C,SFF
  541.     LXI    D,DFCB
  542.     CALL    BDOS
  543.     LXI    H,REQNAM    ;Put back wildcard name
  544.     LXI    D,DFCB
  545.     LXI    B,12
  546.     LDIR
  547. ;
  548. NXTF0:    MVI    C,SFN        ;Find next file
  549. ;
  550. FIRSTF:    CALL    BDOS        ;Enter here for first time around
  551.     INR    A
  552.     JZ    FINISH
  553.     DCR    A        ;Get a pointer to filename
  554.     RRC
  555.     RRC
  556.     RRC
  557.     MOV    L,A
  558.     MVI    H,0
  559.     LXI    D,DBUF+1
  560.     DAD    D
  561.     LDA    REQNAM        ;Get original drive
  562.     LXI    D,IFCB
  563.     STAX    D
  564.     INX    D        ;Move found filename to the input FCB
  565.     LXI    B,11
  566.     LDIR
  567.     LDA    IFCB+10
  568.     RAL
  569.     JRC    NXTF0        ;SYS file, try again
  570.     LHLD    FCOUNT        ;Have file, update count
  571.     INX    H
  572.     SHLD    FCOUNT
  573.     XRA    A
  574.     STA    IFCB+FCB@CR
  575.     STA    IFCB+FCB@EX
  576.     STA    IOSB        ;Init IOSB
  577. ;
  578.     IF    TABEX
  579.     STA    COLUMN        ;Current column
  580.     ENDIF
  581. ;
  582.     LXI    H,FLAGS        ;Reset all but ttyflg (flsflg,filflg,eofflg)
  583.     MOV    A,M
  584.     ANI    1 SHL TTYFLG
  585.     MOV    M,A
  586.     MVI    C,OPENF        ;Open the file
  587.     CALL    IFDOS
  588.     INR    A
  589.     LXI    D,OPNERM
  590.     JZ    EXIT
  591. ;
  592. ; Input file is open, flags, iosb initialized.
  593. ;
  594.     LXI    D,IFCB        ;Say 'Filename ==> '
  595.     CALL    FTYPE
  596.     LXI    D,ORGMSG
  597.     CALL    PRINT
  598.     LXI    H,0FEFFH    ;Init tree in case no nodes
  599.     SHLD    TREE
  600.     SHLD    TREE+2
  601.     MVI    H,IBUF+1    ;Read in a page to start with
  602.     CALL    PIT
  603.     MOV    A,M        ;1st ID byte
  604.     CPI    ID1
  605.     LXI    D,IDERM
  606.     JRNZ    JFABT        ;Not a SQ file
  607.     INX    H        ;2nd ID byte
  608.     MOV    A,M
  609.     CPI    ID2
  610. ;
  611. JFABT:    JNZ    FABT        ;Not a SQ file
  612. ;
  613. ; File starts with proper SQ header.
  614. ;
  615. UNSQF:    INX    H        ;Checksum
  616.     MOV    E,M
  617.     INX    H
  618.     MOV    D,M
  619.     SDED    CHKSUM
  620.     PUSH    H        ;Save filename pointer
  621.     MVI    B,250        ;(Can't be more than 250, only read in a page)
  622.     MOV    C,B
  623. ;
  624. FNM:    INX    H
  625.     MOV    A,M
  626.     ORA    A
  627.     JRZ    FNM1
  628.     DJNZ    FNM
  629.     LXI    D,FNMERM
  630.     JMP    FABT        ;Name way to long, give up
  631. ;
  632. FNM1:    MOV    A,C
  633.     SUB    B        ;A=length of name
  634.     PUSH    PSW        ; Save it
  635.     PUSH    H        ;Get more file
  636.     MVI    A,IBUF+1
  637.     MVI    H,IBUF+5
  638.     CALL    PIT1
  639.     POP    H
  640.     INX    H        ;Number of nodes
  641.     MOV    B,M        ;Low
  642.     INX    H
  643.     MOV    A,M        ;High
  644.     LXI    D,TREE
  645.     ORA    A
  646.     JRZ    TREE0        ;Less than 100h, ok
  647.     DCR    A        ;Else better be exactly 100h
  648.     ORA    B
  649.     JRZ    TREE1
  650.     LXI    D,NCTERM    ;Bad node count
  651.     JMP    FABT
  652. ;
  653. TREE0:    ORA    B
  654.     JRZ    BUFS        ;Skip loop if exactly 0
  655. ;
  656. TREE1:    CALL    GETNOD        ;Car
  657. ;
  658. JTREER:    JNC    TREERR
  659.     CALL    GETNOD        ;Cdr
  660.     JRNC    JTREER
  661.     DJNZ    TREE1
  662. ;
  663. ; Have read in filename, checksum, tree, everything looks ok.
  664. ; Filename pointer and length are on stack
  665. BUFS:    PUSH    H        ;Fill rest of buffer
  666.     LDA    OBUF
  667.     MOV    H,A
  668.     MVI    A,IBUF+5
  669.     CALL    PIT1
  670.     POP    H
  671.     POP    PSW        ;Get back length
  672.     XTHL            ;get back start pointer
  673.     CALL    OUTFIL        ;Get us a file
  674.     POP    H
  675.     LDA    OBUF        ;Init input setup
  676.     SUB    H
  677.     MOV    C,A
  678.     MVI    B,1
  679.     ADD    H        ;Restore to (obuf) for below
  680.     EXX            ;And put it away
  681.     DCR    A        ;Init output setup
  682.     MOV    H,A
  683.     MVI    L,0FFH
  684.     LDA    XBDOS+2
  685.     SUI    8+1        ;2K for ccp
  686.     SUB    H
  687.     MOV    D,A
  688. ;
  689. ; All set up, do it!
  690. ;
  691.     JR    HUFF        ;Jump into loop
  692. ;
  693. HUFF0:    MVI    A,DLE
  694. ;
  695. HUFF1:    MOV    C,A        ;Save
  696.     CALL    PUTC
  697. ;
  698. HUFF:    CALL    HUFC
  699.     JRNZ    FILL        ;Eof, done
  700.     CPI    DLE
  701.     JRNZ    HUFF1
  702.     CALL    HUFC
  703.     JRNZ    HUFF2        ;Got end of file, A=00h but means 100h
  704.     ORA    A
  705.     JRZ    HUFF0        ;0 repeat count means real DLE
  706. ;
  707. HUFF2:    DCR    A        ;Account for one we already did before DLE
  708.     JRZ    HUFF        ;Hmm...
  709.     MOV    B,A
  710. ;
  711. HUFF3:    CALL    PUTC
  712.     DJNZ    HUFF3
  713.     JR    HUFF
  714. ;
  715. FILL:    LDA    FLAGS
  716.     RAL            ;TTY output?
  717.     JRC    CHKCHK        ;Nothing to save then
  718.     MOV    A,L        ;Round off sector with ^Zs
  719.     CMA
  720.     ANI    7FH
  721.     JRZ    SAVE
  722. ;
  723. FILL1:    INX    H
  724.     MVI    M,'Z'-'@'
  725.     DCR    A
  726.     JRNZ    FILL1
  727. ;
  728. SAVE:    INX    H
  729.     LDA    OBUF
  730.     SUB    H
  731.     ORA    L
  732.     PUSH    PSW        ;Remeber if had no output
  733.     JRZ    CLOSE        ;and skip saving
  734.     PUSH    H
  735.     CALL    POT
  736.     POP    H
  737.     JRNZ    OUTERR
  738.     SLAR    L
  739.     JRNC    CLOSE
  740.     LXI    D,OFCB        ;Output orphan sector
  741.     XCHG
  742.     MVI    A,WSS
  743.     CALL    IOT
  744.     JRNZ    OUTERR
  745. ;
  746. CLOSE:    MVI    C,CLOSF        ;Close the file
  747.     CALL    OFDOS
  748.     INR    A
  749.     JZ    CLSERR
  750.     POP    PSW        ;Get back data flag in Z
  751.     JRNZ    CHKCHK        ;Had data, ok
  752.     LXI    D,NOFMSG    ;Else tell him
  753.     CALL    PRINT
  754.     MVI    C,DELF        ;and flush empty file
  755.     CALL    OFDOS
  756. ;
  757. CHKCHK:    LHLD    CHKSUM        ;Check checksum
  758.     LXI    D,CHKMSG
  759.     MOV    A,H
  760.     ORA    L
  761.     CNZ    PRINT        ;Print warning but keep file anyway.
  762.     JMP    NXTF        ;And do it again
  763. ;
  764. OUTMSG:    DB    ' ++ Error writing sector (disk full?) ++','$'
  765. ;
  766. OUTERR: LXI    D,OUTMSG
  767. ;
  768. QUIT:    CALL    FLUSH
  769.     JMP    DONE
  770. ;
  771. ;Put character.
  772. ; Called with character in C, pointer in HL, page count in D.
  773. ; Returns with HL,D updated, A and E clobbered, BC preserved.
  774. ; If TTYFLG is on, HL,D are ignored and clobbered as well.
  775. PUTC:    PUSH    B
  776.     PUSH    H
  777.     LHLD    CHKSUM
  778.     XRA    A
  779.     MOV    B,A
  780.     DSBC    B
  781.     SHLD    CHKSUM
  782.     PUSH    D
  783.     CALL    CONCHK        ;Had enough?
  784.     POP    D
  785.     POP    H
  786.     LDA    FLAGS
  787.     RAL
  788.     JRC    TPUTC        ;Do TTY output
  789.     INR    L
  790.     JRNZ    PUTC1
  791.     INR    H        ;Another page
  792.     DCR    D
  793.     JRNZ    PUTC1
  794.     CALL    POT
  795.     JRNZ    OUTERR
  796.     MOV    D,C
  797. ;
  798. PUTC1:    POP    B
  799.     MOV    M,C
  800.     RET
  801. ;
  802. TPUTC:    RAL            ;flsflg?
  803.     JRC    TPUTCX
  804.     RAL            ;eofflg?
  805.     JRC    TPUTCX
  806.     MOV    A,C
  807.     POP    B
  808.     CPI    'Z'-'@'
  809.     JRNZ    TPUTCC
  810.     LXI    H,FLAGS
  811.     SETB    EOFFLG,M
  812.     RET
  813. ;
  814. TPUTCC:    ANI    7FH
  815.     CPI    '['-'@'
  816.     JRNZ    TPUTC1
  817.     MVI    A,'$'
  818. ;
  819. TPUTC1:    PUSH    B
  820.     CPI    'G'-'@'
  821.     JRZ    BPUTC
  822.     CPI    'J'-'@'
  823.     JZ    BPUTC
  824. ;
  825. TPUTC3:    IF    TABEX
  826.     LXI    H,COLUMN
  827.     ENDIF
  828. ;
  829.     CPI    'I'-'@'
  830.     JRZ    TPUTT
  831.     CPI    'L'-'@'
  832.     JRZ    TPUTC0
  833.     CPI    'M'-'@'
  834.     JRZ    TPUTC0
  835.     CPI    7FH
  836.     JRZ    TPUTC2
  837.     CPI    ' '
  838.     JRC    TPUTC2
  839. ;
  840.     IF    TABEX
  841.     INR    M
  842.     ENDIF
  843. ;
  844. BPUTC:    MOV    C,A
  845. ;
  846.     IF    EXXOS
  847.     CALL    SAVEXX
  848.     ENDIF
  849. BPUTC1:    CALL    0        ;CONOUT through bios
  850.     IF    EXXOS
  851.     CALL    RESEXX
  852.     ENDIF
  853. ;
  854. TPUTCX:    POP    B
  855.     RET
  856. ;
  857. TPUTC2:    MOV    B,A        ;Save char
  858.     MVI    A,'^'        ;Output ^
  859.     CALL    TPUTCC
  860.     MOV    A,B        ;Now output decontrolified char
  861.     XRI    40H
  862.     JR    TPUTC3
  863. ;
  864.     IF    TABEX
  865. TPUTC0:    MVI    M,0
  866.     JR    BPUTC
  867. ;
  868. TPUTT:    MOV    A,M        ;Print a tab. HL points to column.
  869.     CMA
  870.     ANI    7
  871.     INR    A
  872.     MOV    B,A
  873. ;
  874. TPUTT1:    MVI    A,' '
  875.     CALL    TPUTCC
  876.     DJNZ    TPUTT1
  877.     JR    TPUTCX
  878.     ENDIF
  879. ;
  880.     IF    NOT TABEX
  881. TPUTC0    EQU    BPUTC
  882. TPUTT    EQU    BPUTC
  883.     ENDIF
  884. ;
  885. ;Check console for control characters.
  886. ;All regs clobbered.
  887. ;
  888. ABTMSG:    DB    ' ++ Aborted ++','$'
  889. ;
  890. CONCHK:    IF    EXXOS
  891.     CALL    SAVEXX
  892.     ENDIF
  893. CONCK1:    CALL    0        ;CONST through bios
  894.     ORA    A
  895. BGETC1:    CNZ    0        ;CONIN through bios
  896.     LXI    H,FLAGS
  897.     BIT    TTYFLG,M    ;Are we outputting to the TTY
  898.     JRZ    CONCH1        ;If not, dont check for ^S/^O
  899.     PUSH    H
  900.     CPI    'S'-'@'        ;^S=pause until character typed
  901. BGETC2:    CZ    0        ; CONIN through bios
  902.     POP    H
  903.     CPI    'O'-'@'        ;^O=toggle flush flag
  904.     JRNZ    CONCH1
  905.     MOV    A,M
  906.     XRI    1 SHL FLSFLG
  907.     MOV    M,A
  908.     IF    NOT EXXOS
  909.     RET
  910.     ENDIF
  911.     IF    EXXOS
  912.     JMP    RETEXX
  913.     ENDIF
  914. ;
  915. CONCH1:    IF    EXXOS
  916.     CALL    RESEXX
  917.     ENDIF
  918.     CPI    'C'-'@'        ;^C means abort
  919.     LXI    D,ABTMSG
  920.     JZ    QUIT
  921.     CPI    'X'-'@'        ;^X means abort current file
  922.     LXI    D,FABMSG
  923.     JZ    FABT
  924.     RET
  925. ;
  926. OPNERM:    DB    ' ++ Cannot open file ++','$'
  927. ;
  928. FINISH:    LHLD    FCOUNT
  929.     MOV    A,H
  930.     ORA    L
  931.     JRNZ    DONE
  932.     LXI    D,NOPERM    ;Complain that didn't find any files
  933. ;
  934. EXIT:    CALL    PRINT        ;Print reason
  935. ;
  936. DONE:    LSPD    STACK
  937.     RET
  938. ;
  939. ;Storage which doesn't require initialization, don't bother putting
  940. ;in COM file...
  941. TREE    EQU    $        ;The huffman code tree
  942. IOSB    EQU    TREE+(4*256)    ;I/O status byte, saved on error in IOT
  943. ;
  944.     IF    TABEX
  945. COLUMN    EQU    IOSB+1        ;Current output column, for tab expansion
  946.     ENDIF
  947. ;
  948.     IF    NOT TABEX
  949. COLUMN    EQU    IOSB
  950.     ENDIF
  951. ;
  952. FLAGS    EQU    COLUMN+1
  953. FCOUNT    EQU    FLAGS+1        ;Number of files looked at all together.
  954. OFCB    EQU    FCOUNT+2    ;Output FCB
  955. IFCB    EQU    OFCB+33        ;Input FCB
  956. REQNAM    EQU    IFCB+33        ;Requested name, wildcards and all
  957. TOS    EQU    REQNAM+12    ;Top of stack area
  958. STACK    EQU    TOS+(2*25)    ;Saved SP
  959. PGMEND    EQU    STACK+2        ;That's all folks
  960. ;
  961. IBUF    EQU    (PGMEND+0FFH) SHR 8    ;Input buffer page
  962. ;
  963. ;Initialization code -- should be under 1K so fits under Tree memory
  964. ;
  965. NOPERM:    DB    ' ++ File not found ++','$'
  966. ;
  967. HLPMSG:    DB    'UNSQ inputfile [ outputdrive: ]',CR,LF
  968.     DB    'Unsqueezes files created with SQ. Input '
  969.     DB    'filename may be ambiguous.'
  970.     DB    CR,LF,'Any matching non-SQ files will be ignored.'
  971.     DB    CR,LF,CR,LF,'UNSQ inputfile T'
  972.     DB    CR,LF,'Unsqueezes files and types them out on the console.'
  973.     DB    CR,LF,'^S pauses output, ^O toggles output on/off.'
  974.     DB    CR,LF,CR,LF,'In either form, ^C aborts, ^X skips to next file'
  975.     DB    '$'
  976. ;
  977. INIT:    LXI    H,0        ;Establish local stack and save old one
  978.     SHLD    FCOUNT        ; (Init count while have a 0 in hl...)
  979.     DAD    SP
  980.     LXI    SP,STACK+2
  981.     PUSH    H
  982.     IF    EXXOS
  983.     EXX
  984.     SHLD    XXHL+1        ;Save OS alternate registers
  985.     SDED    XXDE+1
  986.     SBCD    XXBC+1
  987.     EXX
  988.     ENDIF
  989.     LHLD    BASE+1        ;Init BIOS routines
  990.     LXI    D,3
  991.     DAD    D
  992.     SHLD    CONCK1+1
  993.     DAD    D
  994.     SHLD    BGETC1+1
  995.     SHLD    BGETC2+1
  996.     DAD    D
  997.     SHLD    BPUTC1+1
  998.     XRA    A
  999.     LXI    H,FLAGS
  1000.     MOV    M,A
  1001.     LXI    D,HLPMSG    ;Prepare to give help at the drop of a hat
  1002.     LDA    DFCB+1        ;Anything there?
  1003.     CPI    ' '
  1004.     JZ    EXIT
  1005.     LDA    DFCB2+1        ;Output filename is flags (sigh)
  1006.     CPI    ' '
  1007.     JRZ    INIT1
  1008.     CPI    'T'
  1009.     JNZ    EXIT
  1010.     SETB    TTYFLG,M    ;TTY output:
  1011.     LDA    XBDOS+2        ;Use everything for input buffer...
  1012.     SUI    8+1
  1013.     STA    OBUF
  1014.     JR    INIT2
  1015. ;
  1016. INIT1:    LDA    DFCB2        ;Save the output drive
  1017.     STA    OFCB
  1018.     LDA    XBDOS+2        ;Establish buffer boundary
  1019.     SUI    8+1+IBUF    ;with input buffer about 60% of the output
  1020.     SRLR    A
  1021.     SRLR    A
  1022.     MOV    B,A
  1023.     SRLR    A
  1024.     ADD    B
  1025.     ADI    IBUF
  1026.     STA    OBUF
  1027. ;
  1028. INIT2:    LXI    H,DFCB        ;Save the input filename for future searches
  1029.     LXI    D,REQNAM
  1030.     LXI    B,12
  1031.     LDIR
  1032.     XRA    A        ;Find the first input file
  1033.     STA    DFCB+FCB@EX
  1034.     STA    DFCB+FCB@CR
  1035.     MVI    C,SFF
  1036.     LXI    D,DFCB
  1037.     JMP    FIRSTF
  1038. ;
  1039.     END
  1040.