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 / STARLET / LSWP106.ZIP / LSWP106.ASM < prev    next >
Assembly Source File  |  1986-10-12  |  35KB  |  1,348 lines

  1. ;    LSWEEP, MSDOS & CCPM version by Howard Vigorita, NYACC, CP/M SIG
  2. ;    upload comments &/or updates to (718) 539 - 3338
  3. ;
  4.             release        equ    1
  5.             version        equ    06
  6.             date macro
  7.                 db    '10/12/86'
  8.             endm
  9. ;
  10. ;    LSWEEP is a MSDOS generic program to step through a directory of
  11. ;    LBR library members in 'sweep' fashion, with the ability to view
  12. ;    or extract members. This version has been derived from the CP/M-86
  13. ;    versions of LDIR & LTYPE by Charlie Godet-Ceraolo. This version has
  14. ;    also been qualified for use under Concurrent PCDOS 4.1 and 5.0.
  15. ;
  16. ;    This software is released into the public domain on the condition
  17. ;    that it is not incorporated into any other software for which the
  18. ;    source code and credits are not supplied or included in any library
  19. ;    for which redistribution is restricted. Any variance from these
  20. ;    conditions may only be obtained on written consent of the author.
  21. ;
  22. ;    Non-Profit Public Domain Libraries & BBS's: redistribution and use
  23. ;    of this package is encouraged.
  24. ;
  25. ;    All other commercial activities: redistribution of this package is
  26. ;    encouraged. Distribution of the executable file alone is permitted
  27. ;    so long as the signon is left intact. The entire package may be
  28. ;    included in a software library for commercial distribution on the
  29. ;    condition that the distributor waive any rights in the software
  30. ;    library which might tend to restrict its redistribution, other than
  31. ;    rights similar to ones reserved here. All non-profit library and
  32. ;    BBS proprietors, as well as other software authors, are intended to
  33. ;    be benificiaries of this covenant. Any enrichment obtained in
  34. ;    violation of this covenant shall be held in trust and disgourged on
  35. ;    demand of the author or any benificiary.
  36. ;
  37. ;    REGENERATION
  38. ;    ------------
  39. ;
  40. ;    To reassemble this program with MASM 1.0 or 2.0:
  41. ;        MASM LSWEEP ;
  42. ;        LINK LSWEEP ;
  43. ;    With later MASMs, use the "/A" option to link segments in alpha order
  44. ;
  45. ;
  46. ;    HISTORY
  47. ;    -------
  48. ;    ver 1.06    Removed '?' in fcb open call for CCPM 5.0.
  49. ;
  50. ;    ver 1.05    Run time detection of CCPM for signon.
  51. ;
  52. ;    ver 1.04    Quashed out spaces in filename z-strings for CCPM 4.1
  53. ;            compatability and optimized the unsqueezer.
  54. ;
  55. ;    ver 1.03    Added command interpretation during paged viewing
  56. ;
  57. ;    ver 1.02    Added P option to allow paged viewing
  58. ;
  59. ;    ver 1.00    Combined LDIR & LTYPE with 'sweep' interface
  60. ;
  61. ;-----------------------------------------------------------------------
  62.  
  63.     ;    equates
  64.     ;
  65.  
  66.     ;    configuration constants
  67.     ;
  68. false        equ    0
  69. true        equ    NOT false
  70. ibm_chr_set    equ    false        ; IBM ext char set (cute little boxes)
  71. page_len    equ    20        ; # of lines for page scroll
  72. dir_buf_sects    equ    4*8        ; # of directory records to buffer
  73. rec_size    equ    128        ; LBR logical record size
  74. irec_per_blk    equ    4*27        ; count of input records to buffer
  75. orec_per_blk    equ    4*27        ; count of unsqueezed records to buffer
  76. ibuf_size    equ    irec_per_blk*rec_size
  77. obuf_size    equ    orec_per_blk*rec_size
  78.  
  79.     ;    LBR equates and offsets
  80.     ;
  81. entries        equ    rec_size*irec_per_blk/entry_len
  82. tree_size    equ    257        ; max chars in Huffman code
  83. entry_len    equ    32
  84. active        equ    00H
  85. unused        equ    0FFH
  86. deleted        equ    0FEH
  87. status        equ     0
  88. fname        equ     1
  89. extension    equ     9
  90. index        equ    12
  91. count        equ    14        ; member size in 128 byte blocks
  92. crc        equ    16
  93.  
  94.     ;    operating system equates
  95.     ;
  96. dos        equ    21h    ; MSDOS entry point
  97. conout        equ    02h    ;    write console character
  98. dir_conin    equ    07h    ;    direct console input
  99. flush_kb    equ    0Ch    ;    flush type-ahead keyboard buffer
  100. openf        equ    0Fh    ;    open file
  101. srch_fst    equ    11h    ;    search first
  102. setdta        equ    1Ah    ;    set disk transfer address
  103. read_blk    equ    27h    ;    random block read
  104. setiv        equ    25h    ;    set interrupt vector
  105. xctl_c        equ    33h    ;     extend ctl-c checking
  106. makstrm        equ    3Ch    ;    make file stream
  107. opnstrm        equ    3Dh    ;    open file stream
  108. clostrm        equ    3Eh    ;    close output stream
  109. wrtstrm        equ    40h    ;    write to output stream
  110. trmproc        equ    4Ch    ;    terminate process
  111.  
  112.     ;    Ascii equates
  113.     ;
  114. TAB        equ    09H
  115. CR        equ    0DH
  116. LF        equ    0AH
  117. eof        equ    1Ah
  118.  
  119.  
  120.  
  121.     ; Base Page Program Segment Prefix
  122.     ; --------------------------------
  123.  
  124. basepg    SEGMENT AT 0
  125.  
  126.     ;        base page fields of interest
  127.     ORG    5Ch
  128. bfcb    equ    $
  129.  
  130.     ORG    80h
  131. bbuff    equ    $
  132.  
  133.  
  134. basepg    ENDS
  135.  
  136.  
  137.     ; Program Data Storage Area
  138.     ; -------------------------
  139.  
  140. data    SEGMENT WORD
  141.  
  142. signon    db    cr,lf,'LSWEEP for ',0
  143. signon1    db    'DOS, version ', release + '0', '.'
  144.     db    (version/10) + '0'
  145.     db    (version MOD 10) + '0',', '
  146.     date
  147.     db    ', Howard Vigorita',CR,LF,
  148.     db    0
  149.  
  150. ms_dos    db    'MS-',0
  151.  
  152. ccpm    db    'Concurrent PC ',0
  153.  
  154. menu_beg    equ    $
  155.  
  156. if ibm_chr_set
  157. menu    db    CR,LF
  158.     db    tab,0DAh,47 dup(0C4h),0BFh,cr,lf
  159.     db    tab,0B3h,tab,tab,'    COMMANDS',tab,tab,tab,0B3h,cr,lf
  160.     db    tab,0B3h,6 dup(tab),0B3h,cr,lf
  161.     db    tab,0B3h,tab,    ' ? - Display this menu',tab,tab,tab,0B3h,cr,lf
  162.     db    tab,0B3h,tab,    ' E - Extract & unsqueeze a member',tab,0B3h,cr,lf
  163.     db    tab,0B3h,tab,    ' Q - Quick extract w/o unsqueezing',tab,0B3h,cr,lf
  164.     db    tab,0B3h,tab,    ' V - View a (viewable) member',tab,tab,0B3h,cr,lf
  165.     db    tab,0B3h,tab,    ' P - Page through a member',tab,tab,0B3h,cr,lf
  166.     db    tab,0B3h,tab,    ' X - Exit this program',tab,tab,tab,0B3h,cr,lf
  167.     db    tab,0B3h,'     Anything else skips to the next member',tab,0B3h,cr,lf
  168.     db    tab,0C0h,47 dup(0C4h),0D9h,cr,lf
  169.     db    0
  170. else
  171. menu    db    CR,LF,tab,tab,tab,'COMMANDS:',cr,lf,cr,lf
  172.     db    tab,tab,'? - Display this menu',cr,lf
  173.     db    tab,tab,'E - Extract & unsqueeze a member',cr,lf
  174.     db    tab,tab,'Q - Quick extract w/o unsqueezing',cr,lf
  175.     db    tab,tab,'V - View a (viewable) member',cr,lf
  176.     db    tab,tab,'P - Page through a member',cr,lf
  177.     db    tab,tab,'X - Exit this program',cr,lf
  178.     db    tab,'    Anything else skips to the next member',cr,lf
  179.     db    0
  180. endif
  181.  
  182. menu_len    equ    $-menu_beg
  183.  
  184. USEMSG        db    TAB,'USAGE: "LSWEEP [D:]LibraryName[.LBR]"',CR,LF
  185.         db    tab,'   or  "LSWEEP D:" if only one LBR on D:',0
  186. drv_req        db    'Enter destination drive A: to P: (CR=default): ',0
  187. k_msg        db    'k    > <',8,8,0
  188. unsq_msg    db    '  unsqueezing -> ',0
  189. page_msg    db    'CTL-X cancels, SPACE advances a line, '
  190.         db    'RETURN advances a page',cr,lf,lf,0
  191. OPNMSG        db    'Library file not found',0
  192. LIBEXT        db    'LBR',0
  193. EOFMSG        db    'Premature End of File',0
  194. NoRoomMsg    db    'No room for Huffman tree',CR,LF,0
  195. mak_msg        db    'Error making output file',0
  196. wrt_msg        db    'Error writing to output',0
  197. rd_msg        db    'Error reading library file',0
  198. full_msg    db    'Error writing to output file, disk may be full',0
  199. lbrmsg        db    'Library: ',0
  200. done_msg    db    'DONE.',cr,lf,0
  201. MAXMSG        db    '; maximum slots:',0
  202. FREEMSG        db    '; free slots:',0
  203.  
  204.  
  205.     ;    dynamic data area
  206.     ;
  207. dda        equ    $
  208. max_entries    equ    dda+2        ; dw (?) size of dir
  209. in_use        equ    max_entries+2    ; dw (?) Max - inuse = free
  210. entries_todo    equ    in_use+2    ; dw (?) how many so far
  211. SEARCH_STR    equ    entries_todo+2 ; db 11 dup (?) for fcb2 fname
  212.  
  213. FCB         equ    search_str+11    ; db (?)
  214. FCBDN        equ     FCB
  215. FCBFN        equ    fcb+1        ; db 8 dup(?)
  216. FCBFT        equ    fcbfn+8        ; db 3 dup(?)
  217. FCBEX        equ    fcbft+3        ; db (?)
  218. FCBS1        equ    fcbex+1        ; db (?)
  219. FCBS2        equ    fcbs1+1        ; db (?)
  220. FCBRC        equ    fcbs2+1        ; db (?)
  221. FCB2        equ    fcbrc+1        ; db 16 dup (?) second fcb
  222. FCBD0        equ    FCB2
  223. FCBCR        equ    fcb2+16        ; db (?)
  224. FCBRNO        equ    fcbcr+1        ; db 4 dup (?)
  225.  
  226. decbuf        equ    fcbrno+4    ; db 6 dup (?) decimal output buffer
  227. code_tree    equ    decbuf+6    ; db tree_size * 4 dup (?) Huffman tree
  228. lbr_name    equ    code_tree+(4*tree_size)    ;db    15 dup (?)
  229. drvout        equ    lbr_name+15    ; db 2 dup (?)
  230. filout        equ    drvout+2    ; db    15 dup (?)
  231.  
  232. buf_counter    equ    filout+15    ; dw  ?     bytes left in input buffer
  233. buf_size    equ    buf_counter+2    ; dw ? input buffer size
  234. buf_ptr        equ    buf_size+2    ; dw ? next input buffer byte
  235. out_handle    equ    buf_ptr+2    ; dw ?
  236. entries_left    equ    out_handle+2    ; dw ?
  237. mbr_name    equ    entries_left+2    ; dw ?
  238. sav_sp        equ    mbr_name+2    ; dw ?
  239. entry_ptr    equ    sav_sp+2    ; dw ?
  240. buf_num        equ    entry_ptr+2    ; dw ?
  241. dbuf_sects    equ    buf_num+2    ; dw ?
  242. blks_left    equ    dbuf_sects+2    ; dw ? size in 128 byte blocks
  243. obuf_ctr    equ    blks_left+2    ; dw ?
  244. obuf_bytes    equ    obuf_ctr+2    ; dw ?
  245. obuf_ptr    equ    obuf_bytes+2    ; dw ?
  246.  
  247. drv_error    equ    obuf_ptr+2    ; db ? drive request out of range
  248. last_char    equ    drv_error+1    ; db ? last character read
  249. rot_counter    equ    last_char+1    ; db ? rotating bit counter
  250. rot_byte    equ    rot_counter+1    ; db ? rotating byte
  251. squeezed    equ    rot_byte+1    ; db ? un/squeezed flag
  252. rep_cnt        equ    squeezed+1    ; db ? repeat counter
  253. line_count    equ    rep_cnt+1    ; db ? line counter for page function
  254.  
  255. wflag        equ    line_count+1    ; db ? write to file requested
  256. rflag        equ    wflag+1        ; db ? raw write to file (no unsq)
  257. pflag        equ    rflag+1        ; db ? page through file
  258.  
  259. dta        equ    pflag+1        ; db 128 dup (?) disk transfer area
  260. obuf        equ    dta+ibuf_size
  261.  
  262. data    ENDS
  263.  
  264.  
  265.  
  266.     ; PROGRAM STARTS HERE
  267.     ; -------------------
  268.  
  269. code    SEGMENT WORD public
  270.     assume    CS:code, DS:basepg, SS:a_stack
  271.  
  272.     ; note that data segment register is left pointing at the base page
  273.     ; program segment prefix pending a copy to our own prog data area
  274.     ;
  275. lsweep:
  276.  
  277.     mov    AX,data            ;init extra segment register
  278.     mov    ES,AX            ; to point to prog data area
  279.     assume    ES:data
  280.  
  281.     ; copy base page file control block to our own fbc in prog data area
  282.     ;
  283.     mov    SI,offset bfcb        ;base pg fcb to source index
  284.     mov    DI,offset fcb        ;our fcb to dest index
  285.     mov    CX,37            ; # of bytes to move
  286.     rep movsb            ;block move em    
  287.  
  288.     ; copy base page disk transfer buffer to our own dta in prog data area
  289.     ;
  290.     mov    SI,offset bbuff        ;base pg dta to source index
  291.     mov    DI,offset dta        ;our dta to dest index
  292.     mov    CX,64            ; # of words to move
  293.     rep movsw            ;block move em    
  294.  
  295.     ; point SS register at program segment prefix
  296.     ; and use default dta & fcb as 165 byte stack
  297.     ;
  298.     push    DS
  299.     pop    SS
  300.     assume    SS:basepg
  301.     mov    SP,100h
  302.  
  303.     ; point the data segment register at our own data area
  304.     ;
  305.     push    ES
  306.     pop    DS
  307.     assume    DS:data 
  308.  
  309.     ; intercept ctl-c interrupt & disable it for now
  310.     ;
  311.     mov    DX,offset int_disable    ; address of an IRET instruction
  312.     call    int_set
  313.  
  314.     ; turn on extended ctl-c detection
  315.     ;
  316.     mov    AX,xctl_c*256+1        ; AH=xctl_c; AL=1
  317.     mov    DL,1
  318.     int    dos
  319.     
  320. begin:
  321.  
  322.     ;    Print signon message
  323.     ;
  324.     mov    SI,offset signon
  325.     call    display
  326.     push    DS
  327.     xor    AX,AX
  328.     mov    DS,AX
  329.     mov    AX,word ptr DS:380h    ; see what's at INT 224
  330.     pop    DS
  331.     or    AX,AX
  332.     jz    its_msdos        ; if nothing, its MSDOS
  333.     mov    SI,offset CCPM        ; else, its Concurrent
  334.     jmp    short disp_os
  335. its_msdos:
  336.     mov    SI,offset ms_dos
  337. disp_os:
  338.     call    display
  339.     mov    SI, offset signon1    ; display rest of signon
  340.     call display
  341.  
  342.     ;    check for command line, display usage if none
  343.     ;
  344.     mov    BX,offset dta
  345.     cmp    byte ptr [BX],0
  346.     jnz    cmdok        ; we got one, proceed
  347.  
  348.     ;    no command line, show usage and exit
  349.     ;
  350.     call    crlf
  351.     mov    SI,offset USEMSG
  352.     call    display
  353.     call    crlf
  354.     jmp    finish
  355.  
  356. cmdok:
  357.     call    display_menu
  358.  
  359.     ;    make sure file type is LBR
  360.     ;
  361. cktype:
  362.     mov    SI,offset LIBEXT
  363.     mov    DI,offset FCBFT
  364.     mov    CX,3
  365.     rep    movsb
  366.  
  367.     ;    if no file name supplied, put in '????????'
  368.     ;
  369. ckfname:
  370.     mov    DI,offset fcbfn
  371.     cmp    byte ptr [DI],' '
  372.     jne    lbr_open
  373.     mov    AL,'?'
  374.     mov    CX,8
  375.     rep    stosb
  376.  
  377.     ;    open the LBR file
  378.     ;
  379. lbr_open:
  380.     call    open_file
  381.     or    AL,AL
  382.     jz    start_read
  383.  
  384.     ;    No file, send message and leave
  385.     ;
  386.     mov    SI,offset OPNMSG
  387.     call    display
  388.     jmp    finish
  389.  
  390.     ;    file found and opened, get directory information
  391.     ;
  392. start_read:
  393.     xor    AX,AX
  394.     mov    word ptr fcbrno,AX    ; set for first record
  395.     mov    word ptr fcbrno+2,AX    ; set for first record
  396.     mov    word ptr in_use,1    ; init member counter
  397.     mov    CX,dir_buf_sects    ; ask for default # of sectors
  398.     mov    word ptr dbuf_sects,CX    ; save directory buffer size
  399.     call    read_sector        ; read them in
  400.     or    AL,AL
  401.     jz    start_read_1        ; if non-zero, maybe eof
  402.     cmp    AL,3            ; see if partial sector
  403.     jz    start_read_1        ; if so, continue
  404.     jmp    prem_eof        ; else bail out
  405. start_read_1:
  406.     mov    BX,offset dta        ; point to first entry
  407.     mov    AX,[BX+count]        ; get dir size in sectors
  408.     mov    CX,AX            ; save directory sect count for read
  409.     shl    AX,1
  410.     shl    AX,1            ; sectors * 4 = MAX_ENTRIES
  411.     mov    word ptr max_entries,AX    ; save it
  412.     cmp    CX,word ptr dbuf_sects    ; whole dir in buffer?
  413.     jbe    find_last        ; if so, another read not needed
  414.     mov    word ptr dbuf_sects,CX    ; else update directory buffer size
  415.  
  416.     ;    read in the whole directory
  417.     ;
  418. dir_read:
  419.     xor    AX,AX
  420.     mov    word ptr fcbrno,AX    ; set for first record
  421.     mov    word ptr fcbrno+2,AX    ; set for first record
  422.     mov    CX,word ptr dbuf_sects    ; number of dir sectors to buffer
  423.     call    read_sector        ; read em all
  424.     or    AL,AL
  425.     jz    find_last        ; if non-zero, maybe eof
  426.     cmp    AL,3            ; see if partial sector
  427.     jz    find_last        ; if so, continue
  428.  
  429.     ;    premature end of file, send message, and exit
  430.     ;
  431. prem_eof:
  432.     mov    SI,offset EOFMSG
  433.     call    display
  434.     jmp    finish
  435.  
  436.     ;    locate the last directory & display slot usage
  437.     ;
  438. find_last:
  439.     mov    BX,offset dta        ; point to first entry
  440.     add    BX,entry_len        ; point to next entry
  441.     mov    CX,word ptr dbuf_sects    ;   to allow for dir header
  442.     shl    CX,1
  443.     shl    CX,1
  444.     dec    CX            ;   CX = 4*dbuf_sects - 1
  445. find_last_1:
  446.     mov    AL,byte ptr [BX+status]
  447.     cmp    AL,unused        ; first unused entry?
  448.     jz    found_last        ; yes, we're done
  449.     cmp    AL,active        ; active entry?
  450.     jnz    find_last_2        ; no, don't count it
  451.     inc    word ptr in_use        ; yes, bump the member counter
  452. find_last_2:
  453.     add    BX,entry_len        ; no, point to next entry
  454.     loop    find_last_1        ; and continue processing
  455. found_last:
  456.  
  457.     call    crlf
  458.     mov    SI,offset lbrmsg
  459.     call    display
  460.     mov    SI,offset lbr_name
  461.     call    display
  462.     mov    SI,offset MAXMSG
  463.     call    display
  464.     mov    BX,word ptr max_entries
  465.     call    bin_2_dec
  466.     mov    SI,offset FREEMSG
  467.     call    display
  468.     sub    BX,word ptr in_use    ; free slots = max - in use
  469.     call    bin_2_dec
  470.     call    crlf
  471.     call    crlf
  472.  
  473. init_vars:
  474.     xor    AX,AX            ; initialize variables
  475.     mov    word ptr in_use,AX
  476.     mov    AX,word ptr max_entries    ; get maximum entry count
  477.     mov    word ptr entries_todo,AX    ; and put in work counter
  478.     inc    word ptr in_use        ; adjust for the dir header
  479.     dec    word ptr entries_todo    ; likewise
  480.  
  481.     mov    BX,offset dta        ; point to first entry
  482.     add    BX,entry_len        ; point to next entry
  483.     mov    CX,word ptr dbuf_sects    ;   to allow for dir header
  484.     shl    CX,1
  485.     shl    CX,1
  486.     dec    CX            ;   CX = 4*dbuf_sects - 1
  487.  
  488.     ;    Read and analyze active entries
  489.     ;
  490. search_loop:
  491.     mov    word ptr entries_left,CX; save search loop control
  492.     mov    AL,byte ptr [BX+status]
  493.     cmp    AL,unused        ; first unused entry?
  494.     jz    skipit            ; yes, we're done
  495.  
  496.     cmp    AL,active        ; active entry?
  497.     jnz    skipit            ; no, don't process it
  498.  
  499.     inc    word ptr in_use        ; yes, bump the member counter
  500.     lea    DI,[BX+fname]        ; point to name
  501.  
  502.  
  503.     call    doentry    ; else display info
  504.  
  505. skipit:
  506.     dec    word ptr entries_todo    ; have we read em all?
  507.     jnz    skipit_1        ; no, do some more
  508.     call    crlf
  509.     jmp    init_vars        ; else, rewind LBR directory
  510. skipit_1:
  511.     add    BX,entry_len        ; point to next entry
  512.     mov    CX,word ptr entries_left
  513.     loop    search_loop        ; and continue processing
  514.                     ; (shouldn't ever fall through loop)
  515.  
  516.     ;    back to DOS
  517.     ;
  518. finish:
  519.     mov    AH,trmproc
  520.     int    dos
  521.  
  522.  
  523.  
  524.     ;            SUBROUTINES
  525.     ;            -----------
  526.  
  527.     ;    entry point for reading/writing/viewing members
  528. typesq:
  529.     mov    BX,word ptr entry_ptr    ; point to the directory entry
  530.     lea    DI,[BX+fname]        ; point to name
  531.     mov    DX,[BX+index]        ; get block # of member
  532.      mov    word ptr fcbrno,DX    ; save member's starting position
  533.     mov    DX,[BX+count]        ; get the member size in blocks
  534.      mov    word ptr blks_left,DX    ; save it
  535.     mov    BX,offset dta        ; get begining of input buffer
  536.     mov    word ptr buf_ptr,BX    ; init pointer
  537.     xor    AX,AX
  538.     mov    byte ptr squeezed,AL
  539.     mov    byte ptr line_count,AL
  540.     mov    word ptr buf_counter,1
  541.  
  542.     ;    if the raw flag set, go to write loop whether or not squeezed
  543.     ;
  544.     cmp    byte ptr rflag,FALSE    ; raw flag off?
  545.     je    read_sq            ; if so, go read the sq'd file
  546.     call    crlf
  547.     call    read_byte        ; else, trigger buffer fill
  548.     dec    word ptr buf_ptr    ; but don't eat first byte
  549.     jmp    write_loop        ; go dump buffer to disk
  550.  
  551.     ;    check for the 2 byte "squeezed" marker
  552. read_sq:
  553.     call    read_word        ; read the 2 byte marker
  554.     cmp    BX,0FF76h        ; see if it's 76FFh (byte reversed)
  555.     je    read_header        ; if so, read the rest of the header
  556.     call    crlf
  557.     call    crlf
  558.     sub    word ptr buf_ptr,2    ; else not sq'd so unread 2 bytes
  559.     cmp    byte ptr wflag,FALSE    ; and if write flag off           
  560.     je    con_dump        ;   dump buffer to console
  561.     jmp    write_loop              ;   otherwise, dump buffer to disk
  562. con_dump:
  563.     jmp    type_loop
  564.  
  565.     ;    The "squeezed" marker is followed by a two-byte checksum,
  566.     ;    which is the simple sum of all the one-byte characters in
  567.     ;    the source file, carried as a two byte sum modulo 2**16.
  568.     ;
  569. read_header:
  570.     mov    SI,offset unsq_msg    ; tell them we're unsqueezing
  571.     call    display
  572.     call    read_word        ; skip over checksum
  573.     mov    DI,offset filout    ; DI=ptr to output file z-string
  574.  
  575.     ;    The 2 byte checksum is followed by the true filename
  576.     ;    which is a null terminated, packed, ascii string
  577. read_name:
  578.     call    read_byte        ; AL = *buf_ptr++ (filename byte)
  579.     stosb                ; *DI++ = AL (filout z-string)
  580.     or    AL,AL            ; null end marker?
  581.     jz    read_name_x        ; if so, done with filename
  582.     call    putchar            ; else echo filename byte to console
  583.     jmp    short read_name        ; and try next byte
  584. read_name_x:
  585.  
  586. page_test:
  587.     call    crlf
  588.     cmp    byte ptr pflag,TRUE    ; see if paging flag on
  589.     jne    page_test_x        ; if not, skip message
  590.     mov    SI,offset page_msg    ; else, display page control commands
  591.     call    display
  592.     jmp    short mak_ofile
  593. page_test_x:
  594.     call    crlf
  595.  
  596.     ;    make output file if wflag set
  597.     ;
  598. mak_ofile:
  599.     cmp    byte ptr wflag,FALSE    ; see if write flag set
  600.     je    get_tree_size        ; if not, go right to code tree
  601.     call    mak_out            ; else, make output file first
  602.     call    init_obuf        ; and init output buffer
  603.  
  604.     ; Load code dictionary. First word is the length followed by a
  605.     ; series of word pairs. For each bit in the code, select the first
  606.     ; or second (1) element. If the pair is positive, it's the table entry
  607.     ; (code + 4*index) at which to continue with the next bit. If it's
  608.     ; negative, it is the complement of the ASCII character (lsb).
  609.     ;
  610. get_tree_size:
  611.     call    read_word        ; read the code tree length to BX
  612.     cmp    BX,tree_size        ; see that its within defined limits
  613.     jbe    load_tree        ; if so, go load it
  614.  
  615.     mov    SI,offset NoRoomMsg    ; else, error message
  616.     call    display
  617.     jmp    exit            ; and bail out
  618.  
  619. load_tree:
  620.     shl    BX,1            ; multiply BX by 4
  621.     shl    BX,1
  622.     mov    CX,BX            ; use CX as input counter
  623.     mov    DI,offset code_tree    ; destination is our code_tree buffer
  624.  
  625. move_em:
  626.     call    read_byte        ; AL = *SI++
  627.     stosb                ; *DI++ = AL
  628.     loop    move_em            ; if(--CX) jmp mov_em
  629.  
  630.     mov    byte ptr rot_counter,1    ; init to trigger read in decoder
  631.     mov    byte ptr squeezed,TRUE    ; set sq flag for dual purpose sq loop
  632.     jmp    typesq_loop        ; go to squeeze processor
  633.  
  634.  
  635.     ; convert binary word to ascii decimal & output it
  636.     ; uses the 8086 divide instruction
  637.     ; parameters passed in registers as follows:
  638.     ;    BX    binary word to be converted
  639.     ;
  640. bin_2_dec:
  641.     mov    DI,offset decbuf    ; address of output buffer
  642.      mov    CX,5            ; buffer length-1
  643.     mov    AL,' '            ; pad character
  644.     rep    stosb            ; clear buffer & point to end
  645.     mov    byte ptr [DI], 0    ; init end of string
  646.     mov    AX,BX            ; put binary word into AX
  647.     mov    SI,10            ; put divisor in SI
  648.  
  649. next_digit:
  650.     xor    DX,DX            ; clear dividend high word
  651.     div    SI            ; AX = (DX:AX)/SI, DX = remainder
  652.     add    DX,'0'            ; convert DL remainder byte to ascii
  653.     dec    DI            ; back step in buffer
  654.     mov    byte ptr [DI], DL    ; put character there
  655.     or    AX,AX            ; all done? (AX = 0?)
  656.     jnz    next_digit        ; if not, do another digit
  657.  
  658.     mov    SI,offset decbuf    ; string address to SI
  659.     call    display            ; output it
  660.     ret
  661.  
  662.     ;
  663.     ; command interpreter
  664. cmd_int:
  665.     push    AX
  666.     mov    DX, offset exit        ; point to exit routine
  667.     call    int_set            ; set ctl-C interrupt vector
  668.     mov    AL,FALSE
  669.     mov    byte ptr pflag,AL    ; initalize the flags
  670.     mov    byte ptr rflag,AL
  671.     mov    byte ptr wflag,AL
  672.     pop    AX
  673.     cmp    AL,'?'            ; help command
  674.     jne    cmd_int_1
  675.     call    display_menu
  676.     call    back_step
  677.     jmp    short cmd_int_x
  678.  
  679. cmd_int_1:
  680.  
  681.     cmp    AL,'X'            ; exit command
  682.     jne    cmd_int_2
  683.     jmp    finish
  684.  
  685. cmd_int_2:
  686.     cmp    AL,'V'            ; view command
  687.     jne    cmd_int_3
  688.     call    typesq
  689.     call    reload_dir
  690.     call    back_step
  691.     jmp    short cmd_int_x
  692.  
  693. cmd_int_3:
  694.     cmp    AL,'Q'            ; raw extract command
  695.     jne    cmd_int_4
  696.     call    get_drv
  697.     cmp    byte ptr drv_error,TRUE
  698.     je    cmd_int_x
  699.     mov    byte ptr wflag,TRUE
  700.     mov    byte ptr rflag,TRUE
  701.     call    typesq
  702.     call    reload_dir
  703.     jmp    short cmd_int_x
  704.  
  705. cmd_int_4:
  706.     cmp    AL,'E'            ; extract & unsqueeze command
  707.     jne    cmd_int_5
  708.     call    get_drv
  709.     cmp    byte ptr drv_error,TRUE
  710.     je    cmd_int_x
  711.     mov    byte ptr wflag,TRUE
  712.     call    typesq
  713.     call    reload_dir
  714.     jmp    short cmd_int_x
  715.  
  716. cmd_int_5:
  717.     cmp    AL,'P'            ; page command
  718.     jne    cmd_int_6
  719.     mov    byte ptr pflag,TRUE
  720.     call    typesq
  721.     call    reload_dir
  722.     call    back_step
  723.     jmp    short cmd_int_x
  724.  
  725. cmd_int_6:
  726.  
  727. cmd_int_x:
  728.     mov    DX, offset int_disable    ; point to IRET instruction
  729.     call    int_set            ; disable ctl-C interrupts
  730.     ret
  731.  
  732.     ;    Decode next squeezed character returning the translated
  733.     ;    character in AL. Transfers to exit sequence on eof.
  734.     ;
  735. decode:
  736.     mov    AL,byte ptr rot_byte
  737.     mov    AH,byte ptr rot_counter
  738.     xor    BX,BX
  739.     mov    DI,offset code_tree
  740.     mov    BP,DI
  741.  
  742.     ;    Read one bit at a time via the carry flag
  743. read_bit:
  744.     dec    AH            ; adjust bit rotation counter
  745.     jz    read_new_bits        ; if haven't done all 8 bits, do next
  746. read_nxt_bit:
  747.     rcr    AL,1
  748.     jnc    its_0            ; point to this entry if lsb=0
  749.     inc    DI            ; else, advance to next entry (lsb=1)
  750.     inc    DI
  751. its_0:
  752.     mov    BX,word ptr [BX+DI]    ; read the code tree entry
  753.     cmp    BX,0FEFFh        ; see if code tree endmarker = 0FEFFh
  754.     je    decode_eof        ; if so, signal eof
  755.     or    BX,BX            ; check code tree entry msb
  756.  
  757.     js    decode_x        ; minus = leaf node
  758.                     ; plus = index to next node
  759.  
  760.     mov    DI,BP            ; DI=code tree root
  761.     shl    BX,1            ; BX=code tree entry * 4
  762.     shl    BX,1
  763.  
  764.     jmp    short read_bit        ; go decode next bit
  765.  
  766. read_new_bits:
  767.     call    read_byte        ; and get 8 new bits (1 byte) into AL
  768.     mov    AH,8            ; else reset rotation counter
  769.     jmp    short read_nxt_bit
  770.  
  771. decode_eof:
  772.     cmp    byte ptr wflag,FALSE    ; see if write flag off
  773.     je    d_eof_x            ; if so, just exit
  774.     call    flush_o            ; else, flush output buffer
  775.     mov    SI,offset done_msg    ; and tell them we're done
  776.     call    display
  777. d_eof_x:
  778.     jmp    exit
  779.  
  780. decode_x:
  781.     mov    byte ptr rot_byte,AL
  782.     mov    byte ptr rot_counter,AH
  783.     mov    AL,BL
  784.     not    AL            ; else, complement the char
  785.     ret
  786.  
  787.  
  788.     ;    Print null-terminated string pointed to by SI
  789.     ;
  790. display:
  791.     lodsb                ; get a character
  792.     or    AL,AL            ; machine zero?
  793.     jz    display_x        ; yes, exit
  794.     call    putchar            ; print it
  795.     jmp    short display        ; do another
  796. display_x:
  797.     ret
  798.  
  799.  
  800.     ; display menu
  801.     ;
  802. display_menu:
  803.     call    CRLF
  804.     push    BX
  805.     push    CX
  806.     push    DX
  807.     mov    AH,40h
  808.     mov    BX,1
  809.     mov    CX,menu_len
  810.     mov    DX,offset menu
  811.     int    dos
  812.     pop    DX
  813.     pop    CX
  814.     pop    BX
  815.     ret
  816.  
  817. back_step:
  818.     inc    word ptr entries_todo    ; adjust variables for no change
  819.     inc    word ptr entries_left    ; CX loop control
  820.     dec    word ptr in_use
  821.     sub    word ptr entry_ptr,entry_len
  822.     ret
  823.  
  824.     ;    process the entry pointed to by BX
  825.     ;
  826. doentry:
  827.     mov    DI,BX            ; for easier processing
  828.     mov    word ptr entry_ptr,BX    ; save caller's pointer
  829.     lea    SI,[DI+fname]        ; point to the name
  830.     call    pfname            ; print it
  831.     mov    BX,[DI+count]        ; get the value
  832.     add    BX,0111b        ; bump to next 1k boundary
  833.     shr    BX,1
  834.     shr    BX,1
  835.     shr    BX,1            ; convert to k
  836. print_size:
  837.     call    bin_2_dec        ; convert & display file size
  838.     mov    SI,offset k_msg        ; write 'k >' to console
  839.     call    display
  840.     call    get_next
  841.     call    CRLF
  842.     mov    BX,word ptr entry_ptr    ; restore caller's pointer
  843.     ret
  844.  
  845.     ; exit a menu command and return to main control loop
  846.     ; also functions as ctl-c interrupt handler
  847. exit:
  848.     mov    DX,offset int_disable    ; disable CTL-C interrupt
  849.     call    int_set
  850.     cmp    byte ptr wflag,FALSE
  851.     je    exit_1
  852.     mov    BX,word ptr out_handle    ; output file handle
  853.     mov    AH,clostrm        ; close output file stream
  854.     int    dos
  855.     mov    byte ptr wflag,FALSE
  856. exit_1:
  857.     mov    AX,flush_kb*256        ; make sure no CTL-C in buffer
  858.     int    dos
  859.     mov    AL,'?'
  860.     mov    SP,word ptr sav_sp    ; restore the stack pointer
  861.     dec    SP
  862.     dec    SP
  863.     ret
  864.  
  865. int_disable:
  866.     iret                ; no nothing but return
  867.  
  868.     ; set the ctl-C interrupt vector, expects address in DX
  869.     ;
  870. int_set:
  871.     mov    AX,setiv*256+23h    ; AH=setiv, AL=ctl-C int #
  872.     push    DS            ; save program data segment
  873.     push    CS            ; put code segment into
  874.     pop    DS            ;  DS for interrupt handler
  875.     int    dos
  876.     pop    DS            ; restore our data segment
  877.     ret
  878.  
  879.     ;    flush output buffer
  880.     ;
  881. flush_o:
  882.     push    AX
  883.     push    CX
  884.     mov    AH,wrtstrm
  885.     mov    BX,word ptr out_handle
  886.     mov    CX,word ptr obuf_bytes
  887.     mov    DX,offset obuf
  888.     int    dos
  889.     jnc    flush_o1
  890.     jmp    write_error
  891. flush_o1:
  892.     cmp    CX,AX
  893.     pop    CX
  894.     pop    AX
  895.     je    flush_o2
  896.     jmp    disk_full
  897. flush_o2:
  898.     call    init_obuf
  899.     dec    word ptr obuf_ctr
  900.     ret
  901.  
  902.     ; input a char, convert to uppercase, then display it
  903.     ;
  904. getchar:
  905.     call    getch            ; console input & uc conversion
  906.     cmp    AL,' '            ; no echo if not printable
  907.     jb    getchar_x
  908. getchar_1:
  909.     mov    DL,AL
  910.     mov    AH,conout        ; echo input to console
  911.     int    dos
  912. getchar_x:
  913.     ret
  914.  
  915.     ; input a char & convert to uppercase w/o echo
  916.     ;
  917. getch:
  918.     mov    AH,dir_conin        ; use direct console input function
  919.     int    dos            ; wait for input
  920.     and    AL,7Fh            ; strip high bit
  921.     cmp    AL,'a'-1        ; convert lower case to upper
  922.     jna    getch_x            ;   but only if between
  923.     cmp    AL,'z'+1        ;   'a' and 'z'
  924.     jnb    getch_x
  925.     sub    AL,20h            ; upper case conversion
  926. getch_x:
  927.     ret
  928.  
  929.     ;    get destination drive, put it in drvout, ret NC if OK
  930.     ;
  931. get_drv:
  932.     call    crlf
  933.     mov    SI,offset drv_req
  934.     call    display
  935.     call    getchar
  936.     mov    byte ptr drv_error,FALSE
  937.     cmp    AL,cr
  938.     jne    get_drv_1
  939.     mov    AL,' '
  940.     mov    byte ptr drvout,AL
  941.     mov    byte ptr drvout+1,AL
  942.     jmp    short get_drv_3
  943. get_drv_1:
  944.     cmp    AL,'A'-1
  945.     jna    get_drv_2
  946.     cmp    AL,'P'
  947.     ja    get_drv_2
  948.     mov    byte ptr drvout,AL
  949.     mov    byte ptr drvout+1,':'
  950.     jmp    short get_drv_3
  951. get_drv_2:
  952.     mov    byte ptr drv_error,TRUE
  953. get_drv_3:
  954.     ret
  955.  
  956.     ; input a command char to determine what to do next
  957.     ;
  958. get_next:
  959.     call    getchar
  960.     push    AX
  961.     mov    AL,' '
  962.     call    putchar
  963.     call    putchar
  964.     pop    AX
  965.     mov    word ptr sav_sp,SP    ; save the stack pointer
  966.     jmp    cmd_int            ; go interpret command
  967.  
  968.     ;    initialize output buffer
  969.     ;
  970. init_obuf:
  971.     mov    word ptr obuf_ctr,obuf_size
  972.     mov    word ptr obuf_bytes,0
  973.     mov    word ptr obuf_ptr,offset obuf
  974.     ret    
  975.  
  976.     ;    make output file on the requested drive
  977. mak_out:
  978.     mov    DX,offset drvout    ; address of outfile z-string
  979.     cmp    byte ptr drvout,' '    ; if no drive spec
  980.     jne    mak_out_1
  981.     mov    DX,offset filout    ; then point to file name
  982. mak_out_1:
  983.     xor    CX,CX            ; no file attribute specified
  984.     mov    AH,makstrm        ; make file stream
  985.     int    dos
  986.     mov    word ptr out_handle,AX    ; save output stream number
  987.     jnc    mak_out_x
  988.     mov    SI,offset mak_msg
  989.     call    display
  990.     jmp    exit
  991. mak_out_x:
  992.     ret
  993.  
  994.     ;    open input file
  995.     ;
  996. open_file:
  997.     mov    AH,setdta
  998.     mov    DX,offset dta
  999.     int    dos
  1000.     xor    AL,AL
  1001.     mov    byte ptr FCBCR,AL
  1002.     mov    byte ptr FCBEX,AL
  1003.     mov    byte ptr FCBRC,AL
  1004.     mov    DX,offset FCB
  1005.     mov    AH,srch_fst
  1006.     int    dos
  1007.     or    AL,AL
  1008.     jnz    open_exit
  1009.     mov    SI,offset dta
  1010.     mov    DI,offset fcb
  1011.     mov    CX,37
  1012.     rep    movsb
  1013.     mov    AH,openf
  1014.     int    dos
  1015.  
  1016.     ;    copy & parse lbr_name from the file control block
  1017.     ;
  1018.     mov    SI,offset dta            ; fcb address is source
  1019.     mov    DI,offset lbr_name        ; destination
  1020.     movsb                    ; copy drive designation
  1021.     add    byte ptr [DI-1],'A'-1        ; convert to ascii
  1022.     mov    AL,':'
  1023.     stosb                    ; colon to destination
  1024.     mov    CX,8
  1025.     rep    movsb                ; copy filename
  1026.     call    quash_space
  1027.     mov    AL,'.'                ; period to destination
  1028.     stosb
  1029.     mov    CX,3
  1030.     rep    movsb                ; copy file type
  1031.     xor    AL,AL
  1032.     stosb                    ; null end marker
  1033. open_exit:
  1034.     ret
  1035.  
  1036.     ;    page routine for viewing
  1037. page:
  1038.     cmp    AL,lf            ; see if char is new line
  1039.     jne    page_x             ; if not, exit
  1040.     mov    AH,byte ptr line_count    ; else get line counter
  1041.     inc    AH            ; increment it
  1042.     cmp    AH,page_len        ; see if whole page
  1043.     jna    sto_line        ; if not, just put count back
  1044.     call    getch            ; input w/o echo to AL
  1045.     cmp    AL,'X'-40h        ; see if an exit command
  1046.     jne    page_L            ; if not, go to LINE test
  1047.     call    crlf
  1048.     jmp    exit
  1049. page_L:
  1050.     cmp    AL,' '            ; see if a line advance command
  1051.     jne    page_P            ; if not, assume page advance
  1052.     mov    AX,lf+256*page_len    ; else, setup AX to advance one line
  1053.     jmp    short sto_line
  1054. page_P:
  1055.     mov    AX,lf            ; setup AX to advance a full page
  1056. sto_line:
  1057.     mov    byte ptr line_count,AH
  1058. page_x:
  1059.     ret
  1060.  
  1061.     ;    Print filename pointed to by SI and precede with line #
  1062.     ;    also make a null terminated copy @ filout
  1063. pfname:
  1064.     push    DI
  1065.     push    SI
  1066.     mov    BX,word ptr in_use
  1067.     dec    BX
  1068.     call    bin_2_dec
  1069.     mov    AL,'.'
  1070.     call    putchar
  1071.     mov    AL,' '
  1072.     call    putchar
  1073.  
  1074.     pop    SI
  1075.     mov    DI,offset filout    ; point to destination of copy
  1076.     mov    CX,8            ; number of chars in name
  1077. fnameloop:
  1078.     lodsb                ; AL = *SI++
  1079.     stosb                ; *DI++ = AL
  1080.     call    putchar
  1081.     loop    fnameloop
  1082.     call    quash_space
  1083.     mov    AL,'.'
  1084.     stosb
  1085.     call    putchar
  1086.     mov    CX,3            ; number of chars in extension
  1087. extloop:
  1088.     lodsb
  1089.     stosb
  1090.     call    putchar
  1091.     loop    extloop
  1092.  
  1093.     xor    AL,AL
  1094.     stosb                ; null terminate copy
  1095.     pop    DI
  1096.     ret
  1097.  
  1098.     ;    output CR,LF
  1099. crlf:
  1100.     mov    AL,CR
  1101.     call    putchar
  1102.     mov    AL,LF            ; fall into putchar
  1103.  
  1104.     ;    Send character in AL to console
  1105. putchar:
  1106.     mov    AH,conout
  1107.     mov    DL,AL
  1108.     and    DL,7Fh            ; strip hi-bit (ws files)
  1109.     int    dos
  1110.     ret
  1111.  
  1112.     ;    Step DI backwards up to 8 chars while pointing to spaces
  1113.     ;    CX downcounter starts equal to 8 at string begining
  1114. quash_space:
  1115.     inc    CX
  1116.     cmp    byte ptr [DI-1],' '
  1117.     jne    not_space
  1118.     dec     DI
  1119.     cmp    CX,8
  1120.     jb    quash_space
  1121. not_space:
  1122.     ret
  1123.  
  1124.  
  1125.     ;    Read one byte, refill buffer as needed.
  1126.     ;
  1127. read_byte:
  1128.     dec    word ptr buf_counter
  1129.     jz    yes_read
  1130. noread:
  1131.     mov    SI,word ptr buf_ptr
  1132.     lodsb
  1133.     mov    word ptr buf_ptr,SI
  1134.     ret
  1135.  
  1136. yes_read:
  1137.     push    CX
  1138.     mov    CX,word ptr blks_left    ; get # of blocks left to read
  1139.     cmp    CX,irec_per_blk        ; max size of buffer <= blocks left ?
  1140.     jbe    yes_read_1        ; if so, read em all
  1141.     mov    CX,irec_per_blk        ; else, only read a buffer full
  1142. yes_read_1:
  1143.     sub    word ptr blks_left,CX    ; and reduce count of blocks left
  1144.     call    read_sector
  1145.     pop    CX
  1146.     cmp    AL,1
  1147.     jnz    noread
  1148.     jmp    exit
  1149.  
  1150.     ;    read block of sectors - expects sector count in CX
  1151.     ;    and Relative Record field in fcb to be preset,
  1152.     ;    translates AL=3 to AL=0 & updates buf counter & size
  1153.     ;
  1154. read_sector:
  1155.     push    DX
  1156.     mov    AX,offset dta
  1157.     mov    word ptr buf_ptr,AX
  1158.     mov    DX,Offset FCB        ; point DX at File Control Block
  1159.     mov    AH,read_blk        ; random block read function
  1160.     int    dos
  1161.     or    AL,AL            ; filled whole buffer?
  1162.     jz    read_secx        ; done
  1163.     cmp    AL,3            ; partial sector read?
  1164.     jne    read_sec2        ; if not, continue
  1165.     xor    AL,AL            ; tell caller all well
  1166.     jmp    short read_secx        ; done
  1167. read_sec2:
  1168.     cmp    AL,1            ; see if end of file
  1169.     jne    read_secx        ; if not, pass AL to caller
  1170.     or    CX,CX            ; else see if any sectors read
  1171.     jz    read_secx        ; if not, pass AL=oef to caller
  1172.     xor    AL,AL            ; else, tell caller all well
  1173. read_secx:
  1174.     mov    DX,CX            ; put # of sectors read in DX
  1175.     mov    CL,7            ; convert DX into count of bytes
  1176.     shl    DX,CL            ;   in buffer via multiply by 128
  1177.     mov    word ptr buf_counter,DX ; save it
  1178.     mov    word ptr buf_size,DX     ; save it
  1179.     pop    DX
  1180.     ret
  1181.  
  1182.     ; read a word into BX
  1183.     ;
  1184. read_word:
  1185.     call    read_byte
  1186.     mov    BL,AL
  1187.     call    read_byte
  1188.     mov    BH,AL
  1189.     ret
  1190.  
  1191.     ;    reload the whole directory
  1192.     ;
  1193. reload_dir:
  1194.     xor    AX,AX
  1195.     mov    word ptr fcbrno,AX    ; set for first record
  1196.     mov    word ptr fcbrno+2,AX    ; set for first record
  1197.     mov    CX,word ptr dbuf_sects    ; number of dir sectors to buffer
  1198.     call    read_sector        ; read em all
  1199.     ret
  1200.  
  1201.     ;    type plain-text member to the console
  1202.     ;
  1203. type_loop:
  1204.     cmp    byte ptr pflag,TRUE    ; see if paging flag on
  1205.     jne    type_loop_1        ; if not, skip message
  1206.     mov    SI,offset page_msg    ; else, display page control commands
  1207.     call    display
  1208. type_loop_1:
  1209.     call    read_byte        ; else just get a byte
  1210.     cmp    AL,eof            ; end of file?
  1211.     je    type_loopx        ; yes, leave
  1212.     cmp    byte ptr pflag,TRUE    ; see if paging flag set
  1213.     jne    type_loop_out        ; if not,just output char
  1214.     call    page            ; else, do page
  1215. type_loop_out:
  1216.     call    putchar            ; else display it
  1217.     jmp    short type_loop_1        ; and back for more
  1218. type_loopx:
  1219.     jmp    exit
  1220.  
  1221.     ;    type squeezed member expanding repeat sequences
  1222.     ;
  1223. typesq_loop:
  1224.     call    decode            ; AL = translated character
  1225.     cmp    AL,090h            ; see if repeat character = 90h
  1226.     jne    reg_char        ; if not, its a regular one
  1227.     call    decode            ; else, see whats next
  1228.     or    AL,AL            ; null?
  1229.     jz    intend_90h        ; if so, 90h is intended
  1230.                     ; else, it's a repeat flag & count
  1231.     dec    AL            ; reduce the count
  1232.     mov    CL,AL            ; convert count to word in CX
  1233.     xor    CH,CH
  1234.     mov    AL,byte ptr last_char    ; restore char to be repeated
  1235.  
  1236. rep_char_loop:
  1237.     call    wrtchar            ; output character
  1238.     loop    rep_char_loop        ; if(CX--) jmp rep_char_loop
  1239.  
  1240.     jmp    short typesq_loop    ; go back for more bytes
  1241.  
  1242. intend_90h:
  1243.     mov    AL,90h            ; else, 90h was intended
  1244.     jmp    short reg_char_1    ; so treat like a regular character
  1245.  
  1246. reg_char:
  1247.     mov    byte ptr last_char,AL    ; save in case a repeat flag follows
  1248. reg_char_1:
  1249.     call    wrtchar            ; output it
  1250.     jmp    short typesq_loop    ; and go back for more bytes
  1251.  
  1252.  
  1253.     ;    write plain-text member to a file
  1254.     ;
  1255. write_loop:
  1256.     call    mak_out            ; make the output file
  1257. write_loop_1:
  1258.     ;    write from input buffer
  1259.     ;
  1260.     mov    BX,word ptr out_handle    ; output file handle
  1261.     mov    DX,word ptr buf_ptr    ; output buffer address
  1262.     mov    CX,word ptr buf_size    ; size of whole buffer
  1263.     sub    CX,DX            ; less buf_ptr
  1264.     add    CX,offset dta        ; plus start = bytes in buffer
  1265.     mov    AH,wrtstrm        ; write to file stream
  1266.     int    dos
  1267.     jc    write_error        ; never happens if trapped by dos
  1268.     cmp    CX,AX            ; make sure all bytes were written
  1269.     jnz    disk_full
  1270.  
  1271.     ;    refill the buffer
  1272.     ;
  1273.     mov    CX,word ptr blks_left    ; get # of blocks left to read
  1274.     or    CX,CX
  1275.     jz    closeout
  1276.     cmp    CX,irec_per_blk        ; max size of buffer <= blocks left ?
  1277.     jbe    write_loop_2        ; if so, read em all to refill buffer
  1278.     mov    CX,irec_per_blk        ; else, only read a buffer full
  1279. write_loop_2:
  1280.     sub    word ptr blks_left,CX    ; reduce count of blocks left
  1281.     call    read_sector        ; fill input buffer
  1282.     cmp    AL,1            ; exit if eof
  1283.     jz    closeout
  1284.     or    AL,AL
  1285.     jnz    read_error
  1286.     jmp    short write_loop_1    ; and back for more
  1287. disk_full:
  1288.     mov    SI,offset full_msg
  1289.     call    display
  1290.     jmp    exit
  1291. read_error:
  1292.     mov    SI,offset rd_msg
  1293.     call    display
  1294.     jmp    exit
  1295. write_error:
  1296.     mov    SI,offset wrt_msg
  1297.     call    display
  1298. closeout:
  1299.     mov    SI,offset done_msg
  1300.     call    display
  1301.     jmp    exit
  1302.  
  1303.  
  1304.     ;    Write character in AL to output file stream
  1305.     ;    if the write flag is set, else transfer to
  1306.     ;    console output function unless eof read
  1307. wrtchar:
  1308.     cmp    byte ptr wflag,TRUE
  1309.     je    wrtflag_on
  1310.     cmp    AL,eof            ; end of file?
  1311.     jne    go_putchar
  1312.     jmp    exit
  1313. wrtflag_on:
  1314.     dec    word ptr obuf_ctr
  1315.     jz    wrtchar_2
  1316. wrtchar_1:
  1317.     mov    DI,word ptr obuf_ptr
  1318.     stosb
  1319.     mov    word ptr obuf_ptr,DI
  1320.     inc    word ptr obuf_bytes
  1321.     ret
  1322. wrtchar_2:
  1323.     call    flush_o
  1324.     jmp    short wrtchar_1
  1325. go_putchar:
  1326.     cmp    byte ptr pflag,TRUE
  1327.     jne    go_putchar_1
  1328.     call    page
  1329. go_putchar_1:
  1330.     jmp    putchar
  1331.  
  1332.  
  1333. code    ENDS            ; end of code segment
  1334.  
  1335.  
  1336.  
  1337.     ; STACK LOCATION
  1338.     ; --------------
  1339.  
  1340. a_stack    SEGMENT word STACK
  1341.  
  1342.     ; dummy declaration to satisfy assembler & linker
  1343.  
  1344. a_stack    ENDS
  1345.  
  1346.  
  1347.     END    lsweep
  1348.