home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ZSYS / SIMTEL20 / ZSIG / UF.LBR / UF.ZZ0 / UF.Z80
Text File  |  2000-06-30  |  27KB  |  948 lines

  1. ; **********************************************************************
  2. ; *                                       *
  3. ; *            Fast Z80 Unsqueezer                   *
  4. ; *            First ZCPR3 Version                   *
  5. ; *              1.0, 7/1/86, by                   *
  6. ; *               Bruce Morgen,                   *
  7. ; *               derived from                    *
  8. ; *             v1.9 2 April 1986                   *
  9. ; *            and v2.0 June 1986                   *
  10. ; *    Original version and algorithm by Steven Greenberg, 1/10/86    *
  11. ; *                                       *
  12. ; **********************************************************************
  13.  
  14. ; Opcode equates
  15.  
  16. JPOP    EQU    0C3H        ; Opcode for "JP" instruction
  17.  
  18. ; ASCII equates
  19.  
  20. CR    EQU    0DH
  21. LF    EQU    0AH
  22.  
  23. ; CP/M address equates
  24.  
  25. DFCB    EQU    5CH        ; Default file control block
  26. DFCB2    EQU    6CH        ; Secondary DFCB
  27. DDMA    EQU    80H        ; Default DMA address
  28. CPM    EQU    0000H        ; Warm boot jump address
  29. BDOS    EQU    0005H        ; BDOS entry point
  30. TPA    EQU    0100H        ; Transient execution call address
  31. ; BDOS function equates
  32.  
  33. CONOUT    EQU    2        ; Print character to console
  34. PRTSTR    EQU    9        ; Print string to console
  35. OPEN    EQU    15        ; Open file
  36. CLOSE    EQU    16        ; Close file
  37. ERASE    EQU    19        ; Erase file
  38. READ    EQU    20        ; Read file (sequential)
  39. WRITE    EQU    21        ; Write file (sequential)
  40. MAKE    EQU    22        ; Make file
  41. GCURDK    EQU    25        ; Get default disk drive
  42. SETDMA    EQU    26        ; Set dma address
  43. GSUSER    EQU    32        ; Get/set user area
  44.  
  45. ;-----------------------------------------------------------------------
  46.     ORG    TPA
  47.  
  48. ENTRY:    JP    START
  49. OUTUSR:    DB    0
  50. INUSR:    DB    0
  51. OLDSTK:    DB    'Copyright (c) Steven Greenberg 1/10/86,201-670-8724,'
  52.     DB    'reproduce for non-profit only!'
  53.  
  54. START:    LD    A,7FH
  55.     ADD    A,A
  56.     JP    PE,Z80
  57.     LD    DE,WRNGUP    ; "Program requires Z80 processor"
  58.     JP    MESS80        ; Non-Z80s: print up and go home
  59.  
  60. Z80:    LD    (OLDSTK),SP    ; Save OS's stack
  61.     LD    SP,START    ; Set local stack
  62.     LD    A,(BDOS+2)    ; Size up the TPA
  63.     SUB    EOBFHI+10    ; (includes 2k for the ccp)
  64.     JR    NC,ENOUGH
  65.     LD    DE,LAKMEM    ; "not enough memory..."
  66.     JP    FATAL        ; (fatal error)
  67.  
  68. ENOUGH:    LD    DE,LOGO        ; Version#, etc
  69.     CALL    MESAGE
  70.     LD    A,(DFCB+1)
  71.     CP    '/'
  72.     JR    NZ,NOTHLP
  73.     LD    DE,HLPMSG
  74.     JP    FATAL
  75. NOTHLP:    LD    A,(DFCB2)
  76.     LD    (OFCB),A
  77.     LD    A,(DFCB2+13)
  78.     LD    (OUTUSR),A
  79.     LD    A,(DFCB+13)
  80.     LD    (INUSR),A
  81.     LD    E,A
  82.     LD    C,GSUSER
  83.     CALL    BDOS
  84.     LD    A,'Q'        ; Force .?Q?
  85.     LD    (DFCB+10),A
  86.     LD    DE,DFCB        ; Point to specified file
  87.     LD    HL,FNBUFF    ; And to filename buffer
  88.     CALL    WILDEX        ; Do wildcard expansion
  89.     LD    (NMBFLS),HL    ; Save number of matching files
  90.     JR    Z,WERR        ; Get out if error
  91.  
  92.     LD    DE,MAXFLS    ; Check if too many matching files
  93.     AND    A        ; Clear carry
  94.     SBC    HL,DE
  95.     JR    NC,TOOMNY
  96.  
  97.     LD    HL,FNBUFF    ; Get name buffer
  98.     LD    (BUFPTR),HL    ; Set up buffer pointer
  99.  
  100. ;-----------------------------------------------------------------------
  101.  
  102. ; Come here for each new file
  103.  
  104. NXTFIL:    XOR    A
  105.     LD    (EOFLAG),A
  106.     LD    A,(INUSR)
  107.     LD    E,A
  108.     LD    C,GSUSER
  109.     CALL    BDOSAV
  110.     LD    DE,DFCB+1    ; Clean input FCB
  111.     PUSH    DE
  112.     CALL    ZERFCB
  113.     LD    HL,(BUFPTR)
  114.     POP    DE
  115.     PUSH    HL        ; Save filepointer
  116.     LD    BC,11        ; 11 characters
  117.     INC    HL
  118.     LDIR            ; Move next filename in place
  119.     LD    DE,OFCB+1
  120.     CALL    ZERFCB        ; Clean output FCB
  121.     POP    HL
  122.     LD    DE,16        ; Offset to next filename
  123.     ADD    HL,DE
  124.     LD    (BUFPTR),HL
  125.     LD    DE,DFCB
  126.     LD    C,OPEN
  127.     CALL    BDOSAV
  128.     INC    A
  129.     JR    NZ,PRIN        ; Branch if successful
  130.  
  131. WERR:    LD    DE,ERR1        ; Else, "Input file not found"
  132.     JP    FATAL
  133.  
  134. TOOMNY:    LD    DE,ERR3        ; "Too many matching files"
  135.     JP    FATAL
  136.  
  137. PRIN:    LD    DE,CRLF
  138.     CALL    PRINT
  139.     LD    HL,DFCB
  140.     LD    A,(HL)
  141.     DEC    A
  142.     CP    0FFH
  143.     JR    NZ,GOTDSK
  144.     LD    C,GCURDK
  145.     CALL    BDOSAV
  146. GOTDSK:    LD    B,A
  147.     LD    A,(INUSR)
  148.     LD    C,A
  149.     CALL    PRNDU
  150.     INC    HL
  151.     CALL    PRNFIL
  152.  
  153. ; Before going too much further, take this opportunity to "clone" a
  154. ; 16 byte template of code into memory 256 times.  This forms the
  155. ; skeleton for the compiled block of code "CODTBL".  Various specific
  156. ; instructions and data will overwrite sections of this template after
  157. ; the dictionary info is read.
  158.  
  159. CLONE:    LD    HL,TMPLAT    ; Xfer one copy to the beg of "CODTBL"
  160.     LD    DE,CODTBL
  161.     LD    BC,16
  162.     LDIR
  163.     LD    HL,CODTBL    ; Now copy it 255 more times.
  164.     LD    BC,255*16    ; De already points to "CODTBL+16"
  165.     LDIR            ; That does it
  166.  
  167. ; Now load up the input buffer.  The input buffer, the output buffer,
  168. ; and "CODTBL" are all page aligned and of page multiple lengths.  There
  169. ; are no other criteria for the lengths of the 2 buffers, except that the
  170. ; input buffer should have a minimum length of 2K plus 1 more page. This
  171. ; guarantees that the entire dictionary (plus miscellaneous header info)
  172. ; will be read in on the 1st pass, simplifying the program.
  173.  
  174.     CALL    RELOAD        ; "reload" leaves HL pointing to
  175.     XOR    A
  176.     LD    (EOFLAG),A
  177.     LD    A,(HL)        ; The beginning of "IBUF"
  178.     CP    76H        ; Check for "Squeezed File Header" 76h,ffh
  179.     JR    NZ,NTSQZD    ; Br if not a squeezed file
  180.     INC    L        ; Note buffer starts on a page boundary
  181.     INC    (HL)        ; Chk for FF [clobber it along the way]
  182.  
  183. NTSQZD:    LD    DE,NSQMSG    ; Meanwhile , prep for poss err msg
  184.     JP    NZ,FATAL    ; Fatal "not squeezed" condition
  185.     LD    DE,ARROW    ; " --->"
  186.     CALL    PRINT        ; Ok, print an arrow
  187.     LD    A,(OUTUSR)
  188.     LD    E,A
  189.     PUSH    DE
  190.     LD    C,GSUSER
  191.     CALL    BDOSAV
  192.     LD    A,(OFCB)
  193.     DEC    A
  194.     CP    0FFH
  195.     JR    NZ,GOTDRV
  196.     LD    C,GCURDK
  197.     CALL    BDOSAV
  198. GOTDRV:    POP    BC
  199.     LD    B,A
  200.     CALL    PRNDU
  201.     LD    HL,(IBUF+2)    ; Get the 16 bit checksum and save
  202.     LD    (CHKSUM),HL    ; Goes there
  203.     LD    HL,IBUF+3    ; Init pointer past 76FF and 2 byte
  204.                 ;  checksum (-1)
  205.     LD    DE,OFCB+1    ; Init pointer to filename of output fcb
  206.     LD    B,11
  207.  
  208. EATLP:    INC    L        ; Filename << 256 chars
  209.     LD    A,(HL)        ; Eat up the file name
  210.     OR    A        ; A zero byte indicates end of filename
  211.     JR    Z,ATEIT        ; Branch when that is encountered
  212.     AND    7FH        ; Strip off any "attribits"
  213.     CALL    UCASE
  214.     CP    '.'        ; Check for name / ext division character
  215.     JR    Z,ISDOT        ; Branch when encountered
  216.     LD    (DE),A        ; Else copy filename char to output FCB
  217.     INC    DE        ; And increment that pointer
  218.     DJNZ    EATLP        ; Continue, but not past filename area of FCB
  219.  
  220.     INC    HL        ; Once more (position should have a null)
  221.     JR    ATEIT        ; We're really done now
  222.  
  223. ; When "." is encountered, skip to the file extension bytes of the output
  224. ; FCB.    (Any remaining non-extension bytes were init'd to blank).  Do not
  225. ; copy the "." to the output FCB.
  226.  
  227. ISDOT:    LD    DE,OFCB+9    ; Skip...
  228.     LD    B,3
  229.     JR    EATLP        ; And continue
  230.  
  231. ATEIT:    PUSH    HL
  232.     LD    HL,OFCB+1
  233.     CALL    PRNFIL
  234.     POP    HL
  235.  
  236.     LD    DE,OFCB        ; Output fcb
  237.     LD    C,ERASE        ; "blind erase" the dest file if it exists
  238.     CALL    BDOSAV        ; (*** implement a prompt here? ***)
  239.     LD    C,MAKE        ; In any case, make the new file
  240.     CALL    BDOSAV
  241.     INC    A
  242.     JR    NZ,MAKTBL    ; Err cond check
  243.     LD    DE,ERR2        ; "file open error"
  244.     JP    FATAL        ; Exit
  245.  
  246. ;  Now    create    "CODTBL"  by overwriting  certain sections  of  the
  247. ; template  created above.  The dictionary contains 4  byte  nodes-
  248. ; these  are  converted into 16 byte  code segments.   The  maximum
  249. ; length  of the original dictionary is (257*4) bytes or  about  2K
  250. ; corresponding to a maximum "CODTBL" length of 8K.
  251. ;
  252. ;    NODE DEFINITION:  As mentioned above, a "node" consists of two
  253. ; pairs  of bytes.  The first pair corresponds to a zero  bit,    the
  254. ; latter  to a "1".  To decode a character, we start at node #0.  A
  255. ; bit is pulled off the bit stream. We then use the 1st or 2nd byte
  256. ; pair    depending on the bit value.  The byte pair takes on 1 of  2
  257. ; forms  "nn FF" or "xx 0x".  The "nn FF" type is a terminal  node,
  258. ; it means we have our next output value - that value  specifically
  259. ; being  the 1's complement (makes it more mysterious) of "nn".  If
  260. ; the  node is of the second type, it is a pointer to another  node
  261. ; (an  absolute offset from the beg of the dictionary in  terms  of
  262. ; node#, must be multiplied by 4 for a byte offset.  It has a  max-
  263. ; imum    value  of  513, and is expressed as  a    16-bit    #,  lo-byte
  264. ; first).   In this case we go to that node, pull another  bit    off
  265. ; the input stream, and continue the process.
  266. ;
  267. ;    There  is actually a 3rd node type, which just comes up  once.
  268. ; Its  form is "FF FE".  It's a special end-of-file  marker  called
  269. ; "SPEOF".
  270. ;
  271. ;    HOW THE PROGRAM WORKS:  Each node is converted into a  16-byte
  272. ; (actually  13  plus 3 nop's) series of instructions.     These    in-
  273. ; structions  later perform the unsqueezing operation.     The  whole
  274. ; block of code starts at "CODTBL" (which is also the  entrypoint).
  275. ; Each 13 byte "node code" consists of a 7 byte header.  The header
  276. ; shifts out the next bit from reg "b", then conditionally branches
  277. ; to  the first or second half of the remaining code (3  bytes    per
  278. ; half;  7+3+3    = 13).    The 3 bytes in each half are either  the  2
  279. ; instructions "LD A,<byte>"  followed by "RET" (terminal node)  or
  280. ; the  single  instruction "JP <nxtnode>".  All calls  to  "CODTBL"
  281. ; eventually hit  a terminal node and perform a normal return.    The
  282. ; only exception is the special end-of-file node which compiles  to
  283. ; "JP  SPEOF"; on this particular return the stack is manually    ad-
  284. ; justed to compensate for the lack of a "RET" instruction.
  285. ;
  286. ; THE TEMPLATE: This is the "template" which was "cloned" earlier
  287. ;
  288. ;    The  following 3 instructions form the header code  for  every
  289. ; node.  They are identical for every node (since the jump is  rel-
  290. ; ative).
  291.  
  292. TMPLAT:    SRL    B        ; Shift out next bit
  293.     CALL    Z,REFILL    ; Refill reg when empty
  294.     JR    C,BITIS1    ; If bit is "1"
  295.  
  296. ;    After  the header code gets executed, one of 2 halves  of    the
  297. ; remainder  of the node gets executed.  Which half depends on    the
  298. ; bit shifted out above ("0" for the first half, "1" for the  2nd).
  299. ; Each    half-node has two possible forms.  The terminal form  loads
  300. ; an appropriate value and returns.  The non-terminal form jumps to
  301. ; the  header  of another node. This 16-byte  "node-code  template"
  302. ; assumes  the former case by default, since 2 of 3 bytes  in  that
  303. ; case    are fixed (only the value need be in-serted).  If it  turns
  304. ; out to be the latter case, all 3 bytes will be overwritten with a
  305. ; "jmp" opcode plus an appropriate address.
  306.  
  307. BITIS0:    LD    A,00H        ; (00h gets replaced with actual value
  308.     RET            ; To be returned.)
  309.  
  310. BITIS1:    LD    A,00H        ; 2nd half of the node, likewise
  311.     RET
  312.  
  313.     NOP
  314.     NOP            ; So the template is exactly 16 bytes
  315.     NOP
  316.  
  317. ; Create the "node code" table
  318.  
  319. MAKTBL:    INC    L        ; Now points one past the filename eof
  320.     LD    E,(HL)        ; Get #of nodes (lo byte)
  321.     INC    L
  322.     LD    D,(HL)        ; Hi byte of same
  323.     INC    L
  324.     LD    A,D
  325.  
  326. ; An additional file validity check: though the #of nodes could in theory
  327. ; theory as high as 0201H or so, it should never approach 0300H or higher.
  328.  
  329.     SUB    2;3        ; If this happens, assume it is not a
  330.     JP    NC,NTSQZD    ; Squeezed file.
  331.  
  332. ; HL indexes through source dictionary (already initialized), & HL' is
  333. ; current dest pointer (indexes thru "codtbl").  DE is initialized to the
  334. ; # of nodes and is decreased to 0.
  335.  
  336.     EXX            ; Init some constants
  337.     LD    DE,10        ; Used for incrementing hl'
  338.     LD    HL,CODTBL+7    ; Init hl' itself
  339.     EXX
  340.  
  341. ; Remember, the whole "header" code and some other instructions are already
  342. ; there (from when "template" was duplicated).    Only specific details need
  343. ; now be filled in.
  344.  
  345. NODELP:    CALL    MAKHAF        ; Make the first ("0") half-node
  346.     CALL    MAKHAF        ; 2nd ("1") half-node
  347.  
  348. ; Source pointer has already been incremented 4 times, as desired. Dest
  349. ; pointer has only been incremented 6 times, however.
  350.  
  351.     EXX
  352.     ADD    HL,DE        ; So take care of that
  353.     EXX
  354.  
  355.     DEC    DE        ; Loop counter
  356.     LD    A,D
  357.     OR    E
  358.     JR    NZ,NODELP    ; Continue till done
  359.     JR    RUN        ; Go run, hl is is ready, pointing to
  360.                 ;  the first byte of squeezed code
  361.  
  362. ; Create a "half-node"
  363.  
  364. MAKHAF:    LD    C,(HL)
  365.     INC    HL
  366.     LD    A,(HL)        ; Get a byte pair from the dictionary
  367.     INC    HL
  368.     OR    A        ; If it is negative, it is "terminal"
  369.     JP    M,TERMOD    ; Branch if that is the case.
  370.  
  371. ; Else create code for one half-node of the non-terminal variety.
  372. ; Byte pair is in A,C.    Multiply it by 16 (bytes/node in "codtbl")
  373.  
  374.     SLA    C
  375.     RLA
  376.     SLA    C
  377.     RLA
  378.     SLA    C
  379.     RLA
  380.     SLA    C
  381.     RLA
  382.     ADD    A,CDTBLH    ; Add offset to beginning of "CODTBL",
  383.                 ; (page aligned)
  384.     LD    B,A        ; Now bc has the jump address
  385.  
  386. ALTENT:    PUSH    BC        ; Save it
  387.     EXX            ; Switch to dest pointers
  388.     LD    (HL),JPOP    ; Insert the "jp" opcode
  389.     INC    L        ; Remember "codtbl" is page aligned
  390.     POP    BC        ; Get addr back
  391.     LD    (HL),C        ; Jump addr, lo
  392.     INC    L
  393.     LD    (HL),B        ; Jump addr, hi
  394.     INC    L
  395.     EXX            ; Back to source pointers
  396.     RET            ; Thats all
  397.  
  398. ; Create a half-node of the terminal variety
  399.  
  400. TERMOD:    CP    0FEH        ; Check for special eof terminal node
  401.     JR    Z,SPEOF        ; Br for that unique case
  402.     LD    A,C        ; Else this byte is the complement of
  403.                 ; The returned value
  404.     CPL
  405.     EXX            ; Switch to dest pointers
  406.     INC    L        ; Just 2nd of 3 bytes need be inserted
  407.     LD    (HL),A        ; Put it in
  408.     INC    L
  409.     INC    L        ; But make sure hl gets incr'd 3 times
  410.     EXX
  411.     RET            ; That's all
  412.  
  413. ; Special EOF returns to a special address in mainline code, rather
  414. ; than using "RET".  Stack is adjusted accordingly there.
  415.  
  416. SPEOF:    LD    BC,DONE        ; The special address
  417.     JR    ALTENT        ; Use convenient code subsection above
  418.  
  419. ; Code to refill register 'B' with the next byte
  420.  
  421. REFILL:    INC    L
  422.     JR    Z,POSRLD    ; If l is zero, may be at end of buffer
  423.  
  424. CONT:    LD    B,(HL)        ; Else get next byte
  425.  
  426. ; Now we pre-shift out the next bit, shifting in a "1" from the left.
  427. ; Since the leftmost bit in the reg is a  guaranteed "1", testing the
  428. ; zero stat of the reg is a necesssary and sufficient condition for
  429. ; determining that all the bits in the reg have   been used up (see
  430. ; header code for "TMPLATE").  The only things to be careful of is that
  431. ; the the last bit is NOT used, and that the bit now in the carry flag
  432. ; IS used upon return from this subroutine.
  433.  
  434.     SCF            ; To shift in the flag bit
  435.     RR    B        ; Shift out real bit as described
  436.     RET            ; That's it
  437.  
  438. POSRLD:    INC    H        ; Check if time to reload the input
  439.     LD    A,EIBFHI    ; Buffer with additional data.
  440.     CP    H
  441.     CALL    Z,RELOAD    ; Reload if necessary (resets hl)
  442.     JR    CONT
  443.  
  444. ; Main code to perform the unsqueeze. In general, the alternate regs
  445. ; are used as output pointers, flags, etc. while the primary registers
  446. ; are used for input pointing and general purpose use.
  447.  
  448. RUN:    EXX            ; First initialize the alternate regs
  449.     LD    HL,OBUF        ; HL', output pntr, to beg of output bfr
  450.     LD    BC,0        ; C always has a copy of the previous
  451.     EXX            ; Char output;    b is a "repeat flag".
  452.  
  453.                 ; Primary register initialization:
  454.     DEC    HL        ; Init hl, the input pntr, to point to
  455.                 ;  the first byte of squeezed code -1.
  456.     LD    DE,0        ; Initialize checksum accumulator to zero
  457.     LD    B,D        ; And initialize 'b' to zero so first
  458.                 ;  call will immediately call in the
  459.                 ;  actual first byte.
  460.  
  461. MAINLP:    CALL    CODTBL        ; Unsqueeze a character
  462.     CALL    SEND        ; Output it to the output buffer
  463.     JR    MAINLP        ; And repeat "forever" (see "SPEOF"
  464.  
  465. ; Reload the input buffer, & reset HL to point to the beginning of it.
  466. ; Assumes input bfr starts page boundry and is of page multiple length.
  467.  
  468. RELOAD:    PUSH    AF
  469.     PUSH    BC
  470.     PUSH    DE
  471.     LD    B,IBUFSZ    ; Loop counter, buffer length in pages
  472.     LD    D,IBUFHI    ; Beg of buffer (hi)
  473.  
  474. RLDLP:    LD    E,0        ; Lo byte of current dma
  475.     CALL    RDSEC        ; Read in 128 bytes (1/2 page)
  476.     JR    NZ,RLDRTN    ; (return if eof enecountered)
  477.     LD    E,80H        ; To read in the next half page
  478.     CALL    RDSEC        ; Do that
  479.     JR    NZ,RLDRTN    ; As above
  480.     INC    D        ; Next page
  481.     DJNZ    RLDLP        ; Loop till done
  482.  
  483. RLDRTN:    POP    DE        ; Restore regs
  484.     POP    BC
  485.     POP    AF
  486.     LD    HL,IBUF        ; Reset input pointer
  487.     RET            ; And return
  488.  
  489. ; Subr for abover, reads 128 bytes to memory starting at HL
  490.  
  491. RDSEC:    PUSH    DE        ; Save dma before clobbering it with fcb
  492.     LD    C,SETDMA    ; Set dma function
  493.     CALL    BDOSAV
  494.     LD    A,(INUSR)
  495.     LD    E,A
  496.     LD    C,GSUSER
  497.     CALL    BDOSAV
  498.     LD    DE,DFCB        ; Input fcb
  499.     LD    C,READ
  500.     CALL    BDOSAV        ; Read a record
  501.     POP    DE        ; Restore dma to original dma address
  502.     OR    A        ; Set non-zero status
  503.     RET    Z
  504.  
  505.     LD    A,(EOFLAG)
  506.     OR    A
  507.     JR    NZ,HTCHED
  508.     CPL
  509.     LD    (EOFLAG),A
  510.     OR    A
  511.     RET
  512.  
  513. HTCHED:    LD    DE,CHOPPD
  514.     JP    FATAL
  515. ;___________________________________________________________________________
  516. ;
  517. ; When "SPEOF" is encountered, a jump to here is made to exit "CODTBL"
  518. ; rather than the normal RET instruction.
  519.  
  520. DONE:    INC    SP        ; So adjust the stack immediately
  521.     INC    SP
  522.     LD    A,(CHKSUM+0)    ; Make sure the checksum checks out
  523.     CP    E        ; Lo-byte
  524.     JR    NZ,NFG        ; Br if nfg
  525.     LD    A,(CHKSUM+1)    ; Likewise
  526.     CP    D
  527.     JR    Z,CKSMOK    ; Ok
  528.  
  529. ; If a checksum error is detected, report the warning. Let the guy
  530. ; have his file anyway, for whats its worth.
  531.  
  532. NFG:    LD    DE,CHKERR    ; "Checksum error detected"
  533.     CALL    MESAGE
  534.  
  535. ; Switch to alternate regs for output. The total #of bytes generated
  536. ; should always be a multiple of 128.  This assumption is not made,
  537. ; however, as it may not be true if the file was squeezed on non-CP/M
  538. ; systems.  Compute # of sectors to write- specifically subtract the
  539. ; buffer start addr from the current pointer value, add 7FH and divide
  540. ; by 128. If the byte count  was in fact a multiple of 128, this has
  541. ; no effect; otherwise it makes sure the final sector gets written.
  542.  
  543. CKSMOK:    EXX            ; Switch to alt regs
  544.     AND    A        ; Clear carry
  545.     LD    DE,OBUF-7FH    ; Take care of adding 7fh in advance
  546.     SBC    HL,DE        ; Subtract
  547.     SLA    L        ; Divide by 128
  548.     RL    H        ; Result now in h
  549.     LD    B,H        ; Use 'b' as the counter
  550.     CALL    WRTOUT        ; Writes 'b' sectors to the output file
  551.     EXX            ; Back to primary regs
  552.  
  553.     LD    DE,OFCB        ; Close the output file
  554.     LD    C,CLOSE
  555.     CALL    BDOSAV
  556.  
  557. ; Fall through
  558.  
  559. EXIT:    LD    HL,(NMBFLS)
  560.     DEC    HL
  561.     LD    (NMBFLS),HL
  562.     LD    A,H
  563.     OR    L
  564.     JP    NZ,NXTFIL    ; Next file
  565.     LD    SP,(OLDSTK)    ; Restore os stack
  566.     RET            ; To ccp
  567.  
  568. ; Write 'B' 128 byte sectors to the output file
  569.  
  570. WRTOUT:    LD    A,B        ; If b=0, don't write any sectors
  571.     OR    A
  572.     RET    Z
  573.  
  574.     LD    DE,OBUF        ; Init dma addr to beg of output bfr
  575.  
  576. WRTLP:    LD    C,SETDMA    ; Set dma to there
  577.     CALL    BDOSAV
  578.     PUSH    DE        ; Save that address
  579.     LD    A,(OUTUSR)
  580.     LD    E,A
  581.     LD    C,GSUSER
  582.     CALL    BDOSAV
  583.     LD    DE,OFCB        ; Specify the output file
  584.     LD    C,WRITE        ; Write a record
  585.     CALL    BDOSAV
  586.     OR    A
  587.     JR    NZ,WRTERR
  588.     POP    DE        ; Address as saved above
  589.     DJNZ    NEXSEC        ; Decrement counter, continue if not done
  590.     RET
  591.  
  592. NEXSEC:    LD    E,80H        ; Else increment by 1/2 page
  593.     LD    C,SETDMA
  594.     CALL    BDOSAV
  595.     PUSH    DE        ; Save DMA pointer
  596.     LD    DE,OFCB        ; Output FCB
  597.     LD    C,WRITE        ; Write another record
  598.     CALL    BDOSAV
  599.     OR    A        ; Need the test here also
  600.     JR    NZ,WRTERR
  601.     POP    DE        ; Get back orig pointer
  602.     INC    D        ; Inc hi-byte, 0 the lo to effect
  603.     LD    E,0        ; Another 80h incr
  604.     DJNZ    WRTLP        ; Loop till done
  605.  
  606.     RET
  607.  
  608. BDOSAV:    EXX            ; BDOS call with all registers and alts
  609.     PUSH    BC        ;   saved except for AF, AF', IX and IY
  610.     PUSH    DE
  611.     PUSH    HL
  612.     EXX
  613.     PUSH    BC
  614.     PUSH    DE
  615.     PUSH    HL
  616.     CALL    BDOS
  617.     POP    HL
  618.     POP    DE
  619.     POP    BC
  620.     EXX
  621.     POP    HL
  622.     POP    DE
  623.     POP    BC
  624.     EXX
  625.     RET
  626.  
  627. WRTERR:    LD    DE,WRTMSG    ; Write error, falls through to "fatal"
  628.  
  629. ; For fatal errors- print the message, restore the OS stack & return.
  630. ; This rountine is "jumped to", not called
  631.  
  632. FATAL:    CALL    MESAGE
  633.     LD    SP,(OLDSTK)    ; Restore stack pointer Z80-style
  634.     RET
  635.  
  636. MESAGE:    EX    DE,HL        ; Save pntr to message (supplied in DE)
  637.     LD    DE,CRLF        ; First print a CR/LF sequence
  638.     LD    C,PRTSTR
  639.     CALL    BDOSAV
  640.     EX    DE,HL        ; Then the message in question
  641.  
  642. PRINT:    LD    C,PRTSTR    ; Entry here if no CR/LF desired
  643.     JP    BDOSAV
  644.  
  645. MESS80:    LD    C,PRTSTR    ; For non-Z80 mesage, don't use "BDOSAV"
  646.     JP    BDOS
  647.  
  648. ; Send character to the output buffer, plus related processing
  649.  
  650. SEND:    EXX            ; Alt regs used for output processing
  651.     SRL    B        ; If reg is "1", repeat flag is set
  652.                 ; (note, clears itself automatically)
  653.     JR    C,REPEAT    ; Go perf the repeat
  654.     CP    90H        ; Else see if char is the repeat spec
  655.     JR    Z,SETRPT    ; Br if so
  656.     LD    C,A        ; Else nothing special- but always keep
  657.     CALL    OUT        ; Else just output the char;
  658.     EXX            ; Back to normal regs
  659.     RET
  660.  
  661. ; Set repeat flag; count value will come as the next byte. (Note: don't
  662. ; clobber C with the "90H"- it still has the prev character, the one to
  663. ; be repeated)
  664.  
  665. SETRPT:    INC    B        ; Set flag
  666.     EXX            ; Switch to primary regs & return.
  667.     RET
  668.  
  669. ; Repeat flag was previously set; current byte in a is a count value.
  670. ; A zero count is a special case which means send 90H itself.  Otherwise
  671. ; use B (was the flag) as a counter. The byte itself goes in A.
  672.  
  673. REPEAT:    OR    A        ; Check for special case
  674.     JR    Z,SND90H    ; Jump if so
  675.     DEC    A        ; Compute "count-1"
  676.     LD    B,A        ; Juggle registers
  677.     LD    A,C
  678.  
  679. AGAIN:    CALL    OUT        ; Repeat b occurrences of byte in 'a'
  680.     DJNZ    AGAIN        ; Leaves b, the rpt flag, 0 as desired
  681.     EXX            ; Restore regs & rtn
  682.     RET
  683.  
  684. SND90H:    LD    A,90H        ; Special case code to send the byte 90h
  685.     CALL    OUT        ; Itself
  686.     EXX            ;
  687.     RET            ; (90H "squeezes" into 2 bytes)
  688.  
  689. ; Output character in 'A' directly to the output buffer
  690.  
  691. OUT:    EXX            ; Back to primary regs briefly
  692.     LD    C,A        ; Save a in c
  693.     ADD    A,E        ; De is the running checksum
  694.     LD    E,A
  695.     JR    NC,NOCARY
  696.     INC    D
  697.  
  698. NOCARY:    LD    A,C        ; Put the char back into a
  699.     EXX            ; Back to output (alternate) regs
  700.  
  701.     LD    (HL),A        ; Put byte into the next avail position
  702.     INC    L        ; Increment pointer
  703.     RET    NZ        ; Return if not passing a page boundry
  704.     INC    H        ; Incr pointer high byte, check limit
  705.     LD    L,A        ; Use l, which is 0, for temp storage
  706.     LD    A,EOBFHI    ; Limit
  707.     CP    H        ; Check
  708.     LD    A,L        ; But first restore regs
  709.     LD    L,0        ;
  710.     RET    NZ        ; Ret if limit not reached
  711.     PUSH    AF
  712.     PUSH    BC
  713.     LD    B,OBUFSZ*2    ; Number of 128 byte records to write
  714.     CALL    WRTOUT
  715.     POP    BC
  716.     POP    AF
  717.     LD    HL,OBUF
  718.     RET
  719.  
  720. ;-----------------------------------------------------------------------
  721. ;
  722. ; Clean up FCB (DE=FCB_address+1)
  723.  
  724. ZERFCB:    LD    B,11        ; Fill filename with blanks
  725.     LD    A,' '
  726.     CALL    ZL
  727.     LD    B,24        ; Then zero remainder
  728.     XOR    A
  729. ZL:    LD    (DE),A
  730.     INC    DE
  731.     DJNZ    ZL
  732.     RET
  733. ;-----------------------------------------------------------------------
  734. ;
  735. ; Print name of output file. HL should point to the FCB plus 1.
  736. ;
  737. PRNFIL:
  738.     LD    B,12        ; Loop cntr (max #of chars plus ".")
  739.  
  740. CHARLP:    LD    A,(HL)        ; Get a char
  741.     CP    ' '        ; Blank?
  742.     JR    Z,SKPTYP    ; Supress them
  743.  
  744. TYPEIT:    CALL    TYPE        ; Type the char
  745.  
  746. SKPTYP:    DEC    B        ; Loop counter
  747.     RET    Z        ; Rtn when done
  748.  
  749.     LD    A,B        ; Check loop counter
  750.     CP    4        ; At this point, type a "."
  751.     JR    NZ,NOT4
  752.     LD    A,'.'
  753.     JR    TYPEIT        ; Type it. do not incr hl or reload a.
  754.  
  755. NOT4:    INC    HL        ; Advance pointer
  756.     JR    CHARLP        ; Repeat till done
  757.  
  758. ;-----------------------------------------------------------------------
  759. ;
  760. TYPE:                ; Type the char in "a" to the console
  761.     PUSH    AF        ;
  762.     PUSH    BC        ;
  763.     PUSH    DE        ;
  764.     LD    E,A        ; Where bdos wants it
  765.     LD    C,CONOUT    ; Bdos "console output" function
  766.     CALL    BDOSAV        ; Do it
  767.     POP    DE        ;
  768.     POP    BC        ;
  769.     POP    AF        ;
  770.     RET            ;
  771. ;______________________________________________________________________________
  772. ;
  773. ; Print drive/user.
  774. ;
  775. ; Entry:  B = drive number (0 .. 15)
  776. ;      C = user number  (0 .. 31, 32-user environments supported)
  777. ;
  778. ; Result:  all registers except PSW are preserved.
  779. ;
  780. PRNDU:
  781.     PUSH    BC        ; save our DU just in case
  782. ;
  783.     LD    A,B        ; Get drive in Acc.
  784.     ADD    A,'A'        ; Add character offset so 0 = 'A'
  785.     CALL    TYPE        ; Type it
  786.     LD    A,C        ; Get user in Acc.
  787. ;
  788.     LD    B,'0'-1        ; Preset for two-digit calculation later
  789.     CP    10        ; See if single digit
  790.     JR    NC,TWODIG    ; If not, print two digits
  791.     ADD    A,'0'        ; Else convert to ASCII
  792.     CALL    TYPE        ; Print to CON:
  793.     JR    PUTCLN        ; Then do colon
  794. TWODIG:    INC    B        ; Count tens digit in B
  795.     SUB    10        ; Keep subtracting 10 until carry is set
  796.     JR    NC,TWODIG
  797.     ADD    A,10        ; Get remainder (units digit) back
  798.     LD    C,A        ; Save it in C
  799.     LD    A,B
  800.     CALL    TYPE
  801.     LD    A,C
  802.     ADD    A,'0'
  803.     CALL    TYPE
  804. ;
  805. PUTCLN:
  806. ;
  807.     LD    A,':'        ; Get a colon
  808.     CALL    TYPE        ; Type that
  809. ;
  810.     POP    BC        ; Get back our DU
  811. ;
  812.     RET            ; All done
  813. ;______________________________________________________________________________
  814. ;
  815. UCASE:                ; "Upcase" the letter in "A", if necessary
  816.     CP    'a'        ;
  817.     RET    C        ; If < "a", forget it
  818.     CP    'z'+1        ;
  819.     RET    NC        ; Likewise if > "z"
  820.     SUB    20H        ; Else convert
  821.     RET            ;
  822. ;-----------------------------------------------------------------------
  823.  
  824. LOGO:    DB    'Fast Unsqueezer, ZCPR3 Version 1.0$'
  825. ERR1:    DB    'Input file not found.$'
  826. ERR2:    DB    'File open error.$'
  827. ERR3:    DB    'Too many matching files.$'
  828. ARROW:    DB    ' ---> $'
  829. LAKMEM:    DB    'Out of memory.$'
  830. NSQMSG:    DB    'Not a squeezed file.$'
  831. CHKERR:    DB    'Checksum error detected.$'
  832. WRNGUP:    DB    'Program requires Z80 uP.$'
  833. WRTMSG:    DB    'Output error, program aborted.$'
  834. CHOPPD:    DB    'Unexpected EOF encountered.$'
  835. HLPMSG:    DB    CR,LF
  836.     DB    'Syntax:',LF,'UF [du: or dir:]afn [output du: or dir:]'
  837. CRLF:    DB    CR,LF,'$'
  838.  
  839. ;-----------------------------------------------------------------------
  840.  
  841. ; Wildcard expansion module - This module, for use with SYSLIB, can be
  842. ; used to expand a wildcard filename into a table of file names as found
  843. ; in current DU:
  844.  
  845. ; ENTRY:
  846. ; HL = .buffer
  847. ; DE = .afn fcb
  848.  
  849. ; EXIT:
  850. ; HL = number of files
  851. ; ACC= zero flag set if error
  852. ; the buffer contains HL file names of 16 characters each
  853. ; Char 0 contains the user number
  854.  
  855. SFIRST    EQU    17
  856. SNEXT    EQU    18
  857.  
  858. WILDEX:    LD    (BUFPTR),HL
  859.     LD    HL,0
  860.     LD    (COUNT),HL
  861.     LD    C,SFIRST
  862.     CALL    BDOSAV
  863.     CP    0FFH
  864.     RET    Z        ; Nothing found -- error
  865.     CALL    MOVEN        ; Move name
  866.  
  867. WLOOP:    LD    C,SNEXT        ; Search for next
  868.     CALL    BDOSAV
  869.     CP    0FFH
  870.     JR    Z,DONEW        ; Finished
  871.     CALL    MOVEN
  872.     JR    WLOOP
  873.  
  874. DONEW:    OR    A
  875.     LD    HL,(COUNT)
  876.     RET
  877.  
  878. MOVEN:    PUSH    DE
  879.     LD    HL,(BUFPTR)
  880.     ADD    A,A
  881.     ADD    A,A
  882.     ADD    A,A
  883.     ADD    A,A
  884.     ADD    A,A
  885.     ADD    A,80H
  886.     LD    C,A
  887.     LD    B,0
  888.     LD    D,16        ; Move 16 characters
  889.  
  890. MOVLP:    LD    A,(BC)
  891.     LD    (HL),A
  892.     INC    HL
  893.     INC    BC
  894.     DEC    D
  895.     JR    NZ,MOVLP
  896.     LD    (BUFPTR),HL
  897.     POP    DE
  898.     LD    HL,(COUNT)
  899.     INC    HL
  900.     LD    (COUNT),HL
  901.     RET
  902.  
  903. BUFPTR:    DW    0
  904. COUNT:    DW    0
  905. NMBFLS:    DW    0
  906.  
  907. CHKSUM:    DS    2        ; Checksum kept here
  908. EOFLAG:    DS    1        ; "EOF Flag", set from 0 to FF when EOF is hit
  909.  
  910. OFCB:    DS    36        ; Output fcb
  911.  
  912. MAXFLS    EQU    400        ; Buffer size (in files) for wildcard ex-
  913.                 ; Pansions. room for this many files will
  914.                 ; Will be allocated. (400 should do it.)
  915. FNBUFF:    DS    [16*MAXFLS]    ; Beg off wildcard expansion buffer
  916. ENDFNB    EQU    $        ; End of buffer
  917.  
  918. ; Compute next page boundary following the end of the above buffer. Do
  919. ; this by adding 0FFH and "anding" with 0FF00H. This will become the
  920. ; beginning of "CODTBL".
  921.  
  922. PGBND    EQU    [ENDFNB+0FFH] AND 0FF00H ; (works with aseg only)
  923.     ORG    PGBND
  924.  
  925. ; Minimum input buffer size is 9 pages to guarantee that the max possible
  926. ; dictionary size (512 bytes plus overhead) will be read in the first pass.
  927.  
  928. IBUFSZ    EQU    16        ; Input buffer size (pages)
  929.  
  930. ; Output buffer can be any page multiple length (note it too is also page
  931. ; aligned).  Increases beyond 64 pages (16k) may do little to improve perf.
  932.  
  933. OBUFSZ    EQU    64        ; Output buffer size (pages)
  934.  
  935. PAGE    EQU    256        ; Clarity is king....
  936.  
  937. CODTBL:    DS    256*16
  938. IBUF:    DS    IBUFSZ*PAGE    ; Beginning of input buffer
  939. OBUF:    DS    OBUFSZ*PAGE    ; Likewise output buffer
  940. EOBUF    EQU    $        ; End of output buffer
  941.  
  942. CDTBLH    EQU    HIGH CODTBL
  943. IBUFHI    EQU    HIGH IBUF    ; High bytes of the beginning addresses
  944. EIBFHI    EQU    HIGH OBUF    ;   of the buffers just defined
  945. EOBFHI    EQU    HIGH EOBUF
  946.  
  947.     END
  948.