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 / ENTERPRS / CPM / UTILS / S / ZIPDIR10.ARC / ZD.Z80 < prev    next >
Text File  |  1989-10-07  |  35KB  |  1,292 lines

  1. ;******************************************************************************
  2. ;*                                          *
  3. ;*                ZIPDIR v1.0                      *
  4. ;*             ZIPfile Directory Lister                  *
  5. ;*                                          *
  6. ;******************************************************************************
  7.  
  8. ; v1.0 15 March 1989  Initial release.
  9.  
  10. ; Note: This code is hereby placed into the public domain HOWEVER a great
  11. ;    deal of the code is taken directly from the listing routines of
  12. ;    Robert A. Freed's UNARC program and used with permission. These
  13. ;    routines may be subject to to the same restrictions stated in the
  14. ;    current version of that program.     - S. Greenberg  03/15/89
  15.  
  16.  
  17.     .Z80
  18.     ASEG
  19.     ORG    100H
  20.     SUBTTL    ZIPDIR
  21.  
  22. NO    EQU    0
  23. YES    EQU    NOT NO
  24.  
  25. WBFLAG    EQU    NO        ; Yes if program is to warm boot on exit
  26. WHLADR    EQU    003EH        ; Wheel byte address if used on an RCP/M
  27.                 ; - (only used to prevent listing SYS files)
  28. LPSCRN    EQU    23        ; Lines per screen before [more] pause.
  29.  
  30. ;--- Ascii equates ---
  31. ;
  32. CTLC    EQU    'C'-'@'        ; Control-C (console abort)
  33. CTLK    EQU    'K'-'@'        ; Control-K (alternate abort)
  34. BEL    EQU    'G'-'@'        ; Bell
  35. HT    EQU    'I'-'@'        ; Horizontal tab
  36. LF    EQU    'J'-'@'        ; Line feed
  37. CR    EQU    'M'-'@'        ; Carriage return
  38. CTLS    EQU    'S'-'@'        ; Control-S (suspend output)
  39. CTLZ    EQU    'Z'-'@'        ; Control-Z (CP/M end-of-file)
  40. DEL    EQU    7FH        ; Delete/rubout
  41. REP    EQU    'P'-'@'+80H    ; Repeated byte flag (DLE with msb set)
  42.  
  43. ;--- CP/M address equates ---
  44. ;
  45. BOOT    EQU    0000H        ; Warm boot address
  46. BDOS    EQU    0005H        ; Bdos entrypoint
  47. FCB    EQU    5CH        ; Default file control block #1
  48.  
  49. ;--- BDOS function equates ---
  50. ;
  51. CONIN    EQU    1        ; Console input (single char)
  52. CONOUT    EQU    2        ; Output single char to console
  53. CONST    EQU    11        ; Get console status
  54. OPEN    EQU    15        ; Open file
  55. CLOSE    EQU    16        ; Close file
  56. READ    EQU    20        ; Read file (sequential)
  57. SETDMA    EQU    26        ; Set dma address
  58. RDRND    EQU    33        ; Read random
  59. GTSIZE    EQU    35        ; Compute file size
  60.     PAGE
  61.  
  62. ;--- FCB offsets ---
  63.  
  64. @DR    EQU    0        ; Drive code
  65. @FN    EQU    1        ; File name
  66. @FT    EQU    9        ; File type
  67. @CR    EQU    32        ; Current record
  68. @R0    EQU    33        ; Random record field R0 (LS byte)
  69. @R1    EQU    34        ; Random record field R1
  70. @R2    EQU    35        ; Random record field R2 (MS byte)
  71. @FCBSX    EQU    35        ; Extended FCB size for random I/O
  72.  
  73. ;--- ZIP file equates ---
  74. ;
  75. SIG0    EQU    50H        ; End of central directory signature (LS byte)
  76. SIG1    EQU    4BH        ; (next byte)
  77. SIG2    EQU    05H        ; (next byte)
  78. SIG3    EQU    06H        ; End of central directory signature (MS byte)
  79.  
  80. ; End of Central Directory Record offsets (only fields used are included here)
  81. ;
  82. @SIG    EQU    0        ; (4) End of central directory record signature
  83. @NFILS    EQU    10        ; (2) #of entries in the central directory
  84. @CDOFF    EQU    16        ; (4) offset- beg of file to start of cent. dir
  85.  
  86. ; Note: Structure of the individual central directory entries is indicated
  87. ; by the data structure HDRBUF at the end of the program.
  88.  
  89.     PAGE
  90. ;..............................................................................
  91. ;
  92. ; Open the file and find the end of it.
  93. ;
  94. ENTRY:    LD    (OLDSTK),SP    ; Save system stack pointer
  95.     LD    SP,STACK    ; Set to local area
  96.     LD    A,(FCB+@FN)    ; Any filename supplied?
  97.     CP    ' '        ;
  98.     JP    Z,GIVUSG    ; If not, give usage
  99.  
  100.     LD    A,LPSCRN    ; Init lines per screen counter
  101.     LD    (LPSCT),A    ;
  102.  
  103.     LD    A,(FCB+@FT)    ; See if any filetype was specified
  104.     CP    ' '        ;
  105.     JR    NZ,SKPZIP    ; If so, leave it as is
  106.  
  107.     LD    HL,'PI'        ; Else inject a ".ZIP" extension
  108.     LD    (FCB+@FT+1),HL    ;
  109.     LD    A,'Z'        ;
  110.     LD    (FCB+@FT+0),A    ;
  111.  
  112. SKPZIP:    LD    HL,FCB+12    ; Init FCB to all 0's except drive & filename
  113.     LD    B,@FCBSX-12    ;
  114. ZLP2:    LD    (HL),0        ;
  115.     INC    HL        ;
  116.     DJNZ    ZLP2        ;
  117.  
  118.     LD    C,OPEN        ; Attempt to open the file
  119.     CALL    FCBDOS        ; (calls BDOS with DE = FCB)
  120.     INC    A        ;
  121.     JP    Z,NOSUCH    ; If no such file..
  122.  
  123.     LD    A,(FCB+10)    ; Check if file has SYS attribute
  124.     AND    80H        ; (for security when program is used online)
  125.     JR    Z,NONSYS    ; If not, it's OK
  126.     LD    A,(WHLADR)    ; If so, check if wheel byte is set
  127.     OR    A        ;
  128.     JP    Z,NOSUCH    ; SYS file w/o wheel byte: pretend no such file
  129.  
  130. NONSYS:    LD    C,SETDMA    ; Set DMA addr to memory area following prgm
  131.     LD    DE,PAGE        ;
  132.     CALL    BDOSAV        ;
  133.  
  134.     LD    C,READ        ; Initially perform a seq. read to guarantee
  135.     CALL    FCBDOS        ; - proper FCB initialization (data not used)
  136.  
  137.     LD    C,GTSIZE    ; Get file size so we can access the last rec
  138.     CALL    FCBDOS        ; Returns value in FCB+@R2,R1,R0
  139.  
  140.     LD    A,(FCB+@R2)    ; Disallow the 8 meg case
  141.     OR    A        ;
  142.     JP    NZ,TOOBIG    ;
  143.     PAGE
  144. ;..............................................................................
  145. ;
  146. ; Search for the 4 byte sequence which comprises the End of Central Directory
  147. ; Record signature. The signature and the rest of the End Record which follows
  148. ; it should be completely contained within the last two records of the file,
  149. ; but it may not if the file was padded during transmission or if the ZIP file
  150. ; contains a long ZIP file comment. For file size of L records, this code will
  151. ; read the last two records, L-2 and L-1, into a page of memory at PAGE. If the
  152. ; signature is not found, the code will try again, this time reading records
  153. ; L-3 and L-2 into memory at PAGE.  This is not optimally effecient, but the
  154. ; number of re-reads is very small in practice so the time penalty is slight.
  155.  
  156. ;................................
  157.                 ;
  158. AGAIN:    LD    DE,-2        ; Come back here if a re-read is necessary
  159.     LD    HL,(FCB+@R0)    ; Last record# plus one (on 1st pass, anyway)
  160.     ADD    HL,DE        ; Subtract two
  161.     JP    NC,BADZIP    ; Don't go below zero
  162.     CALL    CABORT        ; This process is abortable
  163.     CALL    READ2        ; Read 2 recs (HL, HL+1) into page+0, page+80H
  164.  
  165. ;................................
  166.                 ;
  167.     LD    IX,PAGE        ;
  168.     LD    B,255-3        ;
  169.                 ;
  170. MTCHLP:    LD    A,(IX+@SIG+0)    ; Search for end of central directory
  171.     CP    SIG0        ; Signature - (50H,4BH,05H,06H)
  172.     JR    NZ,NOMTCH    ;
  173.     LD    A,(IX+@SIG+1)    ;
  174.     CP    SIG1        ;
  175.     JR    NZ,NOMTCH    ;
  176.     LD    A,(IX+@SIG+2)    ;
  177.     CP    SIG2        ;
  178.     JR    NZ,NOMTCH    ;
  179.     LD    A,(IX+@SIG+3)    ;
  180.     CP    SIG3        ;
  181.     JR    Z,MATCH        ; Match; IX now points to start of central dir
  182. NOMTCH:    INC    IX        ;
  183.     DJNZ    MTCHLP        ;
  184. ;...............................;
  185.  
  186.     JP    AGAIN        ; No match, try again
  187.     PAGE
  188. ;..............................................................................
  189. ;
  190. ; The End Record signature has been located. Use the values contained in the
  191. ; End Record to locate the start of the central directory itself.
  192. ;
  193. MATCH:    LD    H,(IX+@NFILS+1)    ; Get #of files, save it in NFILES
  194.     LD    L,(IX+@NFILS+0)    ;
  195.     LD    (NFILES),HL    ;
  196.  
  197.     LD    A,(IX+@CDOFF+3)    ; Get offset to start of central directory
  198.     OR    A        ; Way too big if MS byte is non-zero
  199.     JP    NZ,TOOBIG    ;
  200.     LD    H,(IX+@CDOFF+2)    ; Will divide the val by 128 to get #of records
  201.     LD    L,(IX+@CDOFF+1)    ;
  202.     LD    A,(IX+@CDOFF+0)    ;
  203.     PUSH    AF        ;
  204.     AND    7FH        ; First get the remainder from the div by 128
  205.     LD    C,A        ; (that will be the offset within the record)
  206.     LD    B,0        ; That value now in BC
  207.     PUSH    BC        ;
  208.     POP    IY        ; Now in IY
  209.     POP    AF        ; Get back orig LS byte
  210.     RLA            ; Divide HL,A by a left shift
  211.     RL    L        ;
  212.     RL    H        ;
  213.     JP    C,TOOBIG    ; Too big if HL was originally > 8000H
  214.     LD    (FCB+@R0),HL    ; Else put the value in the random rec# field
  215.     PAGE
  216. ;.............................................................................
  217. ;
  218. ; Now we are ready to read central directory data into memory. A single
  219. ; random read will position the file properly (R0, R1 are already set).
  220. ; The offset to the beginning of the data in the first record is in IY.
  221.  
  222.     LD    DE,PAGE+80H    ; A record at a time goes into this half page
  223.     LD    C,SETDMA    ;
  224.     CALL    BDOSAV        ;
  225.     LD    C,RDRND        ; Perform a random read to position the file
  226.     CALL    FCBDOS        ;
  227.     LD    C,READ        ; Read the 1st record. After this, use GETDTA.
  228.     CALL    FCBDOS        ;
  229.  
  230.     PUSH    IY        ; Relative offset to start of real data
  231.     POP    HL        ;
  232.     LD    DE,PAGE+80H-1    ; Convert it from a relative to absolute value
  233.     ADD    HL,DE        ;
  234.     LD    (DTAPTR),HL    ; Inititialize "READTA"'s internal pointer
  235.  
  236.     LD    HL,TOTS        ; Initialize all the "totals" data to zero
  237.     LD    B,TOTC        ;
  238. CLRTOT:    LD    (HL),0        ;
  239.     INC    HL        ;
  240.     DJNZ    CLRTOT        ;
  241.  
  242.     LD    DE,IDSTR    ; Type "ZIPFILE = <filename>"
  243.     CALL    PRINTS        ;
  244.     LD    HL,FCB+@FN    ;
  245.     CALL    PFN        ; (types filename, compressing blanks)
  246.     CALL    CRLF        ;
  247.     PAGE
  248. ;..............................................................................
  249. ;
  250. ; Main loop, 1 iteration/filename. Read one file header's worth of information
  251. ; into the structure named HDRBUF. Then process the information, using the
  252. ; named offsets of HDRBUF to refer to it. Repeat for each file.
  253. ;
  254. MEMLP:    LD    DE,HDRBUF    ; Destination spec for GETDTA
  255.     LD    BC,HDRLEN    ; Byte count for same
  256.     CALL    GETDTA        ; Do it
  257.  
  258.     LD    BC,(NAMLEN)    ; Read the filename field into NAMBUF
  259.     PUSH    BC        ; BC is size of field
  260.     LD    DE,NAMBUF    ; Destination spec
  261.     CALL    GETDTA        ; Do it
  262.  
  263.     LD    HL,NAMBUF    ; Spec source of data for DONAME
  264.     POP    BC        ; Field length spec for DONAME
  265.     CALL    DONAME        ; Process NAMBUF into NAME (see routine)
  266.  
  267.     LD    BC,(XLEN)    ; Extra field length
  268.     LD    DE,NAMBUF    ; Spec target area, but data gets thrown out
  269.     CALL    GETDTA        ; Read the extra field, and ignore it
  270.  
  271.     CALL    CABORT        ; Check for ^C, ^S, etc.
  272.     CALL    LIST        ; Process and list the whole entry
  273.  
  274.     LD    HL,(NFILES)    ; Decr #of files counter
  275.     DEC    HL        ;
  276.     LD    (NFILES),HL    ;
  277.     LD    A,H        ;
  278.     OR    L        ;
  279.     JR    NZ,MEMLP    ; And loop until done
  280. ;...............................;
  281.  
  282.     CALL    LISTT        ; Done with all files; list totals
  283.     JP    RETCCP        ; And exit the program
  284.     PAGE
  285. ;..............................................................................
  286. ;
  287. ; Routine to read spec'd #of bytes from the file to spec'd destination area
  288. ;
  289. ; Entry: BC has #of bytes we want to read from file
  290. ;     DE is destination pointer
  291. ;     "DTAPTR" keeps track of internal position within buffer "PAGE"
  292. ;
  293. GETDTA:    LD    A,B        ; Check if zero bytes needed
  294.     CP    16        ; This is a practical consideration - if this
  295.     JP    NC,BADZIP    ; - routine is called to read 4k+, there is
  296.     OR    C        ; - a serious problem. Prevent overwriting BDOS
  297.     RET    Z        ; Return when zero bytes needed.
  298.     DEC    BC        ; Else decr byte counter in advance
  299.     LD    HL,(DTAPTR)    ; Internal [source] pointer
  300.     INC    L        ; We are using 2nd half of page aligned bfr,
  301.     CALL    Z,RELOD        ; - so when l=0, time to reload and reset hl
  302.     LD    (DTAPTR),HL    ; Updated value
  303.     LD    A,(HL)        ; Get a byte
  304.     LD    (DE),A        ; Put it in it's destination
  305.     INC    DE        ; Incr dest pointer
  306.     JR    GETDTA        ; And possible loop for more data
  307.  
  308. ;................................
  309.                 ;
  310. RELOD:    PUSH    DE        ;
  311.     PUSH    BC        ;
  312.     LD    DE,PAGE+80H    ; Read 1 record to 2nd half of this page
  313.     LD    H,D        ; Reset HL to this value for the program's use
  314.     LD    L,E        ;
  315.     LD    C,SETDMA    ;
  316.     CALL    BDOSAV        ;
  317.     LD    C,READ        ;
  318.     CALL    FCBDOS        ;
  319.     POP    BC        ; Rtn w/ HL reset, BC and DE unaffected
  320.     POP    DE        ;
  321.     RET            ;
  322. ;...............................;
  323.     PAGE
  324. ;..............................................................................
  325. ;
  326. ; Filename processing code.
  327. ;
  328. ; Entry: BC has length of filename field
  329. ;     HL points to filename field
  330. ;     NAME is a 12 byte target area for processed filename
  331. ;
  332. ; Plan of attack: First strip off any pathnames contained in the filename
  333. ; field. This is accomplished by searching for any "/" characters; if one
  334. ; is found the effective beginning (and length) of the filename field is
  335. ; adjusted so as to start in a position one past the slash character; the
  336. ; process is repeated to find any additional slash characters.
  337. ; Next, we attempt to force the filename to fit an "8.3" mold (up to 8 chars,
  338. ; a dot, and up to 3 chars). If this is possible, the filename is displayed
  339. ; with appropriate additional spaces injected to align the dots. If, on the
  340. ; other hand, the filename has more than 8 characters before any dot, or has
  341. ; more than three characters following a dot, or has more than one dot, then
  342. ; up to 12 characters of the filename are displayed, left justified, with
  343. ; no additional spaces. If, in this case, the #of characters in the filename
  344. ; is greater than 12, then a ? will be displayed in the 1st column followed
  345. ; by the filename truncated to a length of eleven. [Concept due to Bob Freed]
  346.  
  347. DONAME:    CALL    BLNAME        ; Init the target field to spaces...
  348.     LD    A,'.'        ; And a dot.
  349.     LD    (NAME+8),A    ;
  350.  
  351. ;................................
  352.                 ;
  353. SVINFO:    LD    (NLEN),BC    ; Current value of length of field
  354.     LD    (NPTR),HL    ; Current pointer to beginning of field
  355.     LD    A,'/'        ; Character to search for
  356.     CPIR            ; Do it
  357.     JR    Z,SVINFO    ; If found, re-save BC and HL (one past patch)
  358. ;...............................;
  359.  
  360.     LD    IX,(NPTR)    ; IX: Source pointer
  361.     LD    HL,(NLEN)    ; HL: Overall field size counter
  362.     DEC    HL        ; (since it will decr to -1, not zero)
  363.     LD    DE,-1        ; DE: -1, used to decr HL
  364.     LD    IY,NAME        ; IY: Dest pointer
  365.     LD    B,8        ; B: Counts down from 8, then from 3
  366.  
  367. ;................................
  368.                 ;
  369. LP8:    LD    A,(IX)        ; Get a char, incr source pntr
  370.     INC    IX        ;
  371.     CP    '.'        ; Dot?
  372.     JR    Z,GOTDOT    ; Br if so
  373.     LD    (IY),A        ; Else xfer to dest and incr that pntr
  374.     INC    IY        ;
  375.     ADD    HL,DE        ; Decr overall count
  376.     RET    NC        ; Means we are done
  377.     DJNZ    LP8        ; Counts down from 8
  378. ;...............................;
  379.     PAGE
  380.     LD    A,(IX)        ; After 8 chars, check if next is a dot
  381.     INC    IX        ;
  382.     CP    '.'        ;
  383.     JR    NZ,LJFF        ; If not, exit and go use left-justified format
  384.  
  385. GOTDOT:    ADD    HL,DE        ; Decr overall count to account for the dot
  386.     RET    NC        ; Means we are done
  387.     LD    B,3        ; Length of ext part of filename
  388.     LD    IY,NAME+9    ; One past '.' in destination
  389.  
  390. ;................................
  391.                 ;
  392. LP3:    LD    A,(IX)        ; Transfer up to 3 characters after the dot
  393.     INC    IX        ;
  394.     CP    '.'        ; (a second dot violates the 8.3 format)
  395.     JR    Z,LJFF        ;
  396.     LD    (IY),A        ; Char goes here
  397.     INC    IY        ;
  398.     ADD    HL,DE        ; Decr overall count
  399.     RET    NC        ; Rtn if done
  400.     DJNZ    LP3        ; Else loop
  401. ;...............................;
  402.  
  403.     JR    LJFF        ; More than 3 chars after dot; violates 8.3
  404. ;..............................................................................
  405. ;
  406. ; Filename is nonstandard. Display up to 12 characters, left justified, with
  407. ; no further processing. If >12 chars, display "?" plus 1st 11 characters.
  408. ;
  409. LJFF:    CALL    BLNAME        ; Init destination feild to blanks
  410.     LD    BC,(NLEN)    ;
  411.     LD    A,B        ; Check if overall length is >12
  412.     OR    A        ;
  413.     JR    NZ,TRUNC    ; Indeed, it is over 256!
  414.     LD    A,C        ;
  415.     CP    13        ;
  416.     JR    NC,TRUNC    ; If it is over 12
  417.  
  418.     LD    DE,NAME        ; Destination
  419. XF:    LD    HL,(NPTR)    ; Beg of source field
  420.     LDIR            ; Do it
  421.     RET            ; And return
  422.  
  423. TRUNC:    LD    A,'?'        ; Inject a leading "?", indicating truncation
  424.     LD    (NAME+0),A    ;
  425.     LD    BC,11        ; #of filename characters we can now display
  426.     LD    DE,NAME+1    ; Start them here
  427.     JR    XF        ; Use code above to xfer 11 characters
  428.     PAGE
  429. ;..............................................................................
  430. ;
  431. ; Misc. subroutines
  432.  
  433. ;................................
  434.                 ;
  435. READ2:    LD    DE,PAGE        ; Random reads 2 records (HL, HL+1) to PAGE
  436.     CALL    RD1        ; Read the first
  437.     INC    HL        ; Incr rec#
  438.     LD    DE,PAGE+80H    ; Advance dma pntr
  439. RD1:    LD    (FCB+@R0),HL    ; Set rec#
  440.     LD    C,SETDMA    ;
  441.     CALL    BDOSAV        ; Set dma
  442.     LD    C,RDRND        ;
  443.     CALL    FCBDOS        ; Perform the read
  444.     RET            ;
  445. ;...............................;
  446.  
  447. ;................................
  448.                 ;
  449. PFN:    LD    B,8        ; Subr to type the filename at HL, w/o blanks
  450.     CALL    PFNAUX        ;
  451.     LD    A,'.'        ;
  452.     CALL    PCHAR        ;
  453.     LD    B,3        ;
  454. PFNAUX:    LD    A,(HL)        ;
  455.     CP    ' '        ;
  456.     CALL    NZ,PCHAR    ;
  457.     INC    HL        ;
  458.     DJNZ    PFNAUX        ;
  459.     RET            ;
  460. ;...............................;
  461.  
  462. ;................................
  463.                 ;
  464. BLNAME:    PUSH    BC        ; Init 'name' to 8 blanks, '.', & 3 blanks
  465.     PUSH    HL        ;
  466.     LD    HL,NAME        ;
  467.     LD    B,12        ;
  468. BLP:    LD    (HL),' '    ;
  469.     INC    HL        ;
  470.     DJNZ    BLP        ;
  471.     POP    HL        ;
  472.     POP    BC        ;
  473.     RET            ;
  474. ;...............................;
  475.     PAGE
  476. ;..............................................................................
  477. ;
  478. ; Terminate. Return to CCP, or do a warm boot if desired
  479. ;
  480. RETCCP:
  481.      IF    WBFLAG
  482.     JP    BOOT
  483.      ELSE
  484.     LD    SP,(OLDSTK)
  485.     RET
  486.      ENDIF
  487. ;..............................................................................
  488. ;
  489. GIVUSG:    LD    DE,USAGE    ; Give usage instructions and exit
  490. MSGRTS:    CALL    PRINTX        ;
  491.     JR    RETCCP        ;
  492.  
  493. TOOBIG:    LD    DE,TBMSG    ; Type "ZIPfile too large" and exit
  494.     JR    MSGRTS        ;
  495.  
  496. BADZIP:    LD    DE,BZMSG    ; Type "ZIPfile corrupt" and exit
  497.     JR    MSGRTS        ;
  498.  
  499. NOSUCH:    LD    DE,NSMSG    ; Type "File not found" and exit
  500.     JR    MSGRTS        ;
  501.  
  502. ABORT:    LD    DE,ABMSG    ; Type "++ Aborted ++" and exit
  503.     JR    MSGRTS        ;
  504. ;..............................................................................
  505. ;
  506. BDOSAV:    PUSH    BC        ; Call bdos; save all regs (except A)
  507.     PUSH    DE        ;
  508.     PUSH    HL        ;
  509.     PUSH    IX        ;
  510.     PUSH    IY        ;
  511.     CALL    BDOS        ;
  512.     POP    IY        ;
  513.     POP    IX        ;
  514.     POP    HL        ;
  515.     POP    DE        ;
  516.     POP    BC        ;
  517.     RET            ;
  518. ;..............................................................................
  519. ;
  520. FCBDOS:    PUSH    DE        ; Call bdos with DE = fcb; restore DE on exit
  521.     LD    DE,FCB        ;
  522.     CALL    BDOSAV        ;
  523.     POP    DE        ;
  524.     RET            ;
  525.  
  526. ; ==========================================================================
  527. ; All code below this point is taken nearly verbatim from R. Freed's UNARC16
  528. ; ==========================================================================
  529.  
  530.     SUBTTL    LISTING    ROUTINES
  531.     PAGE
  532. ; List file information
  533.  
  534. LIST:    LD    HL,(TFILES)    ; Get total files so far
  535.     LD    A,H        ; Test if this is first file
  536.     OR    L
  537.     INC    HL        ; Add one more
  538.     LD    (TFILES),HL    ; Update total files
  539.     CALL    Z,LTITLE    ; If first file, list column titles
  540.  
  541.     LD    DE,SIZE        ; Point to compressed file size
  542.     PUSH    DE        ; Save for later
  543.     LD    HL,TSIZE    ; Update total compressed size
  544.     CALL    LADD
  545.  
  546.     LD    DE,LEN        ; Point to uncompressed length
  547.     PUSH    DE        ; Save for later
  548.     LD    HL,TLEN        ; Update total length
  549.     CALL    LADD
  550.  
  551.     LD    HL,LINE        ; Setup listing line pointer
  552.     LD    DE,NAME        ; List file name from output FCB
  553.     LD    C,0        ; (with blank fill)
  554.     CALL    LNAME
  555.  
  556.     POP    DE        ; Recover file length ptr
  557.     PUSH    DE        ; Save again for factor calculation
  558.     CALL    LTODA        ; List file length
  559.     CALL    LDISK        ; Compute and list disk space
  560.     CALL    LSTOW        ; List stowage method and version
  561.     POP    BC        ; Restore uncompressed length ptr
  562.     POP    DE        ; Restore compressed size ptr
  563.     CALL    LSIZE        ; List size and compression factor
  564.     LD    A,(DATE)    ; Check for valid file date
  565.     OR    A        ; (This anticipates no-date CP/M files)
  566.     JR    NZ,LIST1    ; Skip if valid
  567.  
  568.     LD    B,18        ; Else, clear out date and time fields
  569.     CALL    FILLB
  570.     JR    LIST2        ; Skip
  571.  
  572. LIST1:    CALL    LDATE        ; List file date
  573.     CALL    LTIME        ; List file time
  574.  
  575. LIST2:    CALL    LCRC        ; List CRC value
  576.  
  577.     PAGE
  578. ; Terminate and print listing line
  579.  
  580. LISTL:    LD    DE,LINE        ; Setup listing line ptr
  581.     JR    LIST3        ; Go finish up and list it
  582.  
  583. ; List file totals
  584.  
  585. LISTT:    LD    HL,LINE        ; Setup listing line ptr
  586.     LD    DE,(TFILES)    ; List total files
  587.     CALL    WTODA
  588.     LD    DE,TLEN        ; List total file length
  589.     PUSH    DE        ; And save ptr for factor calculation
  590.     CALL    LTODA
  591.     LD    DE,(TDISK)    ; List total disk space
  592.     CALL    LDISK1
  593.     LD    B,8        ; Fill next columns with blanks
  594.     CALL    FILLB
  595.     POP    BC        ; Recover total uncompressed length ptr
  596.     LD    DE,TSIZE    ; Get total compressed size ptr
  597.     CALL    LSIZE        ; List overall size, compression factor
  598.     LD    B,19        ; Fill next columns with blanks
  599.     CALL    FILLB
  600.     LD    DE,(TCRC32+2)    ; List sum of all CRC values
  601.     CALL    WHEX        ;
  602.     LD    B,1        ;
  603.     CALL    FILLB        ;
  604.     LD    DE,(TCRC32+0)    ; LS word
  605.     CALL    WHEX        ;
  606.     LD    DE,TOTALS    ; Point to totals string (precedes line)
  607.  
  608. LIST3:    LD    (HL),0        ; Terminate listing line
  609.     JR    PRINTL        ; Go print it, followed by new line
  610.  
  611. ; Print character. Saves all registers except A.
  612.  
  613. PCHAR:    PUSH    DE        ; Save register
  614.  
  615. PCHAR2:    LD    E,A        ; Setup char
  616.     PUSH    BC
  617.     LD    C,CONOUT    ; Send to BDOS console output
  618.     CALL    BDOSAV
  619.     POP    BC
  620.     POP    DE        ; Restore register
  621.     RET            ; Return
  622.  
  623. ; Print string on new line, then start another
  624.  
  625. PRINTX:    CALL    CRLF
  626.  
  627. ; Print string, then start new line
  628.  
  629. PRINTL:    CALL    PRINTS
  630.  
  631. ; Start new line
  632. ; Note: Must preserve DE
  633.  
  634. CRLF:    LD    A,CR
  635.     CALL    PCHAR
  636.     LD    A,LF
  637.     CALL    PCHAR
  638.  
  639.     LD    HL,LPSCT    ; Reached end of screen?
  640.     DEC    (HL)
  641.     RET    NZ        ; No, return
  642.  
  643.     LD    A,LPSCRN    ; But are screen pauses enabled?
  644. LPS    EQU    $-1        ; (lines per screen = 0 if not)
  645.     OR    A
  646.     RET    Z        ; No, return
  647.  
  648.     LD    (HL),A        ; Reset count of lines left
  649.     PUSH    DE        ; Save register
  650.     LD    DE,MORE        ; Print '[more]' on the new line
  651.     CALL    PRINTS
  652.  
  653. CRLF1:    CALL    CABORT        ; Wait for char (or ^C abort)
  654.     JR    Z,CRLF1
  655.  
  656.     PUSH    AF        ; Save input response
  657.     LD    DE,NOMORE    ; Blank out the '[more]' line
  658.     CALL    PRINTS
  659.     POP    AF        ; Restore response
  660.     POP    DE        ; Restore register
  661.     XOR    ' '        ; Was response the space bar?
  662.     RET    NZ        ; Anything else scrolls another screen
  663.  
  664.     INC    A        ; Yes, set to pause after one more line
  665.     LD    (LPSCT),A
  666.     RET            ; Return
  667.  
  668.     PAGE
  669. ; Print string on new line
  670.  
  671. ; Note: Restricted to at most 5 stack levels (c.f. CHECK).  CRLF will
  672. ;    not perform page pause during this restriction, but PCHAR will
  673. ;    execute PNAME (during ABOMSG print), so we're now at the limit!
  674.  
  675. PRINT:    CALL    CRLF
  676.  
  677. ; Print NUL-terminated string
  678.  
  679. PRINTS:    LD    A,(DE)
  680.     OR    A
  681.     RET    Z
  682.  
  683.     CALL    P,PCHAR        ; (Ignore help msg chars with MSB set)
  684.     INC    DE
  685.     JR    PRINTS
  686.  
  687.     PAGE
  688. ; List column titles
  689.  
  690. ; Note: This saves some much-needed space, by using the same template
  691. ;    to generate the title line and the 'equal signs' separator line.
  692.  
  693. LTITLE:    CALL    CRLF
  694.     LD    DE,TITLES
  695.     PUSH    DE
  696.     LD    A,(DE)
  697.  
  698. LTITL1:    CP    '='        ; For titles, convert '=' to blank
  699.     JR    NZ,LTITL2
  700.     LD    A,' '
  701.  
  702. LTITL2:    CALL    PCHAR
  703.     INC    DE
  704.     LD    A,(DE)
  705.     OR    A
  706.     JR    NZ,LTITL1
  707.  
  708.     POP    DE
  709.     CALL    CRLF
  710.  
  711. LTITL3:    LD    A,(DE)
  712.     OR    A
  713.     JR    Z,CRLF
  714.  
  715.     CP    ' '        ; Separator converts non-blank to '='
  716.     JR    Z,LTITL4
  717.     LD    A,'='
  718.  
  719. LTITL4:    CALL    PCHAR
  720.     INC    DE
  721.     JR    LTITL3
  722.  
  723.     PAGE
  724. ; List file name (rewritten for ZIP)
  725. ;
  726. LNAME:    LD    BC,12
  727.     EX    DE,HL
  728.     LDIR
  729.     EX    DE,HL
  730.     RET
  731.  
  732.     PAGE
  733. ; Compute and list disk space for uncompressed file
  734.  
  735. LDISK:    PUSH    HL        ; Save line ptr
  736.     LD    HL,(LEN)    ; Convert file length to 1k disk space
  737.     LD    A,(LEN+2)    ; (Most we can handle here is 16 Mb)
  738.     LD    DE,1023        ; First, round up to next 1k
  739.     ADD    HL,DE
  740.     ADC    A,0
  741.     RRA            ; Now, shift to divide by 1k
  742.     RR    H
  743.     RRA
  744.     RR    H
  745.     AND    3FH
  746.     LD    L,H        ; Result -> HL
  747.     LD    H,A
  748.     LD    A,(LBLKSZ)    ; Get disk block size
  749.     DEC    A        ; Round up result accordingly
  750.     LD    E,A
  751.     LD    D,0
  752.     ADD    HL,DE
  753.     CPL            ; Form mask for lower bits
  754.     AND    L
  755.     LD    E,A        ; Final result -> DE
  756.     LD    D,H
  757.     LD    HL,(TDISK)    ; Update total disk space used
  758.     ADD    HL,DE
  759.     LD    (TDISK),HL
  760.     POP    HL        ; Restore line ptr
  761.  
  762. LDISK1:    CALL    WTODA        ; List result
  763.     LD    (HL),'k'
  764.     INC    HL
  765.     RET
  766.  
  767.     PAGE
  768. ; List stowage method and version
  769.  
  770. LSTOW:    CALL    FILL2B        ; Blanks first
  771.     EX    DE,HL        ;
  772.     LD    HL,STOWTX    ; Point to stowage text table
  773.     LD    A,(METHOD)    ; Get header version no.
  774.     CP    7        ;
  775.     JR    C,NCLAMP    ;
  776.     LD    A,6        ;
  777. NCLAMP:    SLA    A        ; X2
  778.     LD    C,A        ;
  779.     RLA            ; X4
  780.     ADD    A,C        ; X6
  781.     LD    C,A        ;
  782.     LD    B,0        ;
  783.     ADD    HL,BC        ;
  784.     LD    BC,6        ;
  785.  
  786. LSTOW1:    LDIR            ; List stowage text
  787.     EX    DE,HL        ; Restore line ptr
  788.     RET            ;
  789.     PAGE
  790. ; List compressed file size and compression factor
  791.  
  792. LSIZE:    PUSH    DE        ; Save compressed size ptr
  793.     PUSH    BC        ; Save uncompressed length ptr
  794.     CALL    LTODA        ; List compressed size
  795.     POP    DE        ; Recover length ptr
  796.     EX    (SP),HL        ; Save line ptr, recover size ptr
  797.  
  798. ; Compute compression factor = 100 - [100*size/length]
  799. ; (HL = ptr to size, DE = ptr to length, A = result)
  800.  
  801.     PUSH    DE        ; Save length ptr
  802.     CALL    LGET        ; Get BCDE = size
  803.     LD    H,B        ; Compute 100*size
  804.     LD    L,C        ; In HLIX:
  805.     PUSH    DE
  806.     POP    IX        ; Size
  807.     ADD    IX,IX
  808.     ADC    HL,HL        ; 2*size
  809.     ADD    IX,DE
  810.     ADC    HL,BC        ; 3*size
  811.     ADD    IX,IX
  812.     ADC    HL,HL        ; 6*size
  813.     ADD    IX,IX
  814.     ADC    HL,HL        ; 12*size
  815.     ADD    IX,IX
  816.     ADC    HL,HL        ; 24*size
  817.     ADD    IX,DE
  818.     ADC    HL,BC        ; 25*size
  819.     ADD    IX,IX
  820.     ADC    HL,HL        ; 50*size
  821.     ADD    IX,IX
  822.     ADC    HL,HL        ; 100*size
  823.     EX    (SP),HL        ; Swap back length ptr, save upper
  824.     CALL    LGET        ; Get BCDE = length
  825.     PUSH    IX
  826.     POP    HL        ; Now have (SP),HL = 100*size
  827.     LD    A,B        ; Length = 0?
  828.     OR    C        ; (Unlikely, but possible)
  829.     OR    D
  830.     OR    E
  831.     JR    Z,LSIZE2    ; Yes, go return result = 0
  832.  
  833.     LD    A,101        ; Initialize down counter for result
  834.  
  835. LSIZE1:    DEC    A        ; Divide by successive subtractions
  836.     SBC    HL,DE
  837.     EX    (SP),HL
  838.     SBC    HL,BC
  839.     EX    (SP),HL
  840.     JR    NC,LSIZE1    ; Loop until remainder < length
  841.  
  842. LSIZE2:    POP    HL        ; Clean stack
  843.     POP    HL        ; Restore line ptr
  844.     CALL    BTODA        ; List the factor
  845.     LD    (HL),'%'
  846.     INC    HL
  847.     RET            ; Return
  848.     PAGE
  849. ; List file creation date
  850.  
  851. ; ARC files use MS-DOS 16-bit date format:
  852. ;
  853. ; Bits [15:9] = year - 1980
  854. ; Bits    [8:5] = month of year
  855. ; Bits    [4:0] = day of month
  856. ;
  857. ; (All zero means no date, checked before call to this routine)
  858.  
  859. LDATE:    LD    A,(DATE)    ; Get date
  860.     AND    1FH        ; List day
  861.     CALL    BTODA
  862.     LD    (HL),' '    ; Then a blank
  863.     INC    HL
  864.     EX    DE,HL        ; Save listing line ptr
  865.     LD    HL,(DATE)    ; Get date again
  866.     PUSH    HL        ; Save for listing year (in upper byte)
  867.     ADD    HL,HL        ; Shift month into upper byte
  868.     ADD    HL,HL
  869.     ADD    HL,HL
  870.     LD    A,H        ; Get month
  871.     AND    0FH
  872.     CP    13        ; Make sure it's valid
  873.     JR    C,LDATE1
  874.     XOR    A        ; (Else will show as "???")
  875. LDATE1:    LD    C,A        ; Use to index to 3-byte string table
  876.     LD    B,0
  877.     LD    HL,MONTX
  878.     ADD    HL,BC
  879.     ADD    HL,BC
  880.     ADD    HL,BC
  881.     LD    C,3
  882.     LDIR            ; Move month text into listing line
  883.     EX    DE,HL        ; Restore line ptr
  884.     LD    (HL),' '    ; Then a blank
  885.     INC    HL
  886.     POP    AF        ; Recover high byte of date
  887.     SRL    A        ; Get 1980-relative year
  888.     ADD    A,80        ; Get true year in century
  889.  
  890. LDATE2:    LD    BC,256*2+'0'    ; Setup for 2 digits with high-zero fill
  891.     JP    BTOD        ; And convert binary to decimal ASCII
  892.  
  893.     PAGE
  894. ; List file creation time
  895.  
  896. ; ARC files use MS-DOS 16-bit time format:
  897. ;
  898. ; Bits [15:11] = hour
  899. ; Bits [10:5]  = minute
  900. ; Bits    [4:0]  = second/2 (not shown here)
  901.  
  902. LTIME:    EX    DE,HL        ; Save listing line ptr
  903.     LD    HL,(TIME)    ; Fetch time
  904.     LD    A,H        ; Copy high byte
  905.     RRA            ; Get hour
  906.     RRA
  907.     RRA
  908.     AND    1FH
  909.  
  910. LTIME2:    ADD    HL,HL        ; Shift minutes up to high byte
  911.     ADD    HL,HL
  912.     ADD    HL,HL
  913.     PUSH    HL        ; Save minutes
  914.     EX    DE,HL        ; Recover listing line ptr
  915.     LD    B,3        ;
  916.     CALL    BTODB        ; List hour
  917.     LD    (HL),':'    ; Then ":"
  918.     INC    HL
  919.     POP    AF        ; Restore and list minutes
  920.     AND    3FH
  921.     CALL    LDATE2
  922.     RET            ; Return
  923.  
  924.     PAGE
  925. ; List hex CRC value
  926.  
  927. LCRC:    CALL    FILL2B
  928.     PUSH    HL
  929.     LD    HL,(TCRC32+0)    ; Update CRC total
  930.     LD    DE,(CRC32+0)    ; LS word
  931.     ADD    HL,DE
  932.     LD    (TCRC32+0),HL
  933.     LD    HL,(TCRC32+2)
  934.     LD    DE,(CRC32+2)    ; MS word
  935.     ADC    HL,DE
  936.     LD    (TCRC32+2),HL
  937.     POP    HL
  938.  
  939.     CALL    WHEX        ; List ms word
  940.     LD    B,1
  941.     CALL    FILLB
  942.     LD    DE,(CRC32+0)    ; Fall thru and list ls word
  943.  
  944. ; List hex word in DE
  945.  
  946. WHEX:    CALL    DHEX
  947.     LD    D,E
  948.  
  949. ; List hex byte in D
  950.  
  951. DHEX:    LD    (HL),D
  952.     RLD
  953.     CALL    AHEX
  954.     LD    A,D
  955.  
  956. ; List hex nibble in A
  957.  
  958. AHEX:    OR    0F0H
  959.     DAA
  960.     CP    60H
  961.     SBC    A,1FH
  962.     LD    (HL),A
  963.     INC    HL
  964.     RET
  965.  
  966. ; A few decimal ASCII conversion callers, for convenience
  967.  
  968. WTODA:    LD    B,5        ; List blank-filled word in 5 cols
  969. WTODB:    LD    C,' '        ; List blank-filled word in B cols
  970.     JR    WTOD        ; List C-filled word in B cols
  971.  
  972. BTODA:    LD    B,4        ; List blank-filled byte in 4 cols
  973. BTODB:    LD    C,' '        ; List blank-filled byte in B cols
  974.     JR    BTOD        ; List C-filled byte in B cols
  975.  
  976. LTODA:    LD    BC,9*256+' '    ; List blank-filled long in 9 cols
  977. ;    JR    LTOD
  978.  
  979.     PAGE
  980. ; Convert Long (or Word or Byte) Binary to Decimal ASCII
  981. ; R. A. Freed
  982. ; 2.0    15 Mar 85
  983.  
  984. ; Entry:    A  = Unsigned 8-bit byte value (BTOD)
  985. ;        DE = Unsigned 16-bit word value (WTOD)
  986. ;        DE = Pointer to low byte of 32-bit long value (LTOD)
  987. ;        B  = Max. string length (0 implies 256, i.e. no limit)
  988. ;        C  = High-zero fill (0 to suppress high-zero digits)
  989. ;        HL = Address to store ASCII byte string
  990. ;
  991. ; Return:    HL = Adress of next byte after last stored
  992. ;
  993. ; Stack:    n+1 levels, where n = no. significant digits in output
  994. ;
  995. ; Notes:    If B > n, (B-n) leading fill chars (C non-zero) stored.
  996. ;        If B < n, high-order (n-B) digits are suppressed.
  997. ;        If only word or byte values need be converted, use the
  998. ;         shorter version of this routine (WTOD or BTOD) instead.
  999.  
  1000. RADIX    EQU    10        ; (Will work with any radix <= 10)
  1001.  
  1002. LTOD:    PUSH    DE        ; Entry for 32-bit long pointed to by DE
  1003.     EXX            ; Save caller's regs, swap in alt set
  1004.     POP    HL        ; Get pointer and fetch value to HADE
  1005.     LD    E,(HL)
  1006.     INC    HL
  1007.     LD    D,(HL)
  1008.     INC    HL
  1009.     LD    A,(HL)
  1010.     INC    HL
  1011.     LD    H,(HL)
  1012.     EX    DE,HL        ; Value now in DAHL
  1013.     JR    LTOD1        ; Join common code
  1014.  
  1015. BTOD:    LD    E,A        ; Entry for 8-bit byte in A
  1016.     LD    D,0        ; Copy to 16-bit word in DE
  1017.  
  1018. WTOD:    PUSH    DE        ; Entry for 16-bit word in DE, save it
  1019.     EXX            ; Swap in alt regs for local use
  1020.     POP    HL        ; Recover value in HL
  1021.     XOR    A        ; Set to clear upper bits in DE
  1022.     LD    D,A
  1023.  
  1024. ; Common code for all entries
  1025.  
  1026. LTOD1:    LD    E,A        ; Now have 32-bit value in DEHL
  1027.     LD    C,RADIX        ; Setup radix for divides
  1028.     SCF            ; Set first-time flag
  1029.     PUSH    AF        ; Save for stack emptier when done
  1030.  
  1031.     PAGE
  1032. ; Top of conversion loop
  1033.  
  1034. ; Method:  Generate output digits on stack in reverse order.  Each loop
  1035. ; divides the value by the radix.  Remainder is the next output digit,
  1036. ; quotient becomes the dividend for the next loop.  Stop when get zero
  1037. ; quotient or no. of digits = max. string length.  (Always generates at
  1038. ; least one digit, i.e. zero value has one "significant" digit.)
  1039.  
  1040. LTOD2:    CALL    DIVLB        ; Divide to get next digit
  1041.     OR    '0'        ; Convert to ASCII (clears carry)
  1042.     EXX            ; Swap in caller's regs
  1043.     DJNZ    LTOD5        ; Skip if still more room in string
  1044.  
  1045. ; All done (value fills string), this is the output loop
  1046.  
  1047. LTOD3:    LD    (HL),A        ; Store digit in string
  1048.     INC    HL        ; Bump string ptr
  1049.  
  1050. LTOD4:    POP    AF        ; Unstack next digit
  1051.     JR    NC,LTOD3    ; Loop if any
  1052.  
  1053.     RET            ; Return to caller
  1054.  
  1055. ; Still more room in string, test if more significant digits
  1056.  
  1057. LTOD5:    PUSH    AF        ; Stack this digit
  1058.     EXX            ; Swap back local regs
  1059.     LD    A,H        ; Last quotient = 0?
  1060.     OR    L
  1061.     OR    D
  1062.     OR    E
  1063.     JR    NZ,LTOD2    ; No, loop for next digit
  1064.  
  1065. ; Can stop early (no more digits), handle leading zero-fill (if any)
  1066.  
  1067.     EXX            ; Swap back caller's regs
  1068.     OR    C        ; Any leading fill wanted?
  1069.     JR    Z,LTOD4        ; No, go to output loop
  1070.  
  1071. LTOD6:    LD    (HL),A        ; Store leading fill
  1072.     INC    HL        ; Bump string ptr
  1073.     DJNZ    LTOD6        ; Repeat until fill finished
  1074.     JR    LTOD4        ; Then go store the digits
  1075.  
  1076.     PAGE
  1077.     SUBTTL    MISCELLANEOUS SUPPORT ROUTINES
  1078.  
  1079. ; Note: The following general-purpose routine is currently used in this
  1080. ;    program only to divide longs by 10 (by decimal convertor, LTOD).
  1081. ;    Thus, a few unneeded code locations have been commented out.
  1082. ;    (May be restored if program requirements change.)
  1083.  
  1084. ; Unsigned Integer Division of Long (or Word or Byte) by Byte
  1085. ; R. A. Freed
  1086.  
  1087. ; Divisor in C, dividend in (A)DEHL or (A)HL or L (depends on call used)
  1088. ; Quotient returned in DEHL (or just HL), remainder in A
  1089.  
  1090. ;DIVXLB:OR    A        ; 40-bit dividend in ADEHL (A < C)
  1091. ;    JR    NZ,DIVLB1    ; Skip if have more than 32 bits
  1092.  
  1093. DIVLB:    LD    A,D        ; 32-bit dividend in DEHL
  1094.     OR    E        ; But is it really only 16 bits?
  1095.     JR    Z,DIVWB        ; Yes, skip (speeds things up a lot)
  1096.  
  1097.     XOR    A        ; Clear high quotient for first divide
  1098.  
  1099. DIVLB1:    CALL    DIVLB2        ; Get upper quotient first, then swap:
  1100. DIVLB2:    EX    DE,HL        ; Upper quotient in DE, lower in HL
  1101.  
  1102. DIVXWB:    OR    A        ; 24-bit dividend in AHL (A < C)
  1103.     JR    NZ,DIVWB1    ; Skip if have more than 16 bits
  1104.  
  1105. DIVWB:    LD    A,H        ; 16-bit dividend in HL
  1106.     CP    C        ; Will quotient be less than 8 bits?
  1107.     JR    C,DIVBB1    ; Yes, skip (small dividend speed-up)
  1108.  
  1109.     XOR    A        ; Clear high quotient
  1110.  
  1111. DIVWB1:    LD    B,16        ; Setup count for 16-bit divide
  1112.     JR    DIVB        ; Skip to divide loop
  1113.  
  1114. ;DIVBB: XOR    A        ; 8-bit dividend in L
  1115. DIVBB1:    LD    H,L        ; For very small nos., pre-shift 8 bits
  1116.     LD    L,0        ; High byte of quotient will be zero
  1117.     LD    B,8        ; Setup count for 8-bit divide
  1118.  
  1119. ; Top of divide loop (vanilla in-place shift-and-subtract)
  1120.  
  1121. DIVB:    ADD    HL,HL        ; Divide AHL (B=16) or AH (B=8) by C
  1122.     RLA            ; Shift out next remainder bit
  1123. ;    JR    C,DIVB1     ; (This needed only for divsors > 128)
  1124.     CP    C        ; Greater than divisor?
  1125.     JR    C,DIVB2        ; No, skip (next quotient bit is 0)
  1126.  
  1127. DIVB1:    SUB    C        ; Yes, reduce remainder
  1128.     INC    L        ; And set quotient bit to 1
  1129.  
  1130. DIVB2:    DJNZ    DIVB        ; Loop for no. bits in quotient
  1131.     RET            ; Done (quotient in HL, remainder in A)
  1132.  
  1133.     PAGE
  1134. ; Fetch a long (4-byte) value
  1135.  
  1136. LGET:    LD    E,(HL)        ; Fetch BCDE from (HL)
  1137.     INC    HL
  1138.     LD    D,(HL)
  1139.     INC    HL
  1140.     LD    C,(HL)
  1141.     INC    HL
  1142.     LD    B,(HL)
  1143.     RET
  1144.  
  1145. ; Add two longs
  1146.  
  1147. LADD:    LD    B,4        ; (DE) + (HL) -> (HL)
  1148.     OR    A
  1149.  
  1150. LADD1:    LD    A,(DE)
  1151.     ADC    A,(HL)
  1152.     LD    (HL),A
  1153.     INC    HL
  1154.     INC    DE
  1155.     DJNZ    LADD1
  1156.  
  1157.     RET
  1158.  
  1159. ; Fill routines
  1160.  
  1161. FILL2B:    LD    B,2        ; Fill 2 blanks
  1162.  
  1163. FILLB:    LD    C,' '        ; Fill B blanks
  1164.  
  1165. FILL:    LD    (HL),C        ; Fill B bytes with char in C
  1166.     INC    HL
  1167.     DJNZ    FILL
  1168.     RET
  1169.     PAGE
  1170.  
  1171. ; Check for CTRL-C abort (and/or read console char if any). Destroys C.
  1172.  
  1173. CABORT:    LD    C,CONST        ; Get console status
  1174.     CALL    BDOSAV
  1175.     OR    A        ; Character ready?
  1176.     RET    Z        ; Return (Z set) if not
  1177.  
  1178.     LD    C,CONIN        ; Input console char (echo if printable)
  1179.     CALL    BDOSAV
  1180.  
  1181. ; Note: Following added in UNARC 1.5 to handle any ^S input which is not
  1182. ;    detected by CP/M 2.2 BDOS.
  1183.  
  1184.     AND    7FH        ; Mask to 7 bits
  1185.     CP    CTLS        ; Is it CTRL-S (suspend output)?
  1186.     LD    C,CONIN
  1187.     CALL    Z,BDOSAV    ; Yes, wait for another char
  1188.     AND    7FH        ; Mask to 7 bits
  1189.  
  1190.     CP    CTLC        ; Is it CTRL-C?
  1191.     JR    Z,GABORT    ; Yes, go abort
  1192.  
  1193.     CP    CTLK        ; Or is it CTRL-K (RCP/M alternate ^C)?
  1194.     RET    NZ        ; No, return char (and NZ) to caller
  1195.  
  1196. GABORT:    JP    ABORT        ; Abort
  1197.  
  1198.     PAGE
  1199.     SUBTTL    MESSAGES AND INITIALIZED DATA
  1200.  
  1201. MORE:    DB    '[more]',0
  1202. NOMORE:    DB    CR,'       ',HT,CR,0
  1203.  
  1204. ABMSG:    DB    '++ Aborted ++',0
  1205. TBMSG:    DB    'Zipfile too large.',0
  1206. BZMSG:    DB    'Zipfile corrupt.',0
  1207. NSMSG:    DB    'Not found.',0
  1208. IDSTR:    DB    CR,LF,'Zipfile = ',0
  1209.  
  1210. USAGE:    DB    'ZIPDIR v1.0 SGG  03-15-89   ',CR,LF,LF
  1211.     DB    'Usage:  ZD  <zipfile>[.zip]',0
  1212.  
  1213. MONTX:    DB    '???JanFebMarAprMayJunJulAugSepOctNovDec'
  1214.  
  1215. STOWTX:    DB    'Stored'
  1216.     DB    'Shrunk'
  1217.     DB    'Reduc1'
  1218.     DB    'Reduc2'
  1219.     DB    'Reduc3'
  1220.     DB    'Reduc4'
  1221.     DB    ' ???  '
  1222.  
  1223. TITLES:    DB    'Name========  =Length  Disk  Method  =Stored Save'
  1224.     DB    'd ==Date=== Time=  ===CRC==='
  1225. LINLEN    EQU    $-TITLES
  1226.     DB    0
  1227.  
  1228. TOTALS:    DB    '        ====  =======  ====          =======  ==='
  1229.     DB    '                   ========='
  1230.     DB    CR,LF
  1231.     DB    'Total  '    ; (LINE must follow!)
  1232.  
  1233. LINE:    DS    LINLEN+1    ; Listing line buffer (follow TOTALS!)
  1234.  
  1235. LBLKSZ:    DB    1        ; Disk allocation block size for listing
  1236.  
  1237. ;----
  1238. ;
  1239. TOTS    EQU    $        ; Start of listing totals
  1240.  
  1241. TFILES:    DS    2        ; Total files processed
  1242. TLEN:    DS    4        ; Total uncompressed bytes
  1243. TDISK:    DS    2        ; Total 1K disk blocks
  1244. TSIZE:    DS    4        ; Total compressed bytes
  1245. TCRC32:    DS    4        ; Total of all CRC values
  1246. TOTC    EQU    $-TOTS        ; Count of bytes to clear
  1247.  
  1248. ;................................
  1249.                 ;
  1250. HDRBUF    EQU    $        ; ZIP file header buffer...
  1251.                 ;
  1252. SIG:    DS    4        ; Central file header signature
  1253. PRGVER:    DS    2        ; Program version
  1254. EXTVER:    DS    2        ; Version needed to extract
  1255. BITFLG:    DS    2        ; General purpose bit flag
  1256. METHOD:    DS    2        ; Compression method
  1257. TIME:    DS    2        ; Modification time
  1258. DATE:    DS    2        ; Modification date
  1259. CRC32:    DS    4        ; 32-bit CRC check of uncompressed file
  1260. SIZE:    DS    4        ; Compressed bytes
  1261. LEN:    DS    4        ; Uncompressed bytes
  1262. NAMLEN:    DS    2        ; Filename length
  1263. XLEN:    DS    2        ; Extra field length
  1264. COMLEN:    DS    2        ; File comment length
  1265. STDISK:    DS    2        ; Starting disk number
  1266. INTATR:    DS    2        ; Internal file attributes
  1267. EXTATR:    DS    4        ; External file attributes
  1268. HDRLOC:    DS    4        ; Relative offset of local header
  1269.                 ;
  1270. HDRLEN    EQU    $-HDRBUF    ; Length of all of the above
  1271. ;...............................;
  1272.  
  1273. NAME:    DS    12        ; Post-processed filename
  1274. ;...............................;
  1275.  
  1276. LPSCT:    DS    1        ; Lines per screen counter
  1277. NFILES:    DS    2        ; #of files in the ZIP to list
  1278. NLEN:    DS    2        ;
  1279. NPTR:    DS    2        ;
  1280. DTAPTR:    DS    2        ;
  1281. OLDSTK:    DS    2        ; Save system stack here
  1282.     DS    80H        ; Stack area for program's use
  1283. STACK    EQU    $        ; Tos
  1284.  
  1285. NXTPG    EQU    ($+00FFH) AND (0FF00H)
  1286.     ORG    NXTPG
  1287.  
  1288. PAGE:    DS    100H
  1289. NAMBUF    EQU    $
  1290.  
  1291.     END
  1292.